blob: 686bda76fcad79957df1586c5b536fedb5550522 [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;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001028 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001029 bool changed;
1030
1031 BT_DBG("status 0x%02x", status);
1032
1033 hci_dev_lock(hdev);
1034
1035 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1036 if (!cmd)
1037 goto unlock;
1038
1039 if (status) {
1040 u8 mgmt_err = mgmt_status(status);
1041 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1042 goto remove_cmd;
1043 }
1044
1045 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001046 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001047 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1048 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001049
1050 if (hdev->discov_timeout > 0) {
1051 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1052 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1053 to);
1054 }
1055 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001056 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1057 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001058 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001059
1060 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1061
1062 if (changed)
1063 new_settings(hdev, cmd->sk);
1064
Marcel Holtmann970ba522013-10-15 06:33:57 -07001065 /* When the discoverable mode gets changed, make sure
1066 * that class of device has the limited discoverable
1067 * bit correctly set.
1068 */
1069 hci_req_init(&req, hdev);
1070 update_class(&req);
1071 hci_req_run(&req, NULL);
1072
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001073remove_cmd:
1074 mgmt_pending_remove(cmd);
1075
1076unlock:
1077 hci_dev_unlock(hdev);
1078}
1079
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001080static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001081 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001082{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001083 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001084 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001085 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001086 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001087 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001088 int err;
1089
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001090 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001091
Johan Hedberge6fe7982013-10-02 15:45:22 +03001092 status = mgmt_bredr_support(hdev);
1093 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001094 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001095 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001096
Johan Hedberga7e80f22013-01-09 16:05:19 +02001097 if (cp->val != 0x00 && cp->val != 0x01)
1098 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1099 MGMT_STATUS_INVALID_PARAMS);
1100
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001101 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +01001102 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001103 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001104 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001105
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001106 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001107
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001108 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001109 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001110 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001111 goto failed;
1112 }
1113
1114 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001115 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001116 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001117 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001118 goto failed;
1119 }
1120
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001121 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001122 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001123 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001124 goto failed;
1125 }
1126
1127 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001128 bool changed = false;
1129
1130 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1131 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1132 changed = true;
1133 }
1134
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001135 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001136 if (err < 0)
1137 goto failed;
1138
1139 if (changed)
1140 err = new_settings(hdev, sk);
1141
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001142 goto failed;
1143 }
1144
1145 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001146 if (hdev->discov_timeout > 0) {
1147 cancel_delayed_work(&hdev->discov_off);
1148 hdev->discov_timeout = 0;
1149 }
1150
1151 if (cp->val && timeout > 0) {
1152 hdev->discov_timeout = timeout;
1153 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1154 msecs_to_jiffies(hdev->discov_timeout * 1000));
1155 }
1156
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001157 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001158 goto failed;
1159 }
1160
1161 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1162 if (!cmd) {
1163 err = -ENOMEM;
1164 goto failed;
1165 }
1166
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001167 hci_req_init(&req, hdev);
1168
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001169 scan = SCAN_PAGE;
1170
1171 if (cp->val)
1172 scan |= SCAN_INQUIRY;
1173 else
1174 cancel_delayed_work(&hdev->discov_off);
1175
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001176 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1177
1178 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001179 if (err < 0)
1180 mgmt_pending_remove(cmd);
1181
1182 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001183 hdev->discov_timeout = timeout;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001184
1185failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001186 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001187 return err;
1188}
1189
Johan Hedberg406d7802013-03-15 17:07:09 -05001190static void write_fast_connectable(struct hci_request *req, bool enable)
1191{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001192 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001193 struct hci_cp_write_page_scan_activity acp;
1194 u8 type;
1195
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001196 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1197 return;
1198
Johan Hedberg406d7802013-03-15 17:07:09 -05001199 if (enable) {
1200 type = PAGE_SCAN_TYPE_INTERLACED;
1201
1202 /* 160 msec page scan interval */
1203 acp.interval = __constant_cpu_to_le16(0x0100);
1204 } else {
1205 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1206
1207 /* default 1.28 sec page scan */
1208 acp.interval = __constant_cpu_to_le16(0x0800);
1209 }
1210
1211 acp.window = __constant_cpu_to_le16(0x0012);
1212
Johan Hedbergbd98b992013-03-15 17:07:13 -05001213 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1214 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1215 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1216 sizeof(acp), &acp);
1217
1218 if (hdev->page_scan_type != type)
1219 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001220}
1221
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001222static u8 get_adv_type(struct hci_dev *hdev)
1223{
1224 struct pending_cmd *cmd;
1225 bool connectable;
1226
1227 /* If there's a pending mgmt command the flag will not yet have
1228 * it's final value, so check for this first.
1229 */
1230 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1231 if (cmd) {
1232 struct mgmt_mode *cp = cmd->param;
1233 connectable = !!cp->val;
1234 } else {
1235 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1236 }
1237
1238 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1239}
1240
Johan Hedberg95c66e72013-10-14 16:20:06 +03001241static void enable_advertising(struct hci_request *req)
1242{
1243 struct hci_dev *hdev = req->hdev;
1244 struct hci_cp_le_set_adv_param cp;
1245 u8 enable = 0x01;
1246
1247 memset(&cp, 0, sizeof(cp));
1248 cp.min_interval = __constant_cpu_to_le16(0x0800);
1249 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001250 cp.type = get_adv_type(hdev);
Johan Hedberg95c66e72013-10-14 16:20:06 +03001251 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1252 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1253 else
1254 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1255 cp.channel_map = 0x07;
1256
1257 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1258
1259 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1260}
1261
1262static void disable_advertising(struct hci_request *req)
1263{
1264 u8 enable = 0x00;
1265
1266 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1267}
1268
Johan Hedberg2b76f452013-03-15 17:07:04 -05001269static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1270{
1271 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001272 struct mgmt_mode *cp;
1273 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001274
1275 BT_DBG("status 0x%02x", status);
1276
1277 hci_dev_lock(hdev);
1278
1279 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1280 if (!cmd)
1281 goto unlock;
1282
Johan Hedberg37438c12013-10-14 16:20:05 +03001283 if (status) {
1284 u8 mgmt_err = mgmt_status(status);
1285 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1286 goto remove_cmd;
1287 }
1288
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001289 cp = cmd->param;
1290 if (cp->val)
1291 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1292 else
1293 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1294
Johan Hedberg2b76f452013-03-15 17:07:04 -05001295 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1296
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001297 if (changed)
1298 new_settings(hdev, cmd->sk);
1299
Johan Hedberg37438c12013-10-14 16:20:05 +03001300remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001301 mgmt_pending_remove(cmd);
1302
1303unlock:
1304 hci_dev_unlock(hdev);
1305}
1306
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001307static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001308 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001309{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001310 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001311 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001312 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001313 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001314 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001315
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001316 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001317
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001318 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1319 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001320 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001321 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001322
Johan Hedberga7e80f22013-01-09 16:05:19 +02001323 if (cp->val != 0x00 && cp->val != 0x01)
1324 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1325 MGMT_STATUS_INVALID_PARAMS);
1326
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001327 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001328
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001329 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001330 bool changed = false;
1331
1332 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1333 changed = true;
1334
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001335 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001336 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001337 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001338 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1339 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1340 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001341
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001342 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001343 if (err < 0)
1344 goto failed;
1345
1346 if (changed)
1347 err = new_settings(hdev, sk);
1348
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001349 goto failed;
1350 }
1351
1352 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001353 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001354 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001355 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001356 goto failed;
1357 }
1358
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001359 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1360 if (!cmd) {
1361 err = -ENOMEM;
1362 goto failed;
1363 }
1364
Johan Hedberg2b76f452013-03-15 17:07:04 -05001365 hci_req_init(&req, hdev);
1366
Johan Hedberg9b742462013-10-14 16:20:03 +03001367 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1368 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001369 if (cp->val) {
1370 scan = SCAN_PAGE;
1371 } else {
1372 scan = 0;
1373
1374 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001375 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001376 cancel_delayed_work(&hdev->discov_off);
1377 }
1378
1379 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1380 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001381
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001382 /* If we're going from non-connectable to connectable or
1383 * vice-versa when fast connectable is enabled ensure that fast
1384 * connectable gets disabled. write_fast_connectable won't do
1385 * anything if the page scan parameters are already what they
1386 * should be.
1387 */
1388 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001389 write_fast_connectable(&req, false);
1390
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001391 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1392 hci_conn_num(hdev, LE_LINK) == 0) {
1393 disable_advertising(&req);
1394 enable_advertising(&req);
1395 }
1396
Johan Hedberg2b76f452013-03-15 17:07:04 -05001397 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001398 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001399 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001400 if (err == -ENODATA)
1401 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1402 hdev);
1403 goto failed;
1404 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001405
1406failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001407 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001408 return err;
1409}
1410
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001411static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001412 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001413{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001414 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001415 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001416 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001417
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001418 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001419
Johan Hedberga7e80f22013-01-09 16:05:19 +02001420 if (cp->val != 0x00 && cp->val != 0x01)
1421 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1422 MGMT_STATUS_INVALID_PARAMS);
1423
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001424 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001425
1426 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001427 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001428 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001429 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001430
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001431 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001432 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001433 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001434
Marcel Holtmann55594352013-10-06 16:11:57 -07001435 if (changed)
1436 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001437
Marcel Holtmann55594352013-10-06 16:11:57 -07001438unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001439 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001440 return err;
1441}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001442
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001443static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1444 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001445{
1446 struct mgmt_mode *cp = data;
1447 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001448 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001449 int err;
1450
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001451 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001452
Johan Hedberge6fe7982013-10-02 15:45:22 +03001453 status = mgmt_bredr_support(hdev);
1454 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001455 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001456 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001457
Johan Hedberga7e80f22013-01-09 16:05:19 +02001458 if (cp->val != 0x00 && cp->val != 0x01)
1459 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1460 MGMT_STATUS_INVALID_PARAMS);
1461
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001462 hci_dev_lock(hdev);
1463
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001464 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001465 bool changed = false;
1466
1467 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001468 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001469 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1470 changed = true;
1471 }
1472
1473 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1474 if (err < 0)
1475 goto failed;
1476
1477 if (changed)
1478 err = new_settings(hdev, sk);
1479
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001480 goto failed;
1481 }
1482
1483 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001484 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001485 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001486 goto failed;
1487 }
1488
1489 val = !!cp->val;
1490
1491 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1492 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1493 goto failed;
1494 }
1495
1496 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1497 if (!cmd) {
1498 err = -ENOMEM;
1499 goto failed;
1500 }
1501
1502 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1503 if (err < 0) {
1504 mgmt_pending_remove(cmd);
1505 goto failed;
1506 }
1507
1508failed:
1509 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001510 return err;
1511}
1512
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001513static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001514{
1515 struct mgmt_mode *cp = data;
1516 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001517 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001518 int err;
1519
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001520 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001521
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001522 status = mgmt_bredr_support(hdev);
1523 if (status)
1524 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1525
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001526 if (!lmp_ssp_capable(hdev))
1527 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1528 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001529
Johan Hedberga7e80f22013-01-09 16:05:19 +02001530 if (cp->val != 0x00 && cp->val != 0x01)
1531 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1532 MGMT_STATUS_INVALID_PARAMS);
1533
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001534 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001535
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001536 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001537 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001538
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001539 if (cp->val) {
1540 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1541 &hdev->dev_flags);
1542 } else {
1543 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1544 &hdev->dev_flags);
1545 if (!changed)
1546 changed = test_and_clear_bit(HCI_HS_ENABLED,
1547 &hdev->dev_flags);
1548 else
1549 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001550 }
1551
1552 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1553 if (err < 0)
1554 goto failed;
1555
1556 if (changed)
1557 err = new_settings(hdev, sk);
1558
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001559 goto failed;
1560 }
1561
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001562 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1563 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001564 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1565 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001566 goto failed;
1567 }
1568
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001569 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001570 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1571 goto failed;
1572 }
1573
1574 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1575 if (!cmd) {
1576 err = -ENOMEM;
1577 goto failed;
1578 }
1579
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001580 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001581 if (err < 0) {
1582 mgmt_pending_remove(cmd);
1583 goto failed;
1584 }
1585
1586failed:
1587 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001588 return err;
1589}
1590
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001591static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001592{
1593 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001594 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001595 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001596 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001597
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001598 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001599
Johan Hedberge6fe7982013-10-02 15:45:22 +03001600 status = mgmt_bredr_support(hdev);
1601 if (status)
1602 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001603
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001604 if (!lmp_ssp_capable(hdev))
1605 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1606 MGMT_STATUS_NOT_SUPPORTED);
1607
1608 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1609 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1610 MGMT_STATUS_REJECTED);
1611
Johan Hedberga7e80f22013-01-09 16:05:19 +02001612 if (cp->val != 0x00 && cp->val != 0x01)
1613 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1614 MGMT_STATUS_INVALID_PARAMS);
1615
Marcel Holtmannee392692013-10-01 22:59:23 -07001616 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001617
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001618 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001619 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001620 } else {
1621 if (hdev_is_powered(hdev)) {
1622 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1623 MGMT_STATUS_REJECTED);
1624 goto unlock;
1625 }
1626
Marcel Holtmannee392692013-10-01 22:59:23 -07001627 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001628 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001629
1630 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1631 if (err < 0)
1632 goto unlock;
1633
1634 if (changed)
1635 err = new_settings(hdev, sk);
1636
1637unlock:
1638 hci_dev_unlock(hdev);
1639 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001640}
1641
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001642static void le_enable_complete(struct hci_dev *hdev, u8 status)
1643{
1644 struct cmd_lookup match = { NULL, hdev };
1645
1646 if (status) {
1647 u8 mgmt_err = mgmt_status(status);
1648
1649 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1650 &mgmt_err);
1651 return;
1652 }
1653
1654 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1655
1656 new_settings(hdev, match.sk);
1657
1658 if (match.sk)
1659 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001660
1661 /* Make sure the controller has a good default for
1662 * advertising data. Restrict the update to when LE
1663 * has actually been enabled. During power on, the
1664 * update in powered_update_hci will take care of it.
1665 */
1666 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1667 struct hci_request req;
1668
1669 hci_dev_lock(hdev);
1670
1671 hci_req_init(&req, hdev);
1672 update_ad(&req);
1673 hci_req_run(&req, NULL);
1674
1675 hci_dev_unlock(hdev);
1676 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001677}
1678
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001679static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001680{
1681 struct mgmt_mode *cp = data;
1682 struct hci_cp_write_le_host_supported hci_cp;
1683 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001684 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001685 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001686 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001687
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001688 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001689
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001690 if (!lmp_le_capable(hdev))
1691 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1692 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001693
Johan Hedberga7e80f22013-01-09 16:05:19 +02001694 if (cp->val != 0x00 && cp->val != 0x01)
1695 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1696 MGMT_STATUS_INVALID_PARAMS);
1697
Johan Hedbergc73eee92013-04-19 18:35:21 +03001698 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001699 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001700 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1701 MGMT_STATUS_REJECTED);
1702
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001703 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001704
1705 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001706 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001707
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001708 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001709 bool changed = false;
1710
1711 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1712 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1713 changed = true;
1714 }
1715
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001716 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1717 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001718 changed = true;
1719 }
1720
Johan Hedberg06199cf2012-02-22 16:37:11 +02001721 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1722 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001723 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001724
1725 if (changed)
1726 err = new_settings(hdev, sk);
1727
Johan Hedberg1de028c2012-02-29 19:55:35 -08001728 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001729 }
1730
Johan Hedberg4375f102013-09-25 13:26:10 +03001731 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1732 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001733 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001734 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001735 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001736 }
1737
1738 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1739 if (!cmd) {
1740 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001741 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001742 }
1743
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001744 hci_req_init(&req, hdev);
1745
Johan Hedberg06199cf2012-02-22 16:37:11 +02001746 memset(&hci_cp, 0, sizeof(hci_cp));
1747
1748 if (val) {
1749 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001750 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001751 } else {
1752 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1753 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001754 }
1755
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001756 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1757 &hci_cp);
1758
1759 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301760 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001761 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001762
Johan Hedberg1de028c2012-02-29 19:55:35 -08001763unlock:
1764 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001765 return err;
1766}
1767
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001768/* This is a helper function to test for pending mgmt commands that can
1769 * cause CoD or EIR HCI commands. We can only allow one such pending
1770 * mgmt command at a time since otherwise we cannot easily track what
1771 * the current values are, will be, and based on that calculate if a new
1772 * HCI command needs to be sent and if yes with what value.
1773 */
1774static bool pending_eir_or_class(struct hci_dev *hdev)
1775{
1776 struct pending_cmd *cmd;
1777
1778 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1779 switch (cmd->opcode) {
1780 case MGMT_OP_ADD_UUID:
1781 case MGMT_OP_REMOVE_UUID:
1782 case MGMT_OP_SET_DEV_CLASS:
1783 case MGMT_OP_SET_POWERED:
1784 return true;
1785 }
1786 }
1787
1788 return false;
1789}
1790
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001791static const u8 bluetooth_base_uuid[] = {
1792 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1793 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1794};
1795
1796static u8 get_uuid_size(const u8 *uuid)
1797{
1798 u32 val;
1799
1800 if (memcmp(uuid, bluetooth_base_uuid, 12))
1801 return 128;
1802
1803 val = get_unaligned_le32(&uuid[12]);
1804 if (val > 0xffff)
1805 return 32;
1806
1807 return 16;
1808}
1809
Johan Hedberg92da6092013-03-15 17:06:55 -05001810static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1811{
1812 struct pending_cmd *cmd;
1813
1814 hci_dev_lock(hdev);
1815
1816 cmd = mgmt_pending_find(mgmt_op, hdev);
1817 if (!cmd)
1818 goto unlock;
1819
1820 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1821 hdev->dev_class, 3);
1822
1823 mgmt_pending_remove(cmd);
1824
1825unlock:
1826 hci_dev_unlock(hdev);
1827}
1828
1829static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1830{
1831 BT_DBG("status 0x%02x", status);
1832
1833 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1834}
1835
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001836static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001837{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001838 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001839 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001840 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001841 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001842 int err;
1843
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001844 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001845
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001846 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001847
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001848 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001849 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001850 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001851 goto failed;
1852 }
1853
Andre Guedes92c4c202012-06-07 19:05:44 -03001854 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001855 if (!uuid) {
1856 err = -ENOMEM;
1857 goto failed;
1858 }
1859
1860 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001861 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001862 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001863
Johan Hedbergde66aa62013-01-27 00:31:27 +02001864 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001865
Johan Hedberg890ea892013-03-15 17:06:52 -05001866 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001867
Johan Hedberg890ea892013-03-15 17:06:52 -05001868 update_class(&req);
1869 update_eir(&req);
1870
Johan Hedberg92da6092013-03-15 17:06:55 -05001871 err = hci_req_run(&req, add_uuid_complete);
1872 if (err < 0) {
1873 if (err != -ENODATA)
1874 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001875
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001876 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001877 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001878 goto failed;
1879 }
1880
1881 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001882 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001883 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001884 goto failed;
1885 }
1886
1887 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001888
1889failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001890 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001891 return err;
1892}
1893
Johan Hedberg24b78d02012-02-23 23:24:30 +02001894static bool enable_service_cache(struct hci_dev *hdev)
1895{
1896 if (!hdev_is_powered(hdev))
1897 return false;
1898
1899 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001900 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1901 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001902 return true;
1903 }
1904
1905 return false;
1906}
1907
Johan Hedberg92da6092013-03-15 17:06:55 -05001908static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1909{
1910 BT_DBG("status 0x%02x", status);
1911
1912 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1913}
1914
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001915static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001916 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001917{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001918 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001919 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001920 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001921 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 -05001922 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001923 int err, found;
1924
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001925 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001926
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001927 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001928
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001929 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001930 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001931 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001932 goto unlock;
1933 }
1934
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001935 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1936 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001937
Johan Hedberg24b78d02012-02-23 23:24:30 +02001938 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001939 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001940 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001941 goto unlock;
1942 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001943
Johan Hedberg9246a862012-02-23 21:33:16 +02001944 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001945 }
1946
1947 found = 0;
1948
Johan Hedberg056341c2013-01-27 00:31:30 +02001949 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001950 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1951 continue;
1952
1953 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001954 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001955 found++;
1956 }
1957
1958 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001959 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001960 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001961 goto unlock;
1962 }
1963
Johan Hedberg9246a862012-02-23 21:33:16 +02001964update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001965 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001966
Johan Hedberg890ea892013-03-15 17:06:52 -05001967 update_class(&req);
1968 update_eir(&req);
1969
Johan Hedberg92da6092013-03-15 17:06:55 -05001970 err = hci_req_run(&req, remove_uuid_complete);
1971 if (err < 0) {
1972 if (err != -ENODATA)
1973 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001974
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001975 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001976 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001977 goto unlock;
1978 }
1979
1980 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001981 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001982 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001983 goto unlock;
1984 }
1985
1986 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001987
1988unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001989 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001990 return err;
1991}
1992
Johan Hedberg92da6092013-03-15 17:06:55 -05001993static void set_class_complete(struct hci_dev *hdev, u8 status)
1994{
1995 BT_DBG("status 0x%02x", status);
1996
1997 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1998}
1999
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002000static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002001 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002002{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002003 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002004 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002005 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002006 int err;
2007
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002008 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002009
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002010 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002011 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2012 MGMT_STATUS_NOT_SUPPORTED);
2013
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002014 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002015
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002016 if (pending_eir_or_class(hdev)) {
2017 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2018 MGMT_STATUS_BUSY);
2019 goto unlock;
2020 }
2021
2022 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2023 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2024 MGMT_STATUS_INVALID_PARAMS);
2025 goto unlock;
2026 }
2027
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002028 hdev->major_class = cp->major;
2029 hdev->minor_class = cp->minor;
2030
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002031 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002032 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002033 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002034 goto unlock;
2035 }
2036
Johan Hedberg890ea892013-03-15 17:06:52 -05002037 hci_req_init(&req, hdev);
2038
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002039 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002040 hci_dev_unlock(hdev);
2041 cancel_delayed_work_sync(&hdev->service_cache);
2042 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002043 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002044 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002045
Johan Hedberg890ea892013-03-15 17:06:52 -05002046 update_class(&req);
2047
Johan Hedberg92da6092013-03-15 17:06:55 -05002048 err = hci_req_run(&req, set_class_complete);
2049 if (err < 0) {
2050 if (err != -ENODATA)
2051 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002052
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002053 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002054 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002055 goto unlock;
2056 }
2057
2058 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002059 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002060 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002061 goto unlock;
2062 }
2063
2064 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002065
Johan Hedbergb5235a62012-02-21 14:32:24 +02002066unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002067 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002068 return err;
2069}
2070
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002071static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002072 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002073{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002074 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002075 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002076 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002077
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002078 BT_DBG("request for %s", hdev->name);
2079
2080 if (!lmp_bredr_capable(hdev))
2081 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2082 MGMT_STATUS_NOT_SUPPORTED);
2083
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002084 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002085
Johan Hedberg86742e12011-11-07 23:13:38 +02002086 expected_len = sizeof(*cp) + key_count *
2087 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002088 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002089 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002090 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002091 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002092 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002093 }
2094
Johan Hedberg4ae14302013-01-20 14:27:13 +02002095 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2096 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2097 MGMT_STATUS_INVALID_PARAMS);
2098
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002099 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002100 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002101
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002102 for (i = 0; i < key_count; i++) {
2103 struct mgmt_link_key_info *key = &cp->keys[i];
2104
2105 if (key->addr.type != BDADDR_BREDR)
2106 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2107 MGMT_STATUS_INVALID_PARAMS);
2108 }
2109
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002110 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002111
2112 hci_link_keys_clear(hdev);
2113
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002114 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002115 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002116 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002117 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002118
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002119 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002120 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002121
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002122 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002123 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002124 }
2125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002126 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002127
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002128 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002129
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002130 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002131}
2132
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002133static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002134 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002135{
2136 struct mgmt_ev_device_unpaired ev;
2137
2138 bacpy(&ev.addr.bdaddr, bdaddr);
2139 ev.addr.type = addr_type;
2140
2141 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002142 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002143}
2144
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002145static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002146 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002147{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002148 struct mgmt_cp_unpair_device *cp = data;
2149 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002150 struct hci_cp_disconnect dc;
2151 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002152 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002153 int err;
2154
Johan Hedberga8a1d192011-11-10 15:54:38 +02002155 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002156 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2157 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002158
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002159 if (!bdaddr_type_is_valid(cp->addr.type))
2160 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2161 MGMT_STATUS_INVALID_PARAMS,
2162 &rp, sizeof(rp));
2163
Johan Hedberg118da702013-01-20 14:27:20 +02002164 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2165 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2166 MGMT_STATUS_INVALID_PARAMS,
2167 &rp, sizeof(rp));
2168
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002169 hci_dev_lock(hdev);
2170
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002171 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002172 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002173 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002174 goto unlock;
2175 }
2176
Andre Guedes591f47f2012-04-24 21:02:49 -03002177 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002178 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2179 else
2180 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002181
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002182 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002183 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002184 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002185 goto unlock;
2186 }
2187
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002188 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002189 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002190 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002191 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002192 else
2193 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002194 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002195 } else {
2196 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002197 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002198
Johan Hedberga8a1d192011-11-10 15:54:38 +02002199 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002200 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002201 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002202 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002203 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002204 }
2205
Johan Hedberg124f6e32012-02-09 13:50:12 +02002206 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002207 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002208 if (!cmd) {
2209 err = -ENOMEM;
2210 goto unlock;
2211 }
2212
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002213 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002214 dc.reason = 0x13; /* Remote User Terminated Connection */
2215 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2216 if (err < 0)
2217 mgmt_pending_remove(cmd);
2218
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002219unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002220 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002221 return err;
2222}
2223
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002224static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002225 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002226{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002227 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002228 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002229 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002230 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002231 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002232 int err;
2233
2234 BT_DBG("");
2235
Johan Hedberg06a63b12013-01-20 14:27:21 +02002236 memset(&rp, 0, sizeof(rp));
2237 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2238 rp.addr.type = cp->addr.type;
2239
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002240 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002241 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2242 MGMT_STATUS_INVALID_PARAMS,
2243 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002244
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002245 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002246
2247 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002248 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2249 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002250 goto failed;
2251 }
2252
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002253 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002254 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2255 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002256 goto failed;
2257 }
2258
Andre Guedes591f47f2012-04-24 21:02:49 -03002259 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002260 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2261 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002262 else
2263 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002264
Vishal Agarwalf9607272012-06-13 05:32:43 +05302265 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002266 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2267 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002268 goto failed;
2269 }
2270
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002271 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002272 if (!cmd) {
2273 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002274 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002275 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002276
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002277 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002278 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002279
2280 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2281 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002282 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002283
2284failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002285 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002286 return err;
2287}
2288
Andre Guedes57c14772012-04-24 21:02:50 -03002289static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002290{
2291 switch (link_type) {
2292 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002293 switch (addr_type) {
2294 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002295 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002296
Johan Hedberg48264f02011-11-09 13:58:58 +02002297 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002298 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002299 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002300 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002301
Johan Hedberg4c659c32011-11-07 23:13:39 +02002302 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002303 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002304 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002305 }
2306}
2307
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002308static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2309 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002310{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002311 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002312 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002313 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002314 int err;
2315 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002316
2317 BT_DBG("");
2318
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002319 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002320
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002321 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002322 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002323 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002324 goto unlock;
2325 }
2326
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002327 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002328 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2329 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002330 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002331 }
2332
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002333 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002334 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002335 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002336 err = -ENOMEM;
2337 goto unlock;
2338 }
2339
Johan Hedberg2784eb42011-01-21 13:56:35 +02002340 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002341 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002342 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2343 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002344 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002345 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002346 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002347 continue;
2348 i++;
2349 }
2350
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002351 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002352
Johan Hedberg4c659c32011-11-07 23:13:39 +02002353 /* Recalculate length in case of filtered SCO connections, etc */
2354 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002355
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002356 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002357 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002358
Johan Hedberga38528f2011-01-22 06:46:43 +02002359 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002360
2361unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002362 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002363 return err;
2364}
2365
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002366static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002367 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002368{
2369 struct pending_cmd *cmd;
2370 int err;
2371
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002372 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002373 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002374 if (!cmd)
2375 return -ENOMEM;
2376
Johan Hedbergd8457692012-02-17 14:24:57 +02002377 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002378 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002379 if (err < 0)
2380 mgmt_pending_remove(cmd);
2381
2382 return err;
2383}
2384
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002385static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002386 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002387{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002388 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002389 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002390 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002391 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002392 int err;
2393
2394 BT_DBG("");
2395
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002396 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002397
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002398 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002399 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002400 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002401 goto failed;
2402 }
2403
Johan Hedbergd8457692012-02-17 14:24:57 +02002404 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002405 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002406 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002407 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002408 goto failed;
2409 }
2410
2411 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002412 struct mgmt_cp_pin_code_neg_reply ncp;
2413
2414 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002415
2416 BT_ERR("PIN code is not 16 bytes long");
2417
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002418 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002419 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002420 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002421 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002422
2423 goto failed;
2424 }
2425
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002426 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002427 if (!cmd) {
2428 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002429 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002430 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002431
Johan Hedbergd8457692012-02-17 14:24:57 +02002432 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002433 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002434 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002435
2436 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2437 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002438 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002439
2440failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002441 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002442 return err;
2443}
2444
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002445static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2446 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002447{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002448 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002449
2450 BT_DBG("");
2451
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002452 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002453
2454 hdev->io_capability = cp->io_capability;
2455
2456 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002457 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002458
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002459 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002460
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002461 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2462 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002463}
2464
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002465static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002466{
2467 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002468 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002469
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002470 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002471 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2472 continue;
2473
Johan Hedberge9a416b2011-02-19 12:05:56 -03002474 if (cmd->user_data != conn)
2475 continue;
2476
2477 return cmd;
2478 }
2479
2480 return NULL;
2481}
2482
2483static void pairing_complete(struct pending_cmd *cmd, u8 status)
2484{
2485 struct mgmt_rp_pair_device rp;
2486 struct hci_conn *conn = cmd->user_data;
2487
Johan Hedbergba4e5642011-11-11 00:07:34 +02002488 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002489 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002490
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002491 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002492 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002493
2494 /* So we don't get further callbacks for this connection */
2495 conn->connect_cfm_cb = NULL;
2496 conn->security_cfm_cb = NULL;
2497 conn->disconn_cfm_cb = NULL;
2498
David Herrmann76a68ba2013-04-06 20:28:37 +02002499 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002500
Johan Hedberga664b5b2011-02-19 12:06:02 -03002501 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002502}
2503
2504static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2505{
2506 struct pending_cmd *cmd;
2507
2508 BT_DBG("status %u", status);
2509
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002510 cmd = find_pairing(conn);
2511 if (!cmd)
2512 BT_DBG("Unable to find a pending command");
2513 else
Johan Hedberge2113262012-02-18 15:20:03 +02002514 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002515}
2516
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302517static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2518{
2519 struct pending_cmd *cmd;
2520
2521 BT_DBG("status %u", status);
2522
2523 if (!status)
2524 return;
2525
2526 cmd = find_pairing(conn);
2527 if (!cmd)
2528 BT_DBG("Unable to find a pending command");
2529 else
2530 pairing_complete(cmd, mgmt_status(status));
2531}
2532
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002533static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002534 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002535{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002536 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002537 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002538 struct pending_cmd *cmd;
2539 u8 sec_level, auth_type;
2540 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002541 int err;
2542
2543 BT_DBG("");
2544
Szymon Jancf950a30e2013-01-18 12:48:07 +01002545 memset(&rp, 0, sizeof(rp));
2546 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2547 rp.addr.type = cp->addr.type;
2548
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002549 if (!bdaddr_type_is_valid(cp->addr.type))
2550 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2551 MGMT_STATUS_INVALID_PARAMS,
2552 &rp, sizeof(rp));
2553
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002554 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002555
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002556 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002557 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2558 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002559 goto unlock;
2560 }
2561
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002562 sec_level = BT_SECURITY_MEDIUM;
2563 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002564 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002565 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002566 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002567
Andre Guedes591f47f2012-04-24 21:02:49 -03002568 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002569 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2570 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002571 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002572 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2573 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002574
Ville Tervo30e76272011-02-22 16:10:53 -03002575 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002576 int status;
2577
2578 if (PTR_ERR(conn) == -EBUSY)
2579 status = MGMT_STATUS_BUSY;
2580 else
2581 status = MGMT_STATUS_CONNECT_FAILED;
2582
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002583 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002584 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002585 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002586 goto unlock;
2587 }
2588
2589 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002590 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002591 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002592 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002593 goto unlock;
2594 }
2595
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002596 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002597 if (!cmd) {
2598 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002599 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002600 goto unlock;
2601 }
2602
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002603 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002604 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002605 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302606 else
2607 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002608
Johan Hedberge9a416b2011-02-19 12:05:56 -03002609 conn->security_cfm_cb = pairing_complete_cb;
2610 conn->disconn_cfm_cb = pairing_complete_cb;
2611 conn->io_capability = cp->io_cap;
2612 cmd->user_data = conn;
2613
2614 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002615 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002616 pairing_complete(cmd, 0);
2617
2618 err = 0;
2619
2620unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002621 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002622 return err;
2623}
2624
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002625static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2626 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002627{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002628 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002629 struct pending_cmd *cmd;
2630 struct hci_conn *conn;
2631 int err;
2632
2633 BT_DBG("");
2634
Johan Hedberg28424702012-02-02 04:02:29 +02002635 hci_dev_lock(hdev);
2636
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002637 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002638 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002639 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002640 goto unlock;
2641 }
2642
Johan Hedberg28424702012-02-02 04:02:29 +02002643 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2644 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002645 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002646 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002647 goto unlock;
2648 }
2649
2650 conn = cmd->user_data;
2651
2652 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002653 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002654 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002655 goto unlock;
2656 }
2657
2658 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2659
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002660 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002661 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002662unlock:
2663 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002664 return err;
2665}
2666
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002667static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002668 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002669 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002670{
Johan Hedberga5c29682011-02-19 12:05:57 -03002671 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002672 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002673 int err;
2674
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002675 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002676
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002677 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002678 err = cmd_complete(sk, hdev->id, mgmt_op,
2679 MGMT_STATUS_NOT_POWERED, addr,
2680 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002681 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002682 }
2683
Johan Hedberg1707c602013-03-15 17:07:15 -05002684 if (addr->type == BDADDR_BREDR)
2685 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002686 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002687 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002688
Johan Hedberg272d90d2012-02-09 15:26:12 +02002689 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002690 err = cmd_complete(sk, hdev->id, mgmt_op,
2691 MGMT_STATUS_NOT_CONNECTED, addr,
2692 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002693 goto done;
2694 }
2695
Johan Hedberg1707c602013-03-15 17:07:15 -05002696 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002697 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002698 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002699
Brian Gix5fe57d92011-12-21 16:12:13 -08002700 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002701 err = cmd_complete(sk, hdev->id, mgmt_op,
2702 MGMT_STATUS_SUCCESS, addr,
2703 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002704 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002705 err = cmd_complete(sk, hdev->id, mgmt_op,
2706 MGMT_STATUS_FAILED, addr,
2707 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002708
Brian Gix47c15e22011-11-16 13:53:14 -08002709 goto done;
2710 }
2711
Johan Hedberg1707c602013-03-15 17:07:15 -05002712 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002713 if (!cmd) {
2714 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002715 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002716 }
2717
Brian Gix0df4c182011-11-16 13:53:13 -08002718 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002719 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2720 struct hci_cp_user_passkey_reply cp;
2721
Johan Hedberg1707c602013-03-15 17:07:15 -05002722 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002723 cp.passkey = passkey;
2724 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2725 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002726 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2727 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002728
Johan Hedberga664b5b2011-02-19 12:06:02 -03002729 if (err < 0)
2730 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002731
Brian Gix0df4c182011-11-16 13:53:13 -08002732done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002733 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002734 return err;
2735}
2736
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302737static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2738 void *data, u16 len)
2739{
2740 struct mgmt_cp_pin_code_neg_reply *cp = data;
2741
2742 BT_DBG("");
2743
Johan Hedberg1707c602013-03-15 17:07:15 -05002744 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302745 MGMT_OP_PIN_CODE_NEG_REPLY,
2746 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2747}
2748
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002749static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2750 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002751{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002752 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002753
2754 BT_DBG("");
2755
2756 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002757 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002758 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002759
Johan Hedberg1707c602013-03-15 17:07:15 -05002760 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002761 MGMT_OP_USER_CONFIRM_REPLY,
2762 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002763}
2764
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002765static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002766 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002767{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002768 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002769
2770 BT_DBG("");
2771
Johan Hedberg1707c602013-03-15 17:07:15 -05002772 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002773 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2774 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002775}
2776
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002777static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2778 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002779{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002780 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002781
2782 BT_DBG("");
2783
Johan Hedberg1707c602013-03-15 17:07:15 -05002784 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002785 MGMT_OP_USER_PASSKEY_REPLY,
2786 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002787}
2788
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002789static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002790 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002791{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002792 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002793
2794 BT_DBG("");
2795
Johan Hedberg1707c602013-03-15 17:07:15 -05002796 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002797 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2798 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002799}
2800
Johan Hedberg13928972013-03-15 17:07:00 -05002801static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002802{
Johan Hedberg13928972013-03-15 17:07:00 -05002803 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002804 struct hci_cp_write_local_name cp;
2805
Johan Hedberg13928972013-03-15 17:07:00 -05002806 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002807
Johan Hedberg890ea892013-03-15 17:06:52 -05002808 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002809}
2810
Johan Hedberg13928972013-03-15 17:07:00 -05002811static void set_name_complete(struct hci_dev *hdev, u8 status)
2812{
2813 struct mgmt_cp_set_local_name *cp;
2814 struct pending_cmd *cmd;
2815
2816 BT_DBG("status 0x%02x", status);
2817
2818 hci_dev_lock(hdev);
2819
2820 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2821 if (!cmd)
2822 goto unlock;
2823
2824 cp = cmd->param;
2825
2826 if (status)
2827 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2828 mgmt_status(status));
2829 else
2830 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2831 cp, sizeof(*cp));
2832
2833 mgmt_pending_remove(cmd);
2834
2835unlock:
2836 hci_dev_unlock(hdev);
2837}
2838
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002839static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002840 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002841{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002842 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002843 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002844 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002845 int err;
2846
2847 BT_DBG("");
2848
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002849 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002850
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002851 /* If the old values are the same as the new ones just return a
2852 * direct command complete event.
2853 */
2854 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2855 !memcmp(hdev->short_name, cp->short_name,
2856 sizeof(hdev->short_name))) {
2857 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2858 data, len);
2859 goto failed;
2860 }
2861
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002862 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002863
Johan Hedbergb5235a62012-02-21 14:32:24 +02002864 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002865 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002866
2867 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002868 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002869 if (err < 0)
2870 goto failed;
2871
2872 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002873 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002874
Johan Hedbergb5235a62012-02-21 14:32:24 +02002875 goto failed;
2876 }
2877
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002878 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002879 if (!cmd) {
2880 err = -ENOMEM;
2881 goto failed;
2882 }
2883
Johan Hedberg13928972013-03-15 17:07:00 -05002884 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2885
Johan Hedberg890ea892013-03-15 17:06:52 -05002886 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002887
2888 if (lmp_bredr_capable(hdev)) {
2889 update_name(&req);
2890 update_eir(&req);
2891 }
2892
2893 if (lmp_le_capable(hdev))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002894 update_ad(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05002895
Johan Hedberg13928972013-03-15 17:07:00 -05002896 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002897 if (err < 0)
2898 mgmt_pending_remove(cmd);
2899
2900failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002901 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002902 return err;
2903}
2904
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002905static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002906 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002907{
Szymon Jancc35938b2011-03-22 13:12:21 +01002908 struct pending_cmd *cmd;
2909 int err;
2910
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002911 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002912
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002913 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002914
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002915 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002916 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002917 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002918 goto unlock;
2919 }
2920
Andre Guedes9a1a1992012-07-24 15:03:48 -03002921 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002922 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002923 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002924 goto unlock;
2925 }
2926
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002927 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002928 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002929 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002930 goto unlock;
2931 }
2932
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002933 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002934 if (!cmd) {
2935 err = -ENOMEM;
2936 goto unlock;
2937 }
2938
2939 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2940 if (err < 0)
2941 mgmt_pending_remove(cmd);
2942
2943unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002944 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002945 return err;
2946}
2947
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002948static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002949 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002950{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002951 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002952 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002953 int err;
2954
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002955 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002956
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002957 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002958
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002959 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002960 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002961 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002962 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002963 else
Szymon Janca6785be2012-12-13 15:11:21 +01002964 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002965
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002966 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002967 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002968
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002969 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002970 return err;
2971}
2972
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002973static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002974 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002975{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002976 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002977 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002978 int err;
2979
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002980 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002981
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002982 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002983
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002984 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002985 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002986 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002987 else
Szymon Janca6785be2012-12-13 15:11:21 +01002988 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002989
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002990 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002991 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002992
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002993 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002994 return err;
2995}
2996
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002997static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2998{
2999 struct pending_cmd *cmd;
3000 u8 type;
3001 int err;
3002
3003 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3004
3005 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3006 if (!cmd)
3007 return -ENOENT;
3008
3009 type = hdev->discovery.type;
3010
3011 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3012 &type, sizeof(type));
3013 mgmt_pending_remove(cmd);
3014
3015 return err;
3016}
3017
Andre Guedes7c307722013-04-30 15:29:28 -03003018static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3019{
3020 BT_DBG("status %d", status);
3021
3022 if (status) {
3023 hci_dev_lock(hdev);
3024 mgmt_start_discovery_failed(hdev, status);
3025 hci_dev_unlock(hdev);
3026 return;
3027 }
3028
3029 hci_dev_lock(hdev);
3030 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3031 hci_dev_unlock(hdev);
3032
3033 switch (hdev->discovery.type) {
3034 case DISCOV_TYPE_LE:
3035 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003036 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003037 break;
3038
3039 case DISCOV_TYPE_INTERLEAVED:
3040 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003041 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003042 break;
3043
3044 case DISCOV_TYPE_BREDR:
3045 break;
3046
3047 default:
3048 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3049 }
3050}
3051
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003052static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003053 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003054{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003055 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003056 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003057 struct hci_cp_le_set_scan_param param_cp;
3058 struct hci_cp_le_set_scan_enable enable_cp;
3059 struct hci_cp_inquiry inq_cp;
3060 struct hci_request req;
3061 /* General inquiry access code (GIAC) */
3062 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003063 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003064 int err;
3065
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003066 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003067
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003068 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003069
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003070 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003071 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003072 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003073 goto failed;
3074 }
3075
Andre Guedes642be6c2012-03-21 00:03:37 -03003076 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3077 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3078 MGMT_STATUS_BUSY);
3079 goto failed;
3080 }
3081
Johan Hedbergff9ef572012-01-04 14:23:45 +02003082 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003083 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003084 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003085 goto failed;
3086 }
3087
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003088 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003089 if (!cmd) {
3090 err = -ENOMEM;
3091 goto failed;
3092 }
3093
Andre Guedes4aab14e2012-02-17 20:39:36 -03003094 hdev->discovery.type = cp->type;
3095
Andre Guedes7c307722013-04-30 15:29:28 -03003096 hci_req_init(&req, hdev);
3097
Andre Guedes4aab14e2012-02-17 20:39:36 -03003098 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003099 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003100 status = mgmt_bredr_support(hdev);
3101 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003102 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003103 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003104 mgmt_pending_remove(cmd);
3105 goto failed;
3106 }
3107
Andre Guedes7c307722013-04-30 15:29:28 -03003108 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3109 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3110 MGMT_STATUS_BUSY);
3111 mgmt_pending_remove(cmd);
3112 goto failed;
3113 }
3114
3115 hci_inquiry_cache_flush(hdev);
3116
3117 memset(&inq_cp, 0, sizeof(inq_cp));
3118 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003119 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003120 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003121 break;
3122
3123 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003124 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003125 status = mgmt_le_support(hdev);
3126 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003127 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003128 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003129 mgmt_pending_remove(cmd);
3130 goto failed;
3131 }
3132
Andre Guedes7c307722013-04-30 15:29:28 -03003133 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003134 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003135 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3136 MGMT_STATUS_NOT_SUPPORTED);
3137 mgmt_pending_remove(cmd);
3138 goto failed;
3139 }
3140
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003141 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003142 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3143 MGMT_STATUS_REJECTED);
3144 mgmt_pending_remove(cmd);
3145 goto failed;
3146 }
3147
3148 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3149 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3150 MGMT_STATUS_BUSY);
3151 mgmt_pending_remove(cmd);
3152 goto failed;
3153 }
3154
3155 memset(&param_cp, 0, sizeof(param_cp));
3156 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003157 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3158 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07003159 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
3160 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
3161 else
3162 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03003163 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3164 &param_cp);
3165
3166 memset(&enable_cp, 0, sizeof(enable_cp));
3167 enable_cp.enable = LE_SCAN_ENABLE;
3168 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3169 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3170 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003171 break;
3172
Andre Guedesf39799f2012-02-17 20:39:35 -03003173 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003174 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3175 MGMT_STATUS_INVALID_PARAMS);
3176 mgmt_pending_remove(cmd);
3177 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003178 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003179
Andre Guedes7c307722013-04-30 15:29:28 -03003180 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003181 if (err < 0)
3182 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003183 else
3184 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003185
3186failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003187 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003188 return err;
3189}
3190
Andre Guedes1183fdc2013-04-30 15:29:35 -03003191static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3192{
3193 struct pending_cmd *cmd;
3194 int err;
3195
3196 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3197 if (!cmd)
3198 return -ENOENT;
3199
3200 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3201 &hdev->discovery.type, sizeof(hdev->discovery.type));
3202 mgmt_pending_remove(cmd);
3203
3204 return err;
3205}
3206
Andre Guedes0e05bba2013-04-30 15:29:33 -03003207static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3208{
3209 BT_DBG("status %d", status);
3210
3211 hci_dev_lock(hdev);
3212
3213 if (status) {
3214 mgmt_stop_discovery_failed(hdev, status);
3215 goto unlock;
3216 }
3217
3218 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3219
3220unlock:
3221 hci_dev_unlock(hdev);
3222}
3223
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003224static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003225 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003226{
Johan Hedbergd9306502012-02-20 23:25:18 +02003227 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003228 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003229 struct hci_cp_remote_name_req_cancel cp;
3230 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003231 struct hci_request req;
3232 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003233 int err;
3234
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003235 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003236
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003237 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003238
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003239 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003240 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003241 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3242 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003243 goto unlock;
3244 }
3245
3246 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003247 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003248 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3249 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003250 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003251 }
3252
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003253 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003254 if (!cmd) {
3255 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003256 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003257 }
3258
Andre Guedes0e05bba2013-04-30 15:29:33 -03003259 hci_req_init(&req, hdev);
3260
Andre Guedese0d9727e2012-03-20 15:15:36 -03003261 switch (hdev->discovery.state) {
3262 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003263 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3264 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3265 } else {
3266 cancel_delayed_work(&hdev->le_scan_disable);
3267
3268 memset(&enable_cp, 0, sizeof(enable_cp));
3269 enable_cp.enable = LE_SCAN_DISABLE;
3270 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3271 sizeof(enable_cp), &enable_cp);
3272 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003273
Andre Guedese0d9727e2012-03-20 15:15:36 -03003274 break;
3275
3276 case DISCOVERY_RESOLVING:
3277 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003278 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003279 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003280 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003281 err = cmd_complete(sk, hdev->id,
3282 MGMT_OP_STOP_DISCOVERY, 0,
3283 &mgmt_cp->type,
3284 sizeof(mgmt_cp->type));
3285 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3286 goto unlock;
3287 }
3288
3289 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003290 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3291 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003292
3293 break;
3294
3295 default:
3296 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003297
3298 mgmt_pending_remove(cmd);
3299 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3300 MGMT_STATUS_FAILED, &mgmt_cp->type,
3301 sizeof(mgmt_cp->type));
3302 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003303 }
3304
Andre Guedes0e05bba2013-04-30 15:29:33 -03003305 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003306 if (err < 0)
3307 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003308 else
3309 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003310
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003311unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003312 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003313 return err;
3314}
3315
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003316static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003317 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003318{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003319 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003320 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003321 int err;
3322
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003323 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003324
Johan Hedberg561aafb2012-01-04 13:31:59 +02003325 hci_dev_lock(hdev);
3326
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003327 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003328 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003329 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003330 goto failed;
3331 }
3332
Johan Hedberga198e7b2012-02-17 14:27:06 +02003333 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003334 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003335 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003336 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003337 goto failed;
3338 }
3339
3340 if (cp->name_known) {
3341 e->name_state = NAME_KNOWN;
3342 list_del(&e->list);
3343 } else {
3344 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003345 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003346 }
3347
Johan Hedberge3846622013-01-09 15:29:33 +02003348 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3349 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003350
3351failed:
3352 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003353 return err;
3354}
3355
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003356static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003357 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003358{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003359 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003360 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003361 int err;
3362
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003363 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003364
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003365 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003366 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3367 MGMT_STATUS_INVALID_PARAMS,
3368 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003369
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003370 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003371
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003372 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003373 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003374 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003375 else
Szymon Janca6785be2012-12-13 15:11:21 +01003376 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003377
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003378 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003379 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003380
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003381 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003382
3383 return err;
3384}
3385
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003386static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003387 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003388{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003389 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003390 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003391 int err;
3392
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003393 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003394
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003395 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003396 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3397 MGMT_STATUS_INVALID_PARAMS,
3398 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003399
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003400 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003401
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003402 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003403 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003404 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003405 else
Szymon Janca6785be2012-12-13 15:11:21 +01003406 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003407
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003408 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003409 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003410
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003411 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003412
3413 return err;
3414}
3415
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003416static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3417 u16 len)
3418{
3419 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003420 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003421 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003422 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003423
3424 BT_DBG("%s", hdev->name);
3425
Szymon Jancc72d4b82012-03-16 16:02:57 +01003426 source = __le16_to_cpu(cp->source);
3427
3428 if (source > 0x0002)
3429 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3430 MGMT_STATUS_INVALID_PARAMS);
3431
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003432 hci_dev_lock(hdev);
3433
Szymon Jancc72d4b82012-03-16 16:02:57 +01003434 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003435 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3436 hdev->devid_product = __le16_to_cpu(cp->product);
3437 hdev->devid_version = __le16_to_cpu(cp->version);
3438
3439 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3440
Johan Hedberg890ea892013-03-15 17:06:52 -05003441 hci_req_init(&req, hdev);
3442 update_eir(&req);
3443 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003444
3445 hci_dev_unlock(hdev);
3446
3447 return err;
3448}
3449
Johan Hedberg4375f102013-09-25 13:26:10 +03003450static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3451{
3452 struct cmd_lookup match = { NULL, hdev };
3453
3454 if (status) {
3455 u8 mgmt_err = mgmt_status(status);
3456
3457 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3458 cmd_status_rsp, &mgmt_err);
3459 return;
3460 }
3461
3462 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3463 &match);
3464
3465 new_settings(hdev, match.sk);
3466
3467 if (match.sk)
3468 sock_put(match.sk);
3469}
3470
Marcel Holtmann21b51872013-10-10 09:47:53 -07003471static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3472 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003473{
3474 struct mgmt_mode *cp = data;
3475 struct pending_cmd *cmd;
3476 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003477 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003478 int err;
3479
3480 BT_DBG("request for %s", hdev->name);
3481
Johan Hedberge6fe7982013-10-02 15:45:22 +03003482 status = mgmt_le_support(hdev);
3483 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003484 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003485 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003486
3487 if (cp->val != 0x00 && cp->val != 0x01)
3488 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3489 MGMT_STATUS_INVALID_PARAMS);
3490
3491 hci_dev_lock(hdev);
3492
3493 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003494 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003495
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003496 /* The following conditions are ones which mean that we should
3497 * not do any HCI communication but directly send a mgmt
3498 * response to user space (after toggling the flag if
3499 * necessary).
3500 */
3501 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003502 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003503 bool changed = false;
3504
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003505 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3506 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003507 changed = true;
3508 }
3509
3510 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3511 if (err < 0)
3512 goto unlock;
3513
3514 if (changed)
3515 err = new_settings(hdev, sk);
3516
3517 goto unlock;
3518 }
3519
3520 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3521 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3522 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3523 MGMT_STATUS_BUSY);
3524 goto unlock;
3525 }
3526
3527 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3528 if (!cmd) {
3529 err = -ENOMEM;
3530 goto unlock;
3531 }
3532
3533 hci_req_init(&req, hdev);
3534
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003535 if (val)
3536 enable_advertising(&req);
3537 else
3538 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003539
3540 err = hci_req_run(&req, set_advertising_complete);
3541 if (err < 0)
3542 mgmt_pending_remove(cmd);
3543
3544unlock:
3545 hci_dev_unlock(hdev);
3546 return err;
3547}
3548
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003549static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3550 void *data, u16 len)
3551{
3552 struct mgmt_cp_set_static_address *cp = data;
3553 int err;
3554
3555 BT_DBG("%s", hdev->name);
3556
Marcel Holtmann62af4442013-10-02 22:10:32 -07003557 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003558 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003559 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003560
3561 if (hdev_is_powered(hdev))
3562 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3563 MGMT_STATUS_REJECTED);
3564
3565 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3566 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3567 return cmd_status(sk, hdev->id,
3568 MGMT_OP_SET_STATIC_ADDRESS,
3569 MGMT_STATUS_INVALID_PARAMS);
3570
3571 /* Two most significant bits shall be set */
3572 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3573 return cmd_status(sk, hdev->id,
3574 MGMT_OP_SET_STATIC_ADDRESS,
3575 MGMT_STATUS_INVALID_PARAMS);
3576 }
3577
3578 hci_dev_lock(hdev);
3579
3580 bacpy(&hdev->static_addr, &cp->bdaddr);
3581
3582 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3583
3584 hci_dev_unlock(hdev);
3585
3586 return err;
3587}
3588
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003589static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3590 void *data, u16 len)
3591{
3592 struct mgmt_cp_set_scan_params *cp = data;
3593 __u16 interval, window;
3594 int err;
3595
3596 BT_DBG("%s", hdev->name);
3597
3598 if (!lmp_le_capable(hdev))
3599 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3600 MGMT_STATUS_NOT_SUPPORTED);
3601
3602 interval = __le16_to_cpu(cp->interval);
3603
3604 if (interval < 0x0004 || interval > 0x4000)
3605 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3606 MGMT_STATUS_INVALID_PARAMS);
3607
3608 window = __le16_to_cpu(cp->window);
3609
3610 if (window < 0x0004 || window > 0x4000)
3611 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3612 MGMT_STATUS_INVALID_PARAMS);
3613
Marcel Holtmann899e1072013-10-14 09:55:32 -07003614 if (window > interval)
3615 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3616 MGMT_STATUS_INVALID_PARAMS);
3617
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003618 hci_dev_lock(hdev);
3619
3620 hdev->le_scan_interval = interval;
3621 hdev->le_scan_window = window;
3622
3623 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3624
3625 hci_dev_unlock(hdev);
3626
3627 return err;
3628}
3629
Johan Hedberg33e38b32013-03-15 17:07:05 -05003630static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3631{
3632 struct pending_cmd *cmd;
3633
3634 BT_DBG("status 0x%02x", status);
3635
3636 hci_dev_lock(hdev);
3637
3638 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3639 if (!cmd)
3640 goto unlock;
3641
3642 if (status) {
3643 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3644 mgmt_status(status));
3645 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003646 struct mgmt_mode *cp = cmd->param;
3647
3648 if (cp->val)
3649 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3650 else
3651 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3652
Johan Hedberg33e38b32013-03-15 17:07:05 -05003653 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3654 new_settings(hdev, cmd->sk);
3655 }
3656
3657 mgmt_pending_remove(cmd);
3658
3659unlock:
3660 hci_dev_unlock(hdev);
3661}
3662
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003663static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003664 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003665{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003666 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003667 struct pending_cmd *cmd;
3668 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003669 int err;
3670
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003671 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003672
Johan Hedberg56f87902013-10-02 13:43:13 +03003673 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3674 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003675 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3676 MGMT_STATUS_NOT_SUPPORTED);
3677
Johan Hedberga7e80f22013-01-09 16:05:19 +02003678 if (cp->val != 0x00 && cp->val != 0x01)
3679 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3680 MGMT_STATUS_INVALID_PARAMS);
3681
Johan Hedberg5400c042012-02-21 16:40:33 +02003682 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003683 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003684 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003685
3686 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003687 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003688 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003689
3690 hci_dev_lock(hdev);
3691
Johan Hedberg05cbf292013-03-15 17:07:07 -05003692 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3693 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3694 MGMT_STATUS_BUSY);
3695 goto unlock;
3696 }
3697
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003698 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3699 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3700 hdev);
3701 goto unlock;
3702 }
3703
Johan Hedberg33e38b32013-03-15 17:07:05 -05003704 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3705 data, len);
3706 if (!cmd) {
3707 err = -ENOMEM;
3708 goto unlock;
3709 }
3710
3711 hci_req_init(&req, hdev);
3712
Johan Hedberg406d7802013-03-15 17:07:09 -05003713 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003714
3715 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003716 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003717 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003718 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003719 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003720 }
3721
Johan Hedberg33e38b32013-03-15 17:07:05 -05003722unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003723 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003724
Antti Julkuf6422ec2011-06-22 13:11:56 +03003725 return err;
3726}
3727
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003728static void set_bredr_scan(struct hci_request *req)
3729{
3730 struct hci_dev *hdev = req->hdev;
3731 u8 scan = 0;
3732
3733 /* Ensure that fast connectable is disabled. This function will
3734 * not do anything if the page scan parameters are already what
3735 * they should be.
3736 */
3737 write_fast_connectable(req, false);
3738
3739 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3740 scan |= SCAN_PAGE;
3741 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3742 scan |= SCAN_INQUIRY;
3743
3744 if (scan)
3745 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3746}
3747
Johan Hedberg0663ca22013-10-02 13:43:14 +03003748static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3749{
3750 struct pending_cmd *cmd;
3751
3752 BT_DBG("status 0x%02x", status);
3753
3754 hci_dev_lock(hdev);
3755
3756 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3757 if (!cmd)
3758 goto unlock;
3759
3760 if (status) {
3761 u8 mgmt_err = mgmt_status(status);
3762
3763 /* We need to restore the flag if related HCI commands
3764 * failed.
3765 */
3766 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3767
3768 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3769 } else {
3770 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3771 new_settings(hdev, cmd->sk);
3772 }
3773
3774 mgmt_pending_remove(cmd);
3775
3776unlock:
3777 hci_dev_unlock(hdev);
3778}
3779
3780static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3781{
3782 struct mgmt_mode *cp = data;
3783 struct pending_cmd *cmd;
3784 struct hci_request req;
3785 int err;
3786
3787 BT_DBG("request for %s", hdev->name);
3788
3789 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3790 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3791 MGMT_STATUS_NOT_SUPPORTED);
3792
3793 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3794 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3795 MGMT_STATUS_REJECTED);
3796
3797 if (cp->val != 0x00 && cp->val != 0x01)
3798 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3799 MGMT_STATUS_INVALID_PARAMS);
3800
3801 hci_dev_lock(hdev);
3802
3803 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3804 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3805 goto unlock;
3806 }
3807
3808 if (!hdev_is_powered(hdev)) {
3809 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003810 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3811 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3812 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3813 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3814 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3815 }
3816
3817 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3818
3819 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3820 if (err < 0)
3821 goto unlock;
3822
3823 err = new_settings(hdev, sk);
3824 goto unlock;
3825 }
3826
3827 /* Reject disabling when powered on */
3828 if (!cp->val) {
3829 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3830 MGMT_STATUS_REJECTED);
3831 goto unlock;
3832 }
3833
3834 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3835 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3836 MGMT_STATUS_BUSY);
3837 goto unlock;
3838 }
3839
3840 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3841 if (!cmd) {
3842 err = -ENOMEM;
3843 goto unlock;
3844 }
3845
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07003846 /* We need to flip the bit already here so that update_ad
Johan Hedberg0663ca22013-10-02 13:43:14 +03003847 * generates the correct flags.
3848 */
3849 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3850
3851 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003852
3853 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3854 set_bredr_scan(&req);
3855
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07003856 update_ad(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003857
Johan Hedberg0663ca22013-10-02 13:43:14 +03003858 err = hci_req_run(&req, set_bredr_complete);
3859 if (err < 0)
3860 mgmt_pending_remove(cmd);
3861
3862unlock:
3863 hci_dev_unlock(hdev);
3864 return err;
3865}
3866
Johan Hedberg3f706b72013-01-20 14:27:16 +02003867static bool ltk_is_valid(struct mgmt_ltk_info *key)
3868{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003869 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3870 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003871 if (key->master != 0x00 && key->master != 0x01)
3872 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003873 if (!bdaddr_type_is_le(key->addr.type))
3874 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003875 return true;
3876}
3877
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003878static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003879 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003880{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003881 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3882 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003883 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003884
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003885 BT_DBG("request for %s", hdev->name);
3886
3887 if (!lmp_le_capable(hdev))
3888 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3889 MGMT_STATUS_NOT_SUPPORTED);
3890
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003891 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003892
3893 expected_len = sizeof(*cp) + key_count *
3894 sizeof(struct mgmt_ltk_info);
3895 if (expected_len != len) {
3896 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003897 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003898 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003899 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003900 }
3901
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003902 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003903
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003904 for (i = 0; i < key_count; i++) {
3905 struct mgmt_ltk_info *key = &cp->keys[i];
3906
Johan Hedberg3f706b72013-01-20 14:27:16 +02003907 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003908 return cmd_status(sk, hdev->id,
3909 MGMT_OP_LOAD_LONG_TERM_KEYS,
3910 MGMT_STATUS_INVALID_PARAMS);
3911 }
3912
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003913 hci_dev_lock(hdev);
3914
3915 hci_smp_ltks_clear(hdev);
3916
3917 for (i = 0; i < key_count; i++) {
3918 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003919 u8 type, addr_type;
3920
3921 if (key->addr.type == BDADDR_LE_PUBLIC)
3922 addr_type = ADDR_LE_DEV_PUBLIC;
3923 else
3924 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003925
3926 if (key->master)
3927 type = HCI_SMP_LTK;
3928 else
3929 type = HCI_SMP_LTK_SLAVE;
3930
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003931 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003932 type, 0, key->authenticated, key->val,
3933 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003934 }
3935
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003936 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3937 NULL, 0);
3938
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003939 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003940
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003941 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003942}
3943
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003944static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003945 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3946 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003947 bool var_len;
3948 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003949} mgmt_handlers[] = {
3950 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003951 { read_version, false, MGMT_READ_VERSION_SIZE },
3952 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3953 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3954 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3955 { set_powered, false, MGMT_SETTING_SIZE },
3956 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3957 { set_connectable, false, MGMT_SETTING_SIZE },
3958 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3959 { set_pairable, false, MGMT_SETTING_SIZE },
3960 { set_link_security, false, MGMT_SETTING_SIZE },
3961 { set_ssp, false, MGMT_SETTING_SIZE },
3962 { set_hs, false, MGMT_SETTING_SIZE },
3963 { set_le, false, MGMT_SETTING_SIZE },
3964 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3965 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3966 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3967 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3968 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3969 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3970 { disconnect, false, MGMT_DISCONNECT_SIZE },
3971 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3972 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3973 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3974 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3975 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3976 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3977 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3978 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3979 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3980 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3981 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3982 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3983 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3984 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3985 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3986 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3987 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3988 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3989 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003990 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003991 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003992 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003993 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003994 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003995};
3996
3997
Johan Hedberg03811012010-12-08 00:21:06 +02003998int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3999{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004000 void *buf;
4001 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004002 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004003 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004004 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004005 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004006 int err;
4007
4008 BT_DBG("got %zu bytes", msglen);
4009
4010 if (msglen < sizeof(*hdr))
4011 return -EINVAL;
4012
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004013 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004014 if (!buf)
4015 return -ENOMEM;
4016
4017 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4018 err = -EFAULT;
4019 goto done;
4020 }
4021
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004022 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004023 opcode = __le16_to_cpu(hdr->opcode);
4024 index = __le16_to_cpu(hdr->index);
4025 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004026
4027 if (len != msglen - sizeof(*hdr)) {
4028 err = -EINVAL;
4029 goto done;
4030 }
4031
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004032 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004033 hdev = hci_dev_get(index);
4034 if (!hdev) {
4035 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004036 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004037 goto done;
4038 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004039
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004040 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4041 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004042 err = cmd_status(sk, index, opcode,
4043 MGMT_STATUS_INVALID_INDEX);
4044 goto done;
4045 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004046 }
4047
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004048 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004049 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004050 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004051 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004052 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004053 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004054 }
4055
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004056 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004057 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004058 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004059 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004060 goto done;
4061 }
4062
Johan Hedbergbe22b542012-03-01 22:24:41 +02004063 handler = &mgmt_handlers[opcode];
4064
4065 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004066 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004067 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004068 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004069 goto done;
4070 }
4071
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004072 if (hdev)
4073 mgmt_init_hdev(sk, hdev);
4074
4075 cp = buf + sizeof(*hdr);
4076
Johan Hedbergbe22b542012-03-01 22:24:41 +02004077 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004078 if (err < 0)
4079 goto done;
4080
Johan Hedberg03811012010-12-08 00:21:06 +02004081 err = msglen;
4082
4083done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004084 if (hdev)
4085 hci_dev_put(hdev);
4086
Johan Hedberg03811012010-12-08 00:21:06 +02004087 kfree(buf);
4088 return err;
4089}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004090
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004091void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004092{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004093 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004094 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004095
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004096 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004097}
4098
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004099void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004100{
Johan Hedberg5f159032012-03-02 03:13:19 +02004101 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004102
Marcel Holtmann1514b892013-10-06 08:25:01 -07004103 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004104 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004105
Johan Hedberg744cf192011-11-08 20:40:14 +02004106 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004107
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004108 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004109}
4110
Johan Hedberg229ab392013-03-15 17:06:53 -05004111static void powered_complete(struct hci_dev *hdev, u8 status)
4112{
4113 struct cmd_lookup match = { NULL, hdev };
4114
4115 BT_DBG("status 0x%02x", status);
4116
4117 hci_dev_lock(hdev);
4118
4119 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4120
4121 new_settings(hdev, match.sk);
4122
4123 hci_dev_unlock(hdev);
4124
4125 if (match.sk)
4126 sock_put(match.sk);
4127}
4128
Johan Hedberg70da6242013-03-15 17:06:51 -05004129static int powered_update_hci(struct hci_dev *hdev)
4130{
Johan Hedberg890ea892013-03-15 17:06:52 -05004131 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004132 u8 link_sec;
4133
Johan Hedberg890ea892013-03-15 17:06:52 -05004134 hci_req_init(&req, hdev);
4135
Johan Hedberg70da6242013-03-15 17:06:51 -05004136 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4137 !lmp_host_ssp_capable(hdev)) {
4138 u8 ssp = 1;
4139
Johan Hedberg890ea892013-03-15 17:06:52 -05004140 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004141 }
4142
Johan Hedbergc73eee92013-04-19 18:35:21 +03004143 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4144 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004145 struct hci_cp_write_le_host_supported cp;
4146
4147 cp.le = 1;
4148 cp.simul = lmp_le_br_capable(hdev);
4149
4150 /* Check first if we already have the right
4151 * host state (host features set)
4152 */
4153 if (cp.le != lmp_host_le_capable(hdev) ||
4154 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004155 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4156 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004157 }
4158
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004159 if (lmp_le_capable(hdev)) {
4160 /* Set random address to static address if configured */
4161 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4162 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4163 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004164
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004165 /* Make sure the controller has a good default for
4166 * advertising data. This also applies to the case
4167 * where BR/EDR was toggled during the AUTO_OFF phase.
4168 */
4169 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4170 update_ad(&req);
4171
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004172 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4173 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004174 }
4175
Johan Hedberg70da6242013-03-15 17:06:51 -05004176 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4177 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004178 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4179 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004180
4181 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004182 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4183 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004184 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004185 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004186 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004187 }
4188
Johan Hedberg229ab392013-03-15 17:06:53 -05004189 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004190}
4191
Johan Hedberg744cf192011-11-08 20:40:14 +02004192int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004193{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004194 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004195 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4196 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004197 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004198
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004199 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4200 return 0;
4201
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004202 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004203 if (powered_update_hci(hdev) == 0)
4204 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004205
Johan Hedberg229ab392013-03-15 17:06:53 -05004206 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4207 &match);
4208 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004209 }
4210
Johan Hedberg229ab392013-03-15 17:06:53 -05004211 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4212 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4213
4214 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4215 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4216 zero_cod, sizeof(zero_cod), NULL);
4217
4218new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004219 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004220
4221 if (match.sk)
4222 sock_put(match.sk);
4223
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004224 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004225}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004226
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004227void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004228{
4229 struct pending_cmd *cmd;
4230 u8 status;
4231
4232 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4233 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004234 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004235
4236 if (err == -ERFKILL)
4237 status = MGMT_STATUS_RFKILLED;
4238 else
4239 status = MGMT_STATUS_FAILED;
4240
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004241 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004242
4243 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004244}
4245
Marcel Holtmann86a75642013-10-15 06:33:54 -07004246void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004247{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004248 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004249
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004250 /* Nothing needed here if there's a pending command since that
4251 * commands request completion callback takes care of everything
4252 * necessary.
4253 */
4254 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004255 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004256
Marcel Holtmann86a75642013-10-15 06:33:54 -07004257 if (discoverable)
4258 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4259 else
4260 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004261
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004262 if (changed)
Marcel Holtmann86a75642013-10-15 06:33:54 -07004263 new_settings(hdev, NULL);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004264}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004265
Marcel Holtmanna3309162013-10-15 06:33:55 -07004266void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004267{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004268 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004269
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004270 /* Nothing needed here if there's a pending command since that
4271 * commands request completion callback takes care of everything
4272 * necessary.
4273 */
4274 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004275 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004276
Marcel Holtmanna3309162013-10-15 06:33:55 -07004277 if (connectable)
4278 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4279 else
4280 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004281
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004282 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004283 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004284}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004285
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004286void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004287{
Johan Hedbergca69b792011-11-11 18:10:00 +02004288 u8 mgmt_err = mgmt_status(status);
4289
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004290 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004291 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004292 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004293
4294 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004295 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004296 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004297}
4298
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004299int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4300 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004301{
Johan Hedberg86742e12011-11-07 23:13:38 +02004302 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004303
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004304 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004305
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004306 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004307 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004308 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004309 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004310 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004311 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004312
Johan Hedberg744cf192011-11-08 20:40:14 +02004313 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004314}
Johan Hedbergf7520542011-01-20 12:34:39 +02004315
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004316int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4317{
4318 struct mgmt_ev_new_long_term_key ev;
4319
4320 memset(&ev, 0, sizeof(ev));
4321
4322 ev.store_hint = persistent;
4323 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004324 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004325 ev.key.authenticated = key->authenticated;
4326 ev.key.enc_size = key->enc_size;
4327 ev.key.ediv = key->ediv;
4328
4329 if (key->type == HCI_SMP_LTK)
4330 ev.key.master = 1;
4331
4332 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4333 memcpy(ev.key.val, key->val, sizeof(key->val));
4334
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004335 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4336 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004337}
4338
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004339void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4340 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4341 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004342{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004343 char buf[512];
4344 struct mgmt_ev_device_connected *ev = (void *) buf;
4345 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004346
Johan Hedbergb644ba32012-01-17 21:48:47 +02004347 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004348 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004349
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004350 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004351
Johan Hedbergb644ba32012-01-17 21:48:47 +02004352 if (name_len > 0)
4353 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004354 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004355
4356 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004357 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004358 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004359
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004360 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004361
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004362 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4363 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004364}
4365
Johan Hedberg8962ee72011-01-20 12:40:27 +02004366static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4367{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004368 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004369 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004370 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004371
Johan Hedberg88c3df12012-02-09 14:27:38 +02004372 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4373 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004374
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004375 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004376 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004377
4378 *sk = cmd->sk;
4379 sock_hold(*sk);
4380
Johan Hedberga664b5b2011-02-19 12:06:02 -03004381 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004382}
4383
Johan Hedberg124f6e32012-02-09 13:50:12 +02004384static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004385{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004386 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004387 struct mgmt_cp_unpair_device *cp = cmd->param;
4388 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004389
4390 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004391 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4392 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004393
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004394 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4395
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004396 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004397
4398 mgmt_pending_remove(cmd);
4399}
4400
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004401void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4402 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004403{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004404 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004405 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004406
Johan Hedberg744cf192011-11-08 20:40:14 +02004407 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004408
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004409 bacpy(&ev.addr.bdaddr, bdaddr);
4410 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4411 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004412
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004413 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004414
4415 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004416 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004417
Johan Hedberg124f6e32012-02-09 13:50:12 +02004418 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004419 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004420}
4421
Marcel Holtmann78929242013-10-06 23:55:47 -07004422void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4423 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004424{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004425 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004426 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004427
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004428 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4429 hdev);
4430
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004431 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004432 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004433 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004434
Johan Hedberg88c3df12012-02-09 14:27:38 +02004435 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004436 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004437
Marcel Holtmann78929242013-10-06 23:55:47 -07004438 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4439 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004440
Johan Hedberga664b5b2011-02-19 12:06:02 -03004441 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004442}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004443
Marcel Holtmann445608d2013-10-06 23:55:48 -07004444void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4445 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004446{
4447 struct mgmt_ev_connect_failed ev;
4448
Johan Hedberg4c659c32011-11-07 23:13:39 +02004449 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004450 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004451 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004452
Marcel Holtmann445608d2013-10-06 23:55:48 -07004453 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004454}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004455
Johan Hedberg744cf192011-11-08 20:40:14 +02004456int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004457{
4458 struct mgmt_ev_pin_code_request ev;
4459
Johan Hedbergd8457692012-02-17 14:24:57 +02004460 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004461 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004462 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004463
Johan Hedberg744cf192011-11-08 20:40:14 +02004464 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004465 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004466}
4467
Johan Hedberg744cf192011-11-08 20:40:14 +02004468int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004469 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004470{
4471 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004472 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004473 int err;
4474
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004475 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004476 if (!cmd)
4477 return -ENOENT;
4478
Johan Hedbergd8457692012-02-17 14:24:57 +02004479 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004480 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004481
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004482 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004483 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004484
Johan Hedberga664b5b2011-02-19 12:06:02 -03004485 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004486
4487 return err;
4488}
4489
Johan Hedberg744cf192011-11-08 20:40:14 +02004490int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004491 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004492{
4493 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004494 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004495 int err;
4496
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004497 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004498 if (!cmd)
4499 return -ENOENT;
4500
Johan Hedbergd8457692012-02-17 14:24:57 +02004501 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004502 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004503
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004504 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004505 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004506
Johan Hedberga664b5b2011-02-19 12:06:02 -03004507 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004508
4509 return err;
4510}
Johan Hedberga5c29682011-02-19 12:05:57 -03004511
Johan Hedberg744cf192011-11-08 20:40:14 +02004512int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004513 u8 link_type, u8 addr_type, __le32 value,
4514 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004515{
4516 struct mgmt_ev_user_confirm_request ev;
4517
Johan Hedberg744cf192011-11-08 20:40:14 +02004518 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004519
Johan Hedberg272d90d2012-02-09 15:26:12 +02004520 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004521 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004522 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02004523 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004524
Johan Hedberg744cf192011-11-08 20:40:14 +02004525 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004526 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004527}
4528
Johan Hedberg272d90d2012-02-09 15:26:12 +02004529int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004530 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004531{
4532 struct mgmt_ev_user_passkey_request ev;
4533
4534 BT_DBG("%s", hdev->name);
4535
Johan Hedberg272d90d2012-02-09 15:26:12 +02004536 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004537 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004538
4539 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004540 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004541}
4542
Brian Gix0df4c182011-11-16 13:53:13 -08004543static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004544 u8 link_type, u8 addr_type, u8 status,
4545 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004546{
4547 struct pending_cmd *cmd;
4548 struct mgmt_rp_user_confirm_reply rp;
4549 int err;
4550
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004551 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004552 if (!cmd)
4553 return -ENOENT;
4554
Johan Hedberg272d90d2012-02-09 15:26:12 +02004555 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004556 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004557 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004558 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004559
Johan Hedberga664b5b2011-02-19 12:06:02 -03004560 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004561
4562 return err;
4563}
4564
Johan Hedberg744cf192011-11-08 20:40:14 +02004565int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004566 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004567{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004568 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004569 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004570}
4571
Johan Hedberg272d90d2012-02-09 15:26:12 +02004572int mgmt_user_confirm_neg_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)
Johan Hedberga5c29682011-02-19 12:05:57 -03004574{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004575 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004576 status,
4577 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004578}
Johan Hedberg2a611692011-02-19 12:06:00 -03004579
Brian Gix604086b2011-11-23 08:28:33 -08004580int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004581 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004582{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004583 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004584 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004585}
4586
Johan Hedberg272d90d2012-02-09 15:26:12 +02004587int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004588 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004589{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004590 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004591 status,
4592 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004593}
4594
Johan Hedberg92a25252012-09-06 18:39:26 +03004595int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4596 u8 link_type, u8 addr_type, u32 passkey,
4597 u8 entered)
4598{
4599 struct mgmt_ev_passkey_notify ev;
4600
4601 BT_DBG("%s", hdev->name);
4602
4603 bacpy(&ev.addr.bdaddr, bdaddr);
4604 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4605 ev.passkey = __cpu_to_le32(passkey);
4606 ev.entered = entered;
4607
4608 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4609}
4610
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004611int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004612 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004613{
4614 struct mgmt_ev_auth_failed ev;
4615
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004616 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004617 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004618 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004619
Johan Hedberg744cf192011-11-08 20:40:14 +02004620 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004621}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004622
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004623int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4624{
4625 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004626 bool changed = false;
4627 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004628
4629 if (status) {
4630 u8 mgmt_err = mgmt_status(status);
4631 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004632 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004633 return 0;
4634 }
4635
Johan Hedberg47990ea2012-02-22 11:58:37 +02004636 if (test_bit(HCI_AUTH, &hdev->flags)) {
4637 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4638 changed = true;
4639 } else {
4640 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4641 changed = true;
4642 }
4643
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004644 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004645 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004646
Johan Hedberg47990ea2012-02-22 11:58:37 +02004647 if (changed)
4648 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004649
4650 if (match.sk)
4651 sock_put(match.sk);
4652
4653 return err;
4654}
4655
Johan Hedberg890ea892013-03-15 17:06:52 -05004656static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004657{
Johan Hedberg890ea892013-03-15 17:06:52 -05004658 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004659 struct hci_cp_write_eir cp;
4660
Johan Hedberg976eb202012-10-24 21:12:01 +03004661 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004662 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004663
Johan Hedbergc80da272012-02-22 15:38:48 +02004664 memset(hdev->eir, 0, sizeof(hdev->eir));
4665
Johan Hedbergcacaf522012-02-21 00:52:42 +02004666 memset(&cp, 0, sizeof(cp));
4667
Johan Hedberg890ea892013-03-15 17:06:52 -05004668 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004669}
4670
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004671int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004672{
4673 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004674 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004675 bool changed = false;
4676 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004677
4678 if (status) {
4679 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004680
4681 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004682 &hdev->dev_flags)) {
4683 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004684 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004685 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004686
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004687 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4688 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004689
4690 return err;
4691 }
4692
4693 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004694 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004695 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004696 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4697 if (!changed)
4698 changed = test_and_clear_bit(HCI_HS_ENABLED,
4699 &hdev->dev_flags);
4700 else
4701 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004702 }
4703
4704 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4705
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004706 if (changed)
4707 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004708
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004709 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004710 sock_put(match.sk);
4711
Johan Hedberg890ea892013-03-15 17:06:52 -05004712 hci_req_init(&req, hdev);
4713
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004714 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004715 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004716 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004717 clear_eir(&req);
4718
4719 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004720
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004721 return err;
4722}
4723
Johan Hedberg92da6092013-03-15 17:06:55 -05004724static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004725{
4726 struct cmd_lookup *match = data;
4727
Johan Hedberg90e70452012-02-23 23:09:40 +02004728 if (match->sk == NULL) {
4729 match->sk = cmd->sk;
4730 sock_hold(match->sk);
4731 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004732}
4733
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004734int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004735 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004736{
Johan Hedberg90e70452012-02-23 23:09:40 +02004737 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4738 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004739
Johan Hedberg92da6092013-03-15 17:06:55 -05004740 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4741 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4742 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004743
4744 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004745 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4746 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004747
4748 if (match.sk)
4749 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004750
4751 return err;
4752}
4753
Johan Hedberg744cf192011-11-08 20:40:14 +02004754int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004755{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004756 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004757 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004758
Johan Hedberg13928972013-03-15 17:07:00 -05004759 if (status)
4760 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004761
4762 memset(&ev, 0, sizeof(ev));
4763 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004764 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004765
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004766 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004767 if (!cmd) {
4768 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004769
Johan Hedberg13928972013-03-15 17:07:00 -05004770 /* If this is a HCI command related to powering on the
4771 * HCI dev don't send any mgmt signals.
4772 */
4773 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4774 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004775 }
4776
Johan Hedberg13928972013-03-15 17:07:00 -05004777 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4778 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004779}
Szymon Jancc35938b2011-03-22 13:12:21 +01004780
Johan Hedberg744cf192011-11-08 20:40:14 +02004781int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004782 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004783{
4784 struct pending_cmd *cmd;
4785 int err;
4786
Johan Hedberg744cf192011-11-08 20:40:14 +02004787 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004788
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004789 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004790 if (!cmd)
4791 return -ENOENT;
4792
4793 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004794 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4795 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004796 } else {
4797 struct mgmt_rp_read_local_oob_data rp;
4798
4799 memcpy(rp.hash, hash, sizeof(rp.hash));
4800 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4801
Johan Hedberg744cf192011-11-08 20:40:14 +02004802 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004803 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4804 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004805 }
4806
4807 mgmt_pending_remove(cmd);
4808
4809 return err;
4810}
Johan Hedberge17acd42011-03-30 23:57:16 +03004811
Marcel Holtmann901801b2013-10-06 23:55:51 -07004812void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4813 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4814 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004815{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004816 char buf[512];
4817 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004818 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004819
Andre Guedes12602d02013-04-30 15:29:40 -03004820 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004821 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004822
Johan Hedberg1dc06092012-01-15 21:01:23 +02004823 /* Leave 5 bytes for a potential CoD field */
4824 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004825 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004826
Johan Hedberg1dc06092012-01-15 21:01:23 +02004827 memset(buf, 0, sizeof(buf));
4828
Johan Hedberge319d2e2012-01-15 19:51:59 +02004829 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004830 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004831 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004832 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304833 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004834 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304835 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004836
Johan Hedberg1dc06092012-01-15 21:01:23 +02004837 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004838 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004839
Johan Hedberg1dc06092012-01-15 21:01:23 +02004840 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4841 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004842 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004843
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004844 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004845 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004846
Marcel Holtmann901801b2013-10-06 23:55:51 -07004847 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004848}
Johan Hedberga88a9652011-03-30 13:18:12 +03004849
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004850void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4851 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004852{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004853 struct mgmt_ev_device_found *ev;
4854 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4855 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004856
Johan Hedbergb644ba32012-01-17 21:48:47 +02004857 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004858
Johan Hedbergb644ba32012-01-17 21:48:47 +02004859 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004860
Johan Hedbergb644ba32012-01-17 21:48:47 +02004861 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004862 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004863 ev->rssi = rssi;
4864
4865 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004866 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004867
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004868 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004869
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004870 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004871}
Johan Hedberg314b2382011-04-27 10:29:57 -04004872
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004873void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004874{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004875 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004876 struct pending_cmd *cmd;
4877
Andre Guedes343fb142011-11-22 17:14:19 -03004878 BT_DBG("%s discovering %u", hdev->name, discovering);
4879
Johan Hedberg164a6e72011-11-01 17:06:44 +02004880 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004881 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004882 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004883 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004884
4885 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004886 u8 type = hdev->discovery.type;
4887
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004888 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4889 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004890 mgmt_pending_remove(cmd);
4891 }
4892
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004893 memset(&ev, 0, sizeof(ev));
4894 ev.type = hdev->discovery.type;
4895 ev.discovering = discovering;
4896
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004897 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004898}
Antti Julku5e762442011-08-25 16:48:02 +03004899
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004900int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004901{
4902 struct pending_cmd *cmd;
4903 struct mgmt_ev_device_blocked ev;
4904
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004905 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004906
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004907 bacpy(&ev.addr.bdaddr, bdaddr);
4908 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004909
Johan Hedberg744cf192011-11-08 20:40:14 +02004910 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004911 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004912}
4913
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004914int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004915{
4916 struct pending_cmd *cmd;
4917 struct mgmt_ev_device_unblocked ev;
4918
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004919 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004920
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004921 bacpy(&ev.addr.bdaddr, bdaddr);
4922 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004923
Johan Hedberg744cf192011-11-08 20:40:14 +02004924 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004925 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004926}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004927
4928static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4929{
4930 BT_DBG("%s status %u", hdev->name, status);
4931
4932 /* Clear the advertising mgmt setting if we failed to re-enable it */
4933 if (status) {
4934 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004935 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004936 }
4937}
4938
4939void mgmt_reenable_advertising(struct hci_dev *hdev)
4940{
4941 struct hci_request req;
4942
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004943 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004944 return;
4945
4946 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4947 return;
4948
4949 hci_req_init(&req, hdev);
4950 enable_advertising(&req);
4951
4952 /* If this fails we have no option but to let user space know
4953 * that we've disabled advertising.
4954 */
4955 if (hci_req_run(&req, adv_enable_complete) < 0) {
4956 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004957 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004958 }
4959}