blob: 796db5849795fee3a910d372973f667ee799da95 [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
Johan Hedbergeb2a8d22013-10-19 23:38:20 +0300539static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
540{
541 struct pending_cmd *cmd;
542
543 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
544 if (cmd->opcode == opcode)
545 return cmd;
546 }
547
548 return NULL;
549}
550
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700551static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
552{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700553 u8 ad_len = 0;
554 size_t name_len;
555
556 name_len = strlen(hdev->dev_name);
557 if (name_len > 0) {
558 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
559
560 if (name_len > max_len) {
561 name_len = max_len;
562 ptr[1] = EIR_NAME_SHORT;
563 } else
564 ptr[1] = EIR_NAME_COMPLETE;
565
566 ptr[0] = name_len + 1;
567
568 memcpy(ptr + 2, hdev->dev_name, name_len);
569
570 ad_len += (name_len + 2);
571 ptr += (name_len + 2);
572 }
573
574 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700575}
576
577static void update_scan_rsp_data(struct hci_request *req)
578{
579 struct hci_dev *hdev = req->hdev;
580 struct hci_cp_le_set_scan_rsp_data cp;
581 u8 len;
582
Johan Hedberg7751ef12013-10-19 23:38:15 +0300583 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700584 return;
585
586 memset(&cp, 0, sizeof(cp));
587
588 len = create_scan_rsp_data(hdev, cp.data);
589
Johan Hedbergeb438b52013-10-16 15:31:07 +0300590 if (hdev->scan_rsp_data_len == len &&
591 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700592 return;
593
Johan Hedbergeb438b52013-10-16 15:31:07 +0300594 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
595 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700596
597 cp.length = len;
598
599 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
600}
601
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700602static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700603{
604 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700605
606 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
607 flags |= LE_AD_GENERAL;
608
609 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
610 if (lmp_le_br_capable(hdev))
611 flags |= LE_AD_SIM_LE_BREDR_CTRL;
612 if (lmp_host_le_br_capable(hdev))
613 flags |= LE_AD_SIM_LE_BREDR_HOST;
614 } else {
615 flags |= LE_AD_NO_BREDR;
616 }
617
618 if (flags) {
619 BT_DBG("adv flags 0x%02x", flags);
620
621 ptr[0] = 2;
622 ptr[1] = EIR_FLAGS;
623 ptr[2] = flags;
624
625 ad_len += 3;
626 ptr += 3;
627 }
628
629 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
630 ptr[0] = 2;
631 ptr[1] = EIR_TX_POWER;
632 ptr[2] = (u8) hdev->adv_tx_power;
633
634 ad_len += 3;
635 ptr += 3;
636 }
637
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700638 return ad_len;
639}
640
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700641static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700642{
643 struct hci_dev *hdev = req->hdev;
644 struct hci_cp_le_set_adv_data cp;
645 u8 len;
646
Johan Hedberg10994ce2013-10-19 23:38:16 +0300647 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700648 return;
649
650 memset(&cp, 0, sizeof(cp));
651
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700652 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700653
654 if (hdev->adv_data_len == len &&
655 memcmp(cp.data, hdev->adv_data, len) == 0)
656 return;
657
658 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
659 hdev->adv_data_len = len;
660
661 cp.length = len;
662
663 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
664}
665
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300666static void create_eir(struct hci_dev *hdev, u8 *data)
667{
668 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300669 size_t name_len;
670
671 name_len = strlen(hdev->dev_name);
672
673 if (name_len > 0) {
674 /* EIR Data type */
675 if (name_len > 48) {
676 name_len = 48;
677 ptr[1] = EIR_NAME_SHORT;
678 } else
679 ptr[1] = EIR_NAME_COMPLETE;
680
681 /* EIR Data length */
682 ptr[0] = name_len + 1;
683
684 memcpy(ptr + 2, hdev->dev_name, name_len);
685
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300686 ptr += (name_len + 2);
687 }
688
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100689 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700690 ptr[0] = 2;
691 ptr[1] = EIR_TX_POWER;
692 ptr[2] = (u8) hdev->inq_tx_power;
693
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700694 ptr += 3;
695 }
696
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700697 if (hdev->devid_source > 0) {
698 ptr[0] = 9;
699 ptr[1] = EIR_DEVICE_ID;
700
701 put_unaligned_le16(hdev->devid_source, ptr + 2);
702 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
703 put_unaligned_le16(hdev->devid_product, ptr + 6);
704 put_unaligned_le16(hdev->devid_version, ptr + 8);
705
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700706 ptr += 10;
707 }
708
Johan Hedberg213202e2013-01-27 00:31:33 +0200709 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200710 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200711 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300712}
713
Johan Hedberg890ea892013-03-15 17:06:52 -0500714static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300715{
Johan Hedberg890ea892013-03-15 17:06:52 -0500716 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300717 struct hci_cp_write_eir cp;
718
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200719 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500720 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200721
Johan Hedberg976eb202012-10-24 21:12:01 +0300722 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500723 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300724
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200725 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500726 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300727
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200728 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500729 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300730
731 memset(&cp, 0, sizeof(cp));
732
733 create_eir(hdev, cp.data);
734
735 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500736 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300737
738 memcpy(hdev->eir, cp.data, sizeof(cp.data));
739
Johan Hedberg890ea892013-03-15 17:06:52 -0500740 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300741}
742
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200743static u8 get_service_classes(struct hci_dev *hdev)
744{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300745 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200746 u8 val = 0;
747
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300748 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200749 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200750
751 return val;
752}
753
Johan Hedberg890ea892013-03-15 17:06:52 -0500754static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200755{
Johan Hedberg890ea892013-03-15 17:06:52 -0500756 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200757 u8 cod[3];
758
759 BT_DBG("%s", hdev->name);
760
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200761 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500762 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200763
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300764 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
765 return;
766
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200767 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500768 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200769
770 cod[0] = hdev->minor_class;
771 cod[1] = hdev->major_class;
772 cod[2] = get_service_classes(hdev);
773
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700774 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
775 cod[1] |= 0x20;
776
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200777 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500778 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200779
Johan Hedberg890ea892013-03-15 17:06:52 -0500780 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200781}
782
Johan Hedberg7d785252011-12-15 00:47:39 +0200783static void service_cache_off(struct work_struct *work)
784{
785 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300786 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500787 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200788
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200789 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200790 return;
791
Johan Hedberg890ea892013-03-15 17:06:52 -0500792 hci_req_init(&req, hdev);
793
Johan Hedberg7d785252011-12-15 00:47:39 +0200794 hci_dev_lock(hdev);
795
Johan Hedberg890ea892013-03-15 17:06:52 -0500796 update_eir(&req);
797 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200798
799 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500800
801 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200802}
803
Johan Hedberg6a919082012-02-28 06:17:26 +0200804static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200805{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200806 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200807 return;
808
Johan Hedberg4f87da82012-03-02 19:55:56 +0200809 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200810
Johan Hedberg4f87da82012-03-02 19:55:56 +0200811 /* Non-mgmt controlled devices get this bit set
812 * implicitly so that pairing works for them, however
813 * for mgmt we require user-space to explicitly enable
814 * it
815 */
816 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200817}
818
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200819static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300820 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200821{
822 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200823
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200824 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200825
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300826 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200827
Johan Hedberg03811012010-12-08 00:21:06 +0200828 memset(&rp, 0, sizeof(rp));
829
Johan Hedberg03811012010-12-08 00:21:06 +0200830 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200831
832 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200833 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200834
835 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
836 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
837
838 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200839
840 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200841 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200842
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300843 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200844
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200845 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300846 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200847}
848
849static void mgmt_pending_free(struct pending_cmd *cmd)
850{
851 sock_put(cmd->sk);
852 kfree(cmd->param);
853 kfree(cmd);
854}
855
856static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300857 struct hci_dev *hdev, void *data,
858 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200859{
860 struct pending_cmd *cmd;
861
Andre Guedes12b94562012-06-07 19:05:45 -0300862 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200863 if (!cmd)
864 return NULL;
865
866 cmd->opcode = opcode;
867 cmd->index = hdev->id;
868
Andre Guedes12b94562012-06-07 19:05:45 -0300869 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200870 if (!cmd->param) {
871 kfree(cmd);
872 return NULL;
873 }
874
875 if (data)
876 memcpy(cmd->param, data, len);
877
878 cmd->sk = sk;
879 sock_hold(sk);
880
881 list_add(&cmd->list, &hdev->mgmt_pending);
882
883 return cmd;
884}
885
886static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300887 void (*cb)(struct pending_cmd *cmd,
888 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300889 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200890{
Andre Guedesa3d09352013-02-01 11:21:30 -0300891 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200892
Andre Guedesa3d09352013-02-01 11:21:30 -0300893 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200894 if (opcode > 0 && cmd->opcode != opcode)
895 continue;
896
897 cb(cmd, data);
898 }
899}
900
Johan Hedberg03811012010-12-08 00:21:06 +0200901static void mgmt_pending_remove(struct pending_cmd *cmd)
902{
903 list_del(&cmd->list);
904 mgmt_pending_free(cmd);
905}
906
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200907static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200908{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200909 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200910
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200911 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300912 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200913}
914
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200915static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300916 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200917{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300918 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200919 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200920 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200921
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200922 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200923
Johan Hedberga7e80f22013-01-09 16:05:19 +0200924 if (cp->val != 0x00 && cp->val != 0x01)
925 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
926 MGMT_STATUS_INVALID_PARAMS);
927
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300928 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200929
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300930 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
931 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
932 MGMT_STATUS_BUSY);
933 goto failed;
934 }
935
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100936 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
937 cancel_delayed_work(&hdev->power_off);
938
939 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200940 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
941 data, len);
942 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100943 goto failed;
944 }
945 }
946
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200947 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200948 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200949 goto failed;
950 }
951
Johan Hedberg03811012010-12-08 00:21:06 +0200952 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
953 if (!cmd) {
954 err = -ENOMEM;
955 goto failed;
956 }
957
958 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200959 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200960 else
Johan Hedberg19202572013-01-14 22:33:51 +0200961 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200962
963 err = 0;
964
965failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300966 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200967 return err;
968}
969
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300970static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
971 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200972{
973 struct sk_buff *skb;
974 struct mgmt_hdr *hdr;
975
Andre Guedes790eff42012-06-07 19:05:46 -0300976 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200977 if (!skb)
978 return -ENOMEM;
979
980 hdr = (void *) skb_put(skb, sizeof(*hdr));
981 hdr->opcode = cpu_to_le16(event);
982 if (hdev)
983 hdr->index = cpu_to_le16(hdev->id);
984 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530985 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200986 hdr->len = cpu_to_le16(data_len);
987
988 if (data)
989 memcpy(skb_put(skb, data_len), data, data_len);
990
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100991 /* Time stamp */
992 __net_timestamp(skb);
993
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200994 hci_send_to_control(skb, skip_sk);
995 kfree_skb(skb);
996
997 return 0;
998}
999
1000static int new_settings(struct hci_dev *hdev, struct sock *skip)
1001{
1002 __le32 ev;
1003
1004 ev = cpu_to_le32(get_current_settings(hdev));
1005
1006 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1007}
1008
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001009struct cmd_lookup {
1010 struct sock *sk;
1011 struct hci_dev *hdev;
1012 u8 mgmt_status;
1013};
1014
1015static void settings_rsp(struct pending_cmd *cmd, void *data)
1016{
1017 struct cmd_lookup *match = data;
1018
1019 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1020
1021 list_del(&cmd->list);
1022
1023 if (match->sk == NULL) {
1024 match->sk = cmd->sk;
1025 sock_hold(match->sk);
1026 }
1027
1028 mgmt_pending_free(cmd);
1029}
1030
1031static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1032{
1033 u8 *status = data;
1034
1035 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1036 mgmt_pending_remove(cmd);
1037}
1038
Johan Hedberge6fe7982013-10-02 15:45:22 +03001039static u8 mgmt_bredr_support(struct hci_dev *hdev)
1040{
1041 if (!lmp_bredr_capable(hdev))
1042 return MGMT_STATUS_NOT_SUPPORTED;
1043 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1044 return MGMT_STATUS_REJECTED;
1045 else
1046 return MGMT_STATUS_SUCCESS;
1047}
1048
1049static u8 mgmt_le_support(struct hci_dev *hdev)
1050{
1051 if (!lmp_le_capable(hdev))
1052 return MGMT_STATUS_NOT_SUPPORTED;
1053 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1054 return MGMT_STATUS_REJECTED;
1055 else
1056 return MGMT_STATUS_SUCCESS;
1057}
1058
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001059static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1060{
1061 struct pending_cmd *cmd;
1062 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001063 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001064 bool changed;
1065
1066 BT_DBG("status 0x%02x", status);
1067
1068 hci_dev_lock(hdev);
1069
1070 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1071 if (!cmd)
1072 goto unlock;
1073
1074 if (status) {
1075 u8 mgmt_err = mgmt_status(status);
1076 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001077 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001078 goto remove_cmd;
1079 }
1080
1081 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001082 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001083 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1084 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001085
1086 if (hdev->discov_timeout > 0) {
1087 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1088 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1089 to);
1090 }
1091 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001092 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1093 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001094 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001095
1096 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1097
1098 if (changed)
1099 new_settings(hdev, cmd->sk);
1100
Marcel Holtmann970ba522013-10-15 06:33:57 -07001101 /* When the discoverable mode gets changed, make sure
1102 * that class of device has the limited discoverable
1103 * bit correctly set.
1104 */
1105 hci_req_init(&req, hdev);
1106 update_class(&req);
1107 hci_req_run(&req, NULL);
1108
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001109remove_cmd:
1110 mgmt_pending_remove(cmd);
1111
1112unlock:
1113 hci_dev_unlock(hdev);
1114}
1115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001116static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001117 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001118{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001119 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001120 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001121 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001122 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001123 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001124 int err;
1125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001126 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001127
Johan Hedberge6fe7982013-10-02 15:45:22 +03001128 status = mgmt_bredr_support(hdev);
1129 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001130 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001131 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001132
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001133 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001134 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1135 MGMT_STATUS_INVALID_PARAMS);
1136
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001137 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001138
1139 /* Disabling discoverable requires that no timeout is set,
1140 * and enabling limited discoverable requires a timeout.
1141 */
1142 if ((cp->val == 0x00 && timeout > 0) ||
1143 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001144 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001145 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001146
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001147 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001148
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001149 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001150 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001151 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001152 goto failed;
1153 }
1154
1155 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001156 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001157 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001158 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001159 goto failed;
1160 }
1161
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001162 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001163 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001164 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001165 goto failed;
1166 }
1167
1168 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001169 bool changed = false;
1170
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001171 /* Setting limited discoverable when powered off is
1172 * not a valid operation since it requires a timeout
1173 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1174 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001175 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1176 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1177 changed = true;
1178 }
1179
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001180 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001181 if (err < 0)
1182 goto failed;
1183
1184 if (changed)
1185 err = new_settings(hdev, sk);
1186
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001187 goto failed;
1188 }
1189
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001190 /* If the current mode is the same, then just update the timeout
1191 * value with the new value. And if only the timeout gets updated,
1192 * then no need for any HCI transactions.
1193 */
1194 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1195 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1196 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001197 cancel_delayed_work(&hdev->discov_off);
1198 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001199
Marcel Holtmann36261542013-10-15 08:28:51 -07001200 if (cp->val && hdev->discov_timeout > 0) {
1201 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001202 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001203 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001204 }
1205
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001206 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001207 goto failed;
1208 }
1209
1210 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1211 if (!cmd) {
1212 err = -ENOMEM;
1213 goto failed;
1214 }
1215
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001216 /* Cancel any potential discoverable timeout that might be
1217 * still active and store new timeout value. The arming of
1218 * the timeout happens in the complete handler.
1219 */
1220 cancel_delayed_work(&hdev->discov_off);
1221 hdev->discov_timeout = timeout;
1222
Johan Hedbergb456f872013-10-19 23:38:22 +03001223 /* Limited discoverable mode */
1224 if (cp->val == 0x02)
1225 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1226 else
1227 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1228
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001229 hci_req_init(&req, hdev);
1230
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001231 scan = SCAN_PAGE;
1232
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001233 if (cp->val) {
1234 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001235
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001236 if (cp->val == 0x02) {
1237 /* Limited discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001238 hci_cp.num_iac = 2;
1239 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1240 hci_cp.iac_lap[1] = 0x8b;
1241 hci_cp.iac_lap[2] = 0x9e;
1242 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1243 hci_cp.iac_lap[4] = 0x8b;
1244 hci_cp.iac_lap[5] = 0x9e;
1245 } else {
1246 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001247 hci_cp.num_iac = 1;
1248 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1249 hci_cp.iac_lap[1] = 0x8b;
1250 hci_cp.iac_lap[2] = 0x9e;
1251 }
1252
1253 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1254 (hci_cp.num_iac * 3) + 1, &hci_cp);
1255
1256 scan |= SCAN_INQUIRY;
1257 } else {
1258 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1259 }
1260
1261 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001262
1263 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001264 if (err < 0)
1265 mgmt_pending_remove(cmd);
1266
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001267failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001268 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001269 return err;
1270}
1271
Johan Hedberg406d7802013-03-15 17:07:09 -05001272static void write_fast_connectable(struct hci_request *req, bool enable)
1273{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001274 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001275 struct hci_cp_write_page_scan_activity acp;
1276 u8 type;
1277
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001278 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1279 return;
1280
Johan Hedberg406d7802013-03-15 17:07:09 -05001281 if (enable) {
1282 type = PAGE_SCAN_TYPE_INTERLACED;
1283
1284 /* 160 msec page scan interval */
1285 acp.interval = __constant_cpu_to_le16(0x0100);
1286 } else {
1287 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1288
1289 /* default 1.28 sec page scan */
1290 acp.interval = __constant_cpu_to_le16(0x0800);
1291 }
1292
1293 acp.window = __constant_cpu_to_le16(0x0012);
1294
Johan Hedbergbd98b992013-03-15 17:07:13 -05001295 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1296 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1297 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1298 sizeof(acp), &acp);
1299
1300 if (hdev->page_scan_type != type)
1301 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001302}
1303
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001304static u8 get_adv_type(struct hci_dev *hdev)
1305{
1306 struct pending_cmd *cmd;
1307 bool connectable;
1308
1309 /* If there's a pending mgmt command the flag will not yet have
1310 * it's final value, so check for this first.
1311 */
1312 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1313 if (cmd) {
1314 struct mgmt_mode *cp = cmd->param;
1315 connectable = !!cp->val;
1316 } else {
1317 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1318 }
1319
1320 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1321}
1322
Johan Hedberg95c66e72013-10-14 16:20:06 +03001323static void enable_advertising(struct hci_request *req)
1324{
1325 struct hci_dev *hdev = req->hdev;
1326 struct hci_cp_le_set_adv_param cp;
1327 u8 enable = 0x01;
1328
1329 memset(&cp, 0, sizeof(cp));
1330 cp.min_interval = __constant_cpu_to_le16(0x0800);
1331 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001332 cp.type = get_adv_type(hdev);
Marcel Holtmann79830f62013-10-18 16:38:09 -07001333 cp.own_address_type = hdev->own_addr_type;
Johan Hedberg95c66e72013-10-14 16:20:06 +03001334 cp.channel_map = 0x07;
1335
1336 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1337
1338 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1339}
1340
1341static void disable_advertising(struct hci_request *req)
1342{
1343 u8 enable = 0x00;
1344
1345 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1346}
1347
Johan Hedberg2b76f452013-03-15 17:07:04 -05001348static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1349{
1350 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001351 struct mgmt_mode *cp;
1352 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001353
1354 BT_DBG("status 0x%02x", status);
1355
1356 hci_dev_lock(hdev);
1357
1358 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1359 if (!cmd)
1360 goto unlock;
1361
Johan Hedberg37438c12013-10-14 16:20:05 +03001362 if (status) {
1363 u8 mgmt_err = mgmt_status(status);
1364 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1365 goto remove_cmd;
1366 }
1367
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001368 cp = cmd->param;
1369 if (cp->val)
1370 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1371 else
1372 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1373
Johan Hedberg2b76f452013-03-15 17:07:04 -05001374 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1375
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001376 if (changed)
1377 new_settings(hdev, cmd->sk);
1378
Johan Hedberg37438c12013-10-14 16:20:05 +03001379remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001380 mgmt_pending_remove(cmd);
1381
1382unlock:
1383 hci_dev_unlock(hdev);
1384}
1385
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001386static int set_connectable_update_settings(struct hci_dev *hdev,
1387 struct sock *sk, u8 val)
1388{
1389 bool changed = false;
1390 int err;
1391
1392 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1393 changed = true;
1394
1395 if (val) {
1396 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1397 } else {
1398 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1399 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1400 }
1401
1402 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1403 if (err < 0)
1404 return err;
1405
1406 if (changed)
1407 return new_settings(hdev, sk);
1408
1409 return 0;
1410}
1411
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001412static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001413 u16 len)
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001414{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001415 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001416 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001417 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001418 u8 scan;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001419 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001420
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001421 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001422
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001423 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1424 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001425 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001426 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001427
Johan Hedberga7e80f22013-01-09 16:05:19 +02001428 if (cp->val != 0x00 && cp->val != 0x01)
1429 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1430 MGMT_STATUS_INVALID_PARAMS);
1431
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001432 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001433
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001434 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001435 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001436 goto failed;
1437 }
1438
1439 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001440 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001441 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001442 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001443 goto failed;
1444 }
1445
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001446 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1447 if (!cmd) {
1448 err = -ENOMEM;
1449 goto failed;
1450 }
1451
Johan Hedberg2b76f452013-03-15 17:07:04 -05001452 hci_req_init(&req, hdev);
1453
Johan Hedberg9b742462013-10-14 16:20:03 +03001454 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1455 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001456 if (cp->val) {
1457 scan = SCAN_PAGE;
1458 } else {
1459 scan = 0;
1460
1461 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001462 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001463 cancel_delayed_work(&hdev->discov_off);
1464 }
1465
1466 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1467 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001468
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001469 /* If we're going from non-connectable to connectable or
1470 * vice-versa when fast connectable is enabled ensure that fast
1471 * connectable gets disabled. write_fast_connectable won't do
1472 * anything if the page scan parameters are already what they
1473 * should be.
1474 */
1475 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001476 write_fast_connectable(&req, false);
1477
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001478 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1479 hci_conn_num(hdev, LE_LINK) == 0) {
1480 disable_advertising(&req);
1481 enable_advertising(&req);
1482 }
1483
Johan Hedberg2b76f452013-03-15 17:07:04 -05001484 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001485 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001486 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001487 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001488 err = set_connectable_update_settings(hdev, sk,
1489 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001490 goto failed;
1491 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001492
1493failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001494 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001495 return err;
1496}
1497
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001498static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001499 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001500{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001501 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001502 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001503 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001505 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001506
Johan Hedberga7e80f22013-01-09 16:05:19 +02001507 if (cp->val != 0x00 && cp->val != 0x01)
1508 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1509 MGMT_STATUS_INVALID_PARAMS);
1510
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001511 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001512
1513 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001514 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001515 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001516 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001517
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001518 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001519 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001520 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001521
Marcel Holtmann55594352013-10-06 16:11:57 -07001522 if (changed)
1523 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001524
Marcel Holtmann55594352013-10-06 16:11:57 -07001525unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001526 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001527 return err;
1528}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001529
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001530static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1531 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001532{
1533 struct mgmt_mode *cp = data;
1534 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001535 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001536 int err;
1537
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001538 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001539
Johan Hedberge6fe7982013-10-02 15:45:22 +03001540 status = mgmt_bredr_support(hdev);
1541 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001542 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001543 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001544
Johan Hedberga7e80f22013-01-09 16:05:19 +02001545 if (cp->val != 0x00 && cp->val != 0x01)
1546 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1547 MGMT_STATUS_INVALID_PARAMS);
1548
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001549 hci_dev_lock(hdev);
1550
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001551 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001552 bool changed = false;
1553
1554 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001555 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001556 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1557 changed = true;
1558 }
1559
1560 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1561 if (err < 0)
1562 goto failed;
1563
1564 if (changed)
1565 err = new_settings(hdev, sk);
1566
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001567 goto failed;
1568 }
1569
1570 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001571 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001572 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001573 goto failed;
1574 }
1575
1576 val = !!cp->val;
1577
1578 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1579 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1580 goto failed;
1581 }
1582
1583 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1584 if (!cmd) {
1585 err = -ENOMEM;
1586 goto failed;
1587 }
1588
1589 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1590 if (err < 0) {
1591 mgmt_pending_remove(cmd);
1592 goto failed;
1593 }
1594
1595failed:
1596 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001597 return err;
1598}
1599
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001600static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001601{
1602 struct mgmt_mode *cp = data;
1603 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001604 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001605 int err;
1606
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001607 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001608
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001609 status = mgmt_bredr_support(hdev);
1610 if (status)
1611 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1612
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001613 if (!lmp_ssp_capable(hdev))
1614 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1615 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001616
Johan Hedberga7e80f22013-01-09 16:05:19 +02001617 if (cp->val != 0x00 && cp->val != 0x01)
1618 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1619 MGMT_STATUS_INVALID_PARAMS);
1620
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001621 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001622
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001623 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001624 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001625
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001626 if (cp->val) {
1627 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1628 &hdev->dev_flags);
1629 } else {
1630 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1631 &hdev->dev_flags);
1632 if (!changed)
1633 changed = test_and_clear_bit(HCI_HS_ENABLED,
1634 &hdev->dev_flags);
1635 else
1636 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001637 }
1638
1639 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1640 if (err < 0)
1641 goto failed;
1642
1643 if (changed)
1644 err = new_settings(hdev, sk);
1645
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001646 goto failed;
1647 }
1648
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001649 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1650 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001651 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1652 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001653 goto failed;
1654 }
1655
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001656 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001657 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1658 goto failed;
1659 }
1660
1661 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1662 if (!cmd) {
1663 err = -ENOMEM;
1664 goto failed;
1665 }
1666
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001667 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001668 if (err < 0) {
1669 mgmt_pending_remove(cmd);
1670 goto failed;
1671 }
1672
1673failed:
1674 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001675 return err;
1676}
1677
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001678static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001679{
1680 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001681 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001682 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001683 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001684
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001685 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001686
Johan Hedberge6fe7982013-10-02 15:45:22 +03001687 status = mgmt_bredr_support(hdev);
1688 if (status)
1689 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001690
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001691 if (!lmp_ssp_capable(hdev))
1692 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1693 MGMT_STATUS_NOT_SUPPORTED);
1694
1695 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1696 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1697 MGMT_STATUS_REJECTED);
1698
Johan Hedberga7e80f22013-01-09 16:05:19 +02001699 if (cp->val != 0x00 && cp->val != 0x01)
1700 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1701 MGMT_STATUS_INVALID_PARAMS);
1702
Marcel Holtmannee392692013-10-01 22:59:23 -07001703 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001704
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001705 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001706 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001707 } else {
1708 if (hdev_is_powered(hdev)) {
1709 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1710 MGMT_STATUS_REJECTED);
1711 goto unlock;
1712 }
1713
Marcel Holtmannee392692013-10-01 22:59:23 -07001714 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001715 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001716
1717 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1718 if (err < 0)
1719 goto unlock;
1720
1721 if (changed)
1722 err = new_settings(hdev, sk);
1723
1724unlock:
1725 hci_dev_unlock(hdev);
1726 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001727}
1728
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001729static void le_enable_complete(struct hci_dev *hdev, u8 status)
1730{
1731 struct cmd_lookup match = { NULL, hdev };
1732
1733 if (status) {
1734 u8 mgmt_err = mgmt_status(status);
1735
1736 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1737 &mgmt_err);
1738 return;
1739 }
1740
1741 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1742
1743 new_settings(hdev, match.sk);
1744
1745 if (match.sk)
1746 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001747
1748 /* Make sure the controller has a good default for
1749 * advertising data. Restrict the update to when LE
1750 * has actually been enabled. During power on, the
1751 * update in powered_update_hci will take care of it.
1752 */
1753 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1754 struct hci_request req;
1755
1756 hci_dev_lock(hdev);
1757
1758 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001759 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001760 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001761 hci_req_run(&req, NULL);
1762
1763 hci_dev_unlock(hdev);
1764 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001765}
1766
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001767static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001768{
1769 struct mgmt_mode *cp = data;
1770 struct hci_cp_write_le_host_supported hci_cp;
1771 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001772 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001773 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001774 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001775
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001776 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001777
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001778 if (!lmp_le_capable(hdev))
1779 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1780 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001781
Johan Hedberga7e80f22013-01-09 16:05:19 +02001782 if (cp->val != 0x00 && cp->val != 0x01)
1783 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1784 MGMT_STATUS_INVALID_PARAMS);
1785
Johan Hedbergc73eee92013-04-19 18:35:21 +03001786 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001787 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001788 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1789 MGMT_STATUS_REJECTED);
1790
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001791 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001792
1793 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001794 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001795
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001796 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001797 bool changed = false;
1798
1799 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1800 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1801 changed = true;
1802 }
1803
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001804 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1805 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001806 changed = true;
1807 }
1808
Johan Hedberg06199cf2012-02-22 16:37:11 +02001809 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1810 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001811 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001812
1813 if (changed)
1814 err = new_settings(hdev, sk);
1815
Johan Hedberg1de028c2012-02-29 19:55:35 -08001816 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001817 }
1818
Johan Hedberg4375f102013-09-25 13:26:10 +03001819 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1820 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001821 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001822 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001823 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001824 }
1825
1826 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1827 if (!cmd) {
1828 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001829 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001830 }
1831
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001832 hci_req_init(&req, hdev);
1833
Johan Hedberg06199cf2012-02-22 16:37:11 +02001834 memset(&hci_cp, 0, sizeof(hci_cp));
1835
1836 if (val) {
1837 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001838 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001839 } else {
1840 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1841 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001842 }
1843
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001844 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1845 &hci_cp);
1846
1847 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301848 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001849 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001850
Johan Hedberg1de028c2012-02-29 19:55:35 -08001851unlock:
1852 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001853 return err;
1854}
1855
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001856/* This is a helper function to test for pending mgmt commands that can
1857 * cause CoD or EIR HCI commands. We can only allow one such pending
1858 * mgmt command at a time since otherwise we cannot easily track what
1859 * the current values are, will be, and based on that calculate if a new
1860 * HCI command needs to be sent and if yes with what value.
1861 */
1862static bool pending_eir_or_class(struct hci_dev *hdev)
1863{
1864 struct pending_cmd *cmd;
1865
1866 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1867 switch (cmd->opcode) {
1868 case MGMT_OP_ADD_UUID:
1869 case MGMT_OP_REMOVE_UUID:
1870 case MGMT_OP_SET_DEV_CLASS:
1871 case MGMT_OP_SET_POWERED:
1872 return true;
1873 }
1874 }
1875
1876 return false;
1877}
1878
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001879static const u8 bluetooth_base_uuid[] = {
1880 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1881 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1882};
1883
1884static u8 get_uuid_size(const u8 *uuid)
1885{
1886 u32 val;
1887
1888 if (memcmp(uuid, bluetooth_base_uuid, 12))
1889 return 128;
1890
1891 val = get_unaligned_le32(&uuid[12]);
1892 if (val > 0xffff)
1893 return 32;
1894
1895 return 16;
1896}
1897
Johan Hedberg92da6092013-03-15 17:06:55 -05001898static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1899{
1900 struct pending_cmd *cmd;
1901
1902 hci_dev_lock(hdev);
1903
1904 cmd = mgmt_pending_find(mgmt_op, hdev);
1905 if (!cmd)
1906 goto unlock;
1907
1908 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1909 hdev->dev_class, 3);
1910
1911 mgmt_pending_remove(cmd);
1912
1913unlock:
1914 hci_dev_unlock(hdev);
1915}
1916
1917static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1918{
1919 BT_DBG("status 0x%02x", status);
1920
1921 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1922}
1923
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001924static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001925{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001926 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001927 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001928 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001929 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001930 int err;
1931
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001932 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001933
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001934 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001935
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001936 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001937 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001938 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001939 goto failed;
1940 }
1941
Andre Guedes92c4c202012-06-07 19:05:44 -03001942 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001943 if (!uuid) {
1944 err = -ENOMEM;
1945 goto failed;
1946 }
1947
1948 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001949 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001950 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001951
Johan Hedbergde66aa62013-01-27 00:31:27 +02001952 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001953
Johan Hedberg890ea892013-03-15 17:06:52 -05001954 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001955
Johan Hedberg890ea892013-03-15 17:06:52 -05001956 update_class(&req);
1957 update_eir(&req);
1958
Johan Hedberg92da6092013-03-15 17:06:55 -05001959 err = hci_req_run(&req, add_uuid_complete);
1960 if (err < 0) {
1961 if (err != -ENODATA)
1962 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001963
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001964 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001965 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001966 goto failed;
1967 }
1968
1969 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001970 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001971 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001972 goto failed;
1973 }
1974
1975 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001976
1977failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001978 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001979 return err;
1980}
1981
Johan Hedberg24b78d02012-02-23 23:24:30 +02001982static bool enable_service_cache(struct hci_dev *hdev)
1983{
1984 if (!hdev_is_powered(hdev))
1985 return false;
1986
1987 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001988 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1989 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001990 return true;
1991 }
1992
1993 return false;
1994}
1995
Johan Hedberg92da6092013-03-15 17:06:55 -05001996static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1997{
1998 BT_DBG("status 0x%02x", status);
1999
2000 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2001}
2002
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002003static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002004 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002005{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002006 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002007 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002008 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002009 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 -05002010 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002011 int err, found;
2012
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002013 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002014
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002015 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002016
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002017 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002018 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002019 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002020 goto unlock;
2021 }
2022
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002023 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
2024 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002025
Johan Hedberg24b78d02012-02-23 23:24:30 +02002026 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002027 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002028 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002029 goto unlock;
2030 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002031
Johan Hedberg9246a862012-02-23 21:33:16 +02002032 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002033 }
2034
2035 found = 0;
2036
Johan Hedberg056341c2013-01-27 00:31:30 +02002037 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002038 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2039 continue;
2040
2041 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002042 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002043 found++;
2044 }
2045
2046 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002047 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002048 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002049 goto unlock;
2050 }
2051
Johan Hedberg9246a862012-02-23 21:33:16 +02002052update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002053 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002054
Johan Hedberg890ea892013-03-15 17:06:52 -05002055 update_class(&req);
2056 update_eir(&req);
2057
Johan Hedberg92da6092013-03-15 17:06:55 -05002058 err = hci_req_run(&req, remove_uuid_complete);
2059 if (err < 0) {
2060 if (err != -ENODATA)
2061 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002062
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002063 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002064 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002065 goto unlock;
2066 }
2067
2068 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002069 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002070 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002071 goto unlock;
2072 }
2073
2074 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002075
2076unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002077 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002078 return err;
2079}
2080
Johan Hedberg92da6092013-03-15 17:06:55 -05002081static void set_class_complete(struct hci_dev *hdev, u8 status)
2082{
2083 BT_DBG("status 0x%02x", status);
2084
2085 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2086}
2087
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002088static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002089 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002090{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002091 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002092 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002093 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002094 int err;
2095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002096 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002097
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002098 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002099 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2100 MGMT_STATUS_NOT_SUPPORTED);
2101
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002102 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002103
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002104 if (pending_eir_or_class(hdev)) {
2105 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2106 MGMT_STATUS_BUSY);
2107 goto unlock;
2108 }
2109
2110 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2111 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2112 MGMT_STATUS_INVALID_PARAMS);
2113 goto unlock;
2114 }
2115
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002116 hdev->major_class = cp->major;
2117 hdev->minor_class = cp->minor;
2118
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002119 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002120 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002121 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002122 goto unlock;
2123 }
2124
Johan Hedberg890ea892013-03-15 17:06:52 -05002125 hci_req_init(&req, hdev);
2126
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002127 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002128 hci_dev_unlock(hdev);
2129 cancel_delayed_work_sync(&hdev->service_cache);
2130 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002131 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002132 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002133
Johan Hedberg890ea892013-03-15 17:06:52 -05002134 update_class(&req);
2135
Johan Hedberg92da6092013-03-15 17:06:55 -05002136 err = hci_req_run(&req, set_class_complete);
2137 if (err < 0) {
2138 if (err != -ENODATA)
2139 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002140
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002141 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002142 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002143 goto unlock;
2144 }
2145
2146 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002147 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002148 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002149 goto unlock;
2150 }
2151
2152 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002153
Johan Hedbergb5235a62012-02-21 14:32:24 +02002154unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002155 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002156 return err;
2157}
2158
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002159static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002160 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002161{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002162 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002163 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002164 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002165
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002166 BT_DBG("request for %s", hdev->name);
2167
2168 if (!lmp_bredr_capable(hdev))
2169 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2170 MGMT_STATUS_NOT_SUPPORTED);
2171
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002172 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002173
Johan Hedberg86742e12011-11-07 23:13:38 +02002174 expected_len = sizeof(*cp) + key_count *
2175 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002176 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002177 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002178 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002179 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002180 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002181 }
2182
Johan Hedberg4ae14302013-01-20 14:27:13 +02002183 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2184 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2185 MGMT_STATUS_INVALID_PARAMS);
2186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002187 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002188 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002189
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002190 for (i = 0; i < key_count; i++) {
2191 struct mgmt_link_key_info *key = &cp->keys[i];
2192
2193 if (key->addr.type != BDADDR_BREDR)
2194 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2195 MGMT_STATUS_INVALID_PARAMS);
2196 }
2197
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002198 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002199
2200 hci_link_keys_clear(hdev);
2201
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002202 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002203 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002204 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002205 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002206
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002207 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002208 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002209
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002210 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002211 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002212 }
2213
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002214 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002215
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002216 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002217
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002218 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002219}
2220
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002221static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002222 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002223{
2224 struct mgmt_ev_device_unpaired ev;
2225
2226 bacpy(&ev.addr.bdaddr, bdaddr);
2227 ev.addr.type = addr_type;
2228
2229 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002230 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002231}
2232
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002233static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002234 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002235{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002236 struct mgmt_cp_unpair_device *cp = data;
2237 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002238 struct hci_cp_disconnect dc;
2239 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002240 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002241 int err;
2242
Johan Hedberga8a1d192011-11-10 15:54:38 +02002243 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002244 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2245 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002246
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002247 if (!bdaddr_type_is_valid(cp->addr.type))
2248 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2249 MGMT_STATUS_INVALID_PARAMS,
2250 &rp, sizeof(rp));
2251
Johan Hedberg118da702013-01-20 14:27:20 +02002252 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2253 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2254 MGMT_STATUS_INVALID_PARAMS,
2255 &rp, sizeof(rp));
2256
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002257 hci_dev_lock(hdev);
2258
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002259 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002260 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002261 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002262 goto unlock;
2263 }
2264
Andre Guedes591f47f2012-04-24 21:02:49 -03002265 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002266 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2267 else
2268 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002269
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002270 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002271 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002272 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002273 goto unlock;
2274 }
2275
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002276 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002277 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002278 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002279 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002280 else
2281 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002282 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002283 } else {
2284 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002285 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002286
Johan Hedberga8a1d192011-11-10 15:54:38 +02002287 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002288 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002289 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002290 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002291 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002292 }
2293
Johan Hedberg124f6e32012-02-09 13:50:12 +02002294 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002295 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002296 if (!cmd) {
2297 err = -ENOMEM;
2298 goto unlock;
2299 }
2300
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002301 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002302 dc.reason = 0x13; /* Remote User Terminated Connection */
2303 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2304 if (err < 0)
2305 mgmt_pending_remove(cmd);
2306
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002307unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002308 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002309 return err;
2310}
2311
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002312static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002313 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002314{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002315 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002316 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002317 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002318 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002319 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002320 int err;
2321
2322 BT_DBG("");
2323
Johan Hedberg06a63b12013-01-20 14:27:21 +02002324 memset(&rp, 0, sizeof(rp));
2325 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2326 rp.addr.type = cp->addr.type;
2327
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002328 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002329 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2330 MGMT_STATUS_INVALID_PARAMS,
2331 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002332
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002333 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002334
2335 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002336 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2337 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002338 goto failed;
2339 }
2340
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002341 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002342 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2343 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002344 goto failed;
2345 }
2346
Andre Guedes591f47f2012-04-24 21:02:49 -03002347 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002348 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2349 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002350 else
2351 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002352
Vishal Agarwalf9607272012-06-13 05:32:43 +05302353 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002354 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2355 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002356 goto failed;
2357 }
2358
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002359 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002360 if (!cmd) {
2361 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002362 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002363 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002364
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002365 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002366 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002367
2368 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2369 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002370 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002371
2372failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002373 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002374 return err;
2375}
2376
Andre Guedes57c14772012-04-24 21:02:50 -03002377static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002378{
2379 switch (link_type) {
2380 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002381 switch (addr_type) {
2382 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002383 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002384
Johan Hedberg48264f02011-11-09 13:58:58 +02002385 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002386 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002387 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002388 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002389
Johan Hedberg4c659c32011-11-07 23:13:39 +02002390 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002391 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002392 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002393 }
2394}
2395
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002396static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2397 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002398{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002399 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002400 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002401 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002402 int err;
2403 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002404
2405 BT_DBG("");
2406
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002407 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002408
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002409 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002410 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002411 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002412 goto unlock;
2413 }
2414
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002415 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002416 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2417 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002418 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002419 }
2420
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002421 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002422 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002423 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002424 err = -ENOMEM;
2425 goto unlock;
2426 }
2427
Johan Hedberg2784eb42011-01-21 13:56:35 +02002428 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002429 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002430 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2431 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002432 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002433 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002434 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002435 continue;
2436 i++;
2437 }
2438
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002439 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002440
Johan Hedberg4c659c32011-11-07 23:13:39 +02002441 /* Recalculate length in case of filtered SCO connections, etc */
2442 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002443
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002444 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002445 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002446
Johan Hedberga38528f2011-01-22 06:46:43 +02002447 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002448
2449unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002450 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002451 return err;
2452}
2453
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002454static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002455 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002456{
2457 struct pending_cmd *cmd;
2458 int err;
2459
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002460 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002461 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002462 if (!cmd)
2463 return -ENOMEM;
2464
Johan Hedbergd8457692012-02-17 14:24:57 +02002465 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002466 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002467 if (err < 0)
2468 mgmt_pending_remove(cmd);
2469
2470 return err;
2471}
2472
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002473static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002474 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002475{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002476 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002477 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002478 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002479 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002480 int err;
2481
2482 BT_DBG("");
2483
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002484 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002485
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002486 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002487 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002488 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002489 goto failed;
2490 }
2491
Johan Hedbergd8457692012-02-17 14:24:57 +02002492 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002493 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002494 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002495 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002496 goto failed;
2497 }
2498
2499 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002500 struct mgmt_cp_pin_code_neg_reply ncp;
2501
2502 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002503
2504 BT_ERR("PIN code is not 16 bytes long");
2505
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002506 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002507 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002508 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002509 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002510
2511 goto failed;
2512 }
2513
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002514 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002515 if (!cmd) {
2516 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002517 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002518 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002519
Johan Hedbergd8457692012-02-17 14:24:57 +02002520 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002521 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002522 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002523
2524 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2525 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002526 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002527
2528failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002529 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002530 return err;
2531}
2532
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002533static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2534 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002535{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002536 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002537
2538 BT_DBG("");
2539
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002540 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002541
2542 hdev->io_capability = cp->io_capability;
2543
2544 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002545 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002546
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002547 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002548
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002549 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2550 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002551}
2552
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002553static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002554{
2555 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002556 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002557
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002558 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002559 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2560 continue;
2561
Johan Hedberge9a416b2011-02-19 12:05:56 -03002562 if (cmd->user_data != conn)
2563 continue;
2564
2565 return cmd;
2566 }
2567
2568 return NULL;
2569}
2570
2571static void pairing_complete(struct pending_cmd *cmd, u8 status)
2572{
2573 struct mgmt_rp_pair_device rp;
2574 struct hci_conn *conn = cmd->user_data;
2575
Johan Hedbergba4e5642011-11-11 00:07:34 +02002576 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002577 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002578
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002579 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002580 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002581
2582 /* So we don't get further callbacks for this connection */
2583 conn->connect_cfm_cb = NULL;
2584 conn->security_cfm_cb = NULL;
2585 conn->disconn_cfm_cb = NULL;
2586
David Herrmann76a68ba2013-04-06 20:28:37 +02002587 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002588
Johan Hedberga664b5b2011-02-19 12:06:02 -03002589 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002590}
2591
2592static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2593{
2594 struct pending_cmd *cmd;
2595
2596 BT_DBG("status %u", status);
2597
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002598 cmd = find_pairing(conn);
2599 if (!cmd)
2600 BT_DBG("Unable to find a pending command");
2601 else
Johan Hedberge2113262012-02-18 15:20:03 +02002602 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002603}
2604
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302605static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2606{
2607 struct pending_cmd *cmd;
2608
2609 BT_DBG("status %u", status);
2610
2611 if (!status)
2612 return;
2613
2614 cmd = find_pairing(conn);
2615 if (!cmd)
2616 BT_DBG("Unable to find a pending command");
2617 else
2618 pairing_complete(cmd, mgmt_status(status));
2619}
2620
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002621static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002622 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002623{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002624 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002625 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002626 struct pending_cmd *cmd;
2627 u8 sec_level, auth_type;
2628 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002629 int err;
2630
2631 BT_DBG("");
2632
Szymon Jancf950a30e2013-01-18 12:48:07 +01002633 memset(&rp, 0, sizeof(rp));
2634 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2635 rp.addr.type = cp->addr.type;
2636
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002637 if (!bdaddr_type_is_valid(cp->addr.type))
2638 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2639 MGMT_STATUS_INVALID_PARAMS,
2640 &rp, sizeof(rp));
2641
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002642 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002643
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002644 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002645 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2646 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002647 goto unlock;
2648 }
2649
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002650 sec_level = BT_SECURITY_MEDIUM;
2651 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002652 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002653 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002654 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002655
Andre Guedes591f47f2012-04-24 21:02:49 -03002656 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002657 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2658 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002659 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002660 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2661 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002662
Ville Tervo30e76272011-02-22 16:10:53 -03002663 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002664 int status;
2665
2666 if (PTR_ERR(conn) == -EBUSY)
2667 status = MGMT_STATUS_BUSY;
2668 else
2669 status = MGMT_STATUS_CONNECT_FAILED;
2670
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002671 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002672 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002673 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002674 goto unlock;
2675 }
2676
2677 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002678 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002679 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002680 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002681 goto unlock;
2682 }
2683
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002684 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002685 if (!cmd) {
2686 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002687 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002688 goto unlock;
2689 }
2690
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002691 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002692 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002693 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302694 else
2695 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002696
Johan Hedberge9a416b2011-02-19 12:05:56 -03002697 conn->security_cfm_cb = pairing_complete_cb;
2698 conn->disconn_cfm_cb = pairing_complete_cb;
2699 conn->io_capability = cp->io_cap;
2700 cmd->user_data = conn;
2701
2702 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002703 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002704 pairing_complete(cmd, 0);
2705
2706 err = 0;
2707
2708unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002709 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002710 return err;
2711}
2712
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002713static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2714 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002715{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002716 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002717 struct pending_cmd *cmd;
2718 struct hci_conn *conn;
2719 int err;
2720
2721 BT_DBG("");
2722
Johan Hedberg28424702012-02-02 04:02:29 +02002723 hci_dev_lock(hdev);
2724
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002725 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002726 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002727 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002728 goto unlock;
2729 }
2730
Johan Hedberg28424702012-02-02 04:02:29 +02002731 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2732 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002733 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002734 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002735 goto unlock;
2736 }
2737
2738 conn = cmd->user_data;
2739
2740 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002741 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002742 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002743 goto unlock;
2744 }
2745
2746 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2747
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002748 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002749 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002750unlock:
2751 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002752 return err;
2753}
2754
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002755static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002756 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002757 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002758{
Johan Hedberga5c29682011-02-19 12:05:57 -03002759 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002760 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002761 int err;
2762
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002763 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002764
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002765 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002766 err = cmd_complete(sk, hdev->id, mgmt_op,
2767 MGMT_STATUS_NOT_POWERED, addr,
2768 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002769 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002770 }
2771
Johan Hedberg1707c602013-03-15 17:07:15 -05002772 if (addr->type == BDADDR_BREDR)
2773 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002774 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002775 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002776
Johan Hedberg272d90d2012-02-09 15:26:12 +02002777 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002778 err = cmd_complete(sk, hdev->id, mgmt_op,
2779 MGMT_STATUS_NOT_CONNECTED, addr,
2780 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002781 goto done;
2782 }
2783
Johan Hedberg1707c602013-03-15 17:07:15 -05002784 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002785 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002786 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002787
Brian Gix5fe57d92011-12-21 16:12:13 -08002788 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002789 err = cmd_complete(sk, hdev->id, mgmt_op,
2790 MGMT_STATUS_SUCCESS, addr,
2791 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002792 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002793 err = cmd_complete(sk, hdev->id, mgmt_op,
2794 MGMT_STATUS_FAILED, addr,
2795 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002796
Brian Gix47c15e22011-11-16 13:53:14 -08002797 goto done;
2798 }
2799
Johan Hedberg1707c602013-03-15 17:07:15 -05002800 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002801 if (!cmd) {
2802 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002803 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002804 }
2805
Brian Gix0df4c182011-11-16 13:53:13 -08002806 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002807 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2808 struct hci_cp_user_passkey_reply cp;
2809
Johan Hedberg1707c602013-03-15 17:07:15 -05002810 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002811 cp.passkey = passkey;
2812 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2813 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002814 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2815 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002816
Johan Hedberga664b5b2011-02-19 12:06:02 -03002817 if (err < 0)
2818 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002819
Brian Gix0df4c182011-11-16 13:53:13 -08002820done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002821 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002822 return err;
2823}
2824
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302825static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2826 void *data, u16 len)
2827{
2828 struct mgmt_cp_pin_code_neg_reply *cp = data;
2829
2830 BT_DBG("");
2831
Johan Hedberg1707c602013-03-15 17:07:15 -05002832 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302833 MGMT_OP_PIN_CODE_NEG_REPLY,
2834 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2835}
2836
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002837static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2838 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002839{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002840 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002841
2842 BT_DBG("");
2843
2844 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002845 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002846 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002847
Johan Hedberg1707c602013-03-15 17:07:15 -05002848 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002849 MGMT_OP_USER_CONFIRM_REPLY,
2850 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002851}
2852
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002853static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002854 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002855{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002856 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002857
2858 BT_DBG("");
2859
Johan Hedberg1707c602013-03-15 17:07:15 -05002860 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002861 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2862 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002863}
2864
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002865static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2866 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002867{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002868 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002869
2870 BT_DBG("");
2871
Johan Hedberg1707c602013-03-15 17:07:15 -05002872 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002873 MGMT_OP_USER_PASSKEY_REPLY,
2874 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002875}
2876
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002877static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002878 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002879{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002880 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002881
2882 BT_DBG("");
2883
Johan Hedberg1707c602013-03-15 17:07:15 -05002884 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002885 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2886 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002887}
2888
Johan Hedberg13928972013-03-15 17:07:00 -05002889static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002890{
Johan Hedberg13928972013-03-15 17:07:00 -05002891 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002892 struct hci_cp_write_local_name cp;
2893
Johan Hedberg13928972013-03-15 17:07:00 -05002894 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002895
Johan Hedberg890ea892013-03-15 17:06:52 -05002896 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002897}
2898
Johan Hedberg13928972013-03-15 17:07:00 -05002899static void set_name_complete(struct hci_dev *hdev, u8 status)
2900{
2901 struct mgmt_cp_set_local_name *cp;
2902 struct pending_cmd *cmd;
2903
2904 BT_DBG("status 0x%02x", status);
2905
2906 hci_dev_lock(hdev);
2907
2908 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2909 if (!cmd)
2910 goto unlock;
2911
2912 cp = cmd->param;
2913
2914 if (status)
2915 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2916 mgmt_status(status));
2917 else
2918 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2919 cp, sizeof(*cp));
2920
2921 mgmt_pending_remove(cmd);
2922
2923unlock:
2924 hci_dev_unlock(hdev);
2925}
2926
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002927static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002928 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002929{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002930 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002931 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002932 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002933 int err;
2934
2935 BT_DBG("");
2936
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002937 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002938
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002939 /* If the old values are the same as the new ones just return a
2940 * direct command complete event.
2941 */
2942 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2943 !memcmp(hdev->short_name, cp->short_name,
2944 sizeof(hdev->short_name))) {
2945 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2946 data, len);
2947 goto failed;
2948 }
2949
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002950 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002951
Johan Hedbergb5235a62012-02-21 14:32:24 +02002952 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002953 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002954
2955 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002956 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002957 if (err < 0)
2958 goto failed;
2959
2960 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002961 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002962
Johan Hedbergb5235a62012-02-21 14:32:24 +02002963 goto failed;
2964 }
2965
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002966 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002967 if (!cmd) {
2968 err = -ENOMEM;
2969 goto failed;
2970 }
2971
Johan Hedberg13928972013-03-15 17:07:00 -05002972 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2973
Johan Hedberg890ea892013-03-15 17:06:52 -05002974 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002975
2976 if (lmp_bredr_capable(hdev)) {
2977 update_name(&req);
2978 update_eir(&req);
2979 }
2980
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07002981 /* The name is stored in the scan response data and so
2982 * no need to udpate the advertising data here.
2983 */
Johan Hedberg3f985052013-03-15 17:07:02 -05002984 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07002985 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05002986
Johan Hedberg13928972013-03-15 17:07:00 -05002987 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002988 if (err < 0)
2989 mgmt_pending_remove(cmd);
2990
2991failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002992 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002993 return err;
2994}
2995
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002996static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002997 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002998{
Szymon Jancc35938b2011-03-22 13:12:21 +01002999 struct pending_cmd *cmd;
3000 int err;
3001
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003002 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003003
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003004 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003005
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003006 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003007 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003008 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003009 goto unlock;
3010 }
3011
Andre Guedes9a1a1992012-07-24 15:03:48 -03003012 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003013 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003014 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003015 goto unlock;
3016 }
3017
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003018 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003019 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003020 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003021 goto unlock;
3022 }
3023
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003024 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003025 if (!cmd) {
3026 err = -ENOMEM;
3027 goto unlock;
3028 }
3029
3030 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3031 if (err < 0)
3032 mgmt_pending_remove(cmd);
3033
3034unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003035 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003036 return err;
3037}
3038
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003039static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003040 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003041{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003042 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003043 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003044 int err;
3045
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003046 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003047
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003048 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003049
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003050 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003051 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01003052 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003053 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01003054 else
Szymon Janca6785be2012-12-13 15:11:21 +01003055 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003056
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003057 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003058 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003059
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003060 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003061 return err;
3062}
3063
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003064static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003065 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003066{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003067 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003068 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003069 int err;
3070
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003071 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003072
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003073 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003074
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003075 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003076 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003077 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003078 else
Szymon Janca6785be2012-12-13 15:11:21 +01003079 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003080
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003081 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003082 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003083
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003084 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003085 return err;
3086}
3087
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003088static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3089{
3090 struct pending_cmd *cmd;
3091 u8 type;
3092 int err;
3093
3094 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3095
3096 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3097 if (!cmd)
3098 return -ENOENT;
3099
3100 type = hdev->discovery.type;
3101
3102 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3103 &type, sizeof(type));
3104 mgmt_pending_remove(cmd);
3105
3106 return err;
3107}
3108
Andre Guedes7c307722013-04-30 15:29:28 -03003109static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3110{
3111 BT_DBG("status %d", status);
3112
3113 if (status) {
3114 hci_dev_lock(hdev);
3115 mgmt_start_discovery_failed(hdev, status);
3116 hci_dev_unlock(hdev);
3117 return;
3118 }
3119
3120 hci_dev_lock(hdev);
3121 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3122 hci_dev_unlock(hdev);
3123
3124 switch (hdev->discovery.type) {
3125 case DISCOV_TYPE_LE:
3126 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003127 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003128 break;
3129
3130 case DISCOV_TYPE_INTERLEAVED:
3131 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003132 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003133 break;
3134
3135 case DISCOV_TYPE_BREDR:
3136 break;
3137
3138 default:
3139 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3140 }
3141}
3142
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003143static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003144 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003145{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003146 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003147 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003148 struct hci_cp_le_set_scan_param param_cp;
3149 struct hci_cp_le_set_scan_enable enable_cp;
3150 struct hci_cp_inquiry inq_cp;
3151 struct hci_request req;
3152 /* General inquiry access code (GIAC) */
3153 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003154 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003155 int err;
3156
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003157 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003158
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003159 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003160
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003161 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003162 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003163 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003164 goto failed;
3165 }
3166
Andre Guedes642be6c2012-03-21 00:03:37 -03003167 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3168 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3169 MGMT_STATUS_BUSY);
3170 goto failed;
3171 }
3172
Johan Hedbergff9ef572012-01-04 14:23:45 +02003173 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003174 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003175 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003176 goto failed;
3177 }
3178
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003179 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003180 if (!cmd) {
3181 err = -ENOMEM;
3182 goto failed;
3183 }
3184
Andre Guedes4aab14e2012-02-17 20:39:36 -03003185 hdev->discovery.type = cp->type;
3186
Andre Guedes7c307722013-04-30 15:29:28 -03003187 hci_req_init(&req, hdev);
3188
Andre Guedes4aab14e2012-02-17 20:39:36 -03003189 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003190 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003191 status = mgmt_bredr_support(hdev);
3192 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003193 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003194 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003195 mgmt_pending_remove(cmd);
3196 goto failed;
3197 }
3198
Andre Guedes7c307722013-04-30 15:29:28 -03003199 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3200 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3201 MGMT_STATUS_BUSY);
3202 mgmt_pending_remove(cmd);
3203 goto failed;
3204 }
3205
3206 hci_inquiry_cache_flush(hdev);
3207
3208 memset(&inq_cp, 0, sizeof(inq_cp));
3209 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003210 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003211 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003212 break;
3213
3214 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003215 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003216 status = mgmt_le_support(hdev);
3217 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003218 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003219 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003220 mgmt_pending_remove(cmd);
3221 goto failed;
3222 }
3223
Andre Guedes7c307722013-04-30 15:29:28 -03003224 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003225 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003226 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3227 MGMT_STATUS_NOT_SUPPORTED);
3228 mgmt_pending_remove(cmd);
3229 goto failed;
3230 }
3231
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003232 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003233 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3234 MGMT_STATUS_REJECTED);
3235 mgmt_pending_remove(cmd);
3236 goto failed;
3237 }
3238
3239 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3240 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3241 MGMT_STATUS_BUSY);
3242 mgmt_pending_remove(cmd);
3243 goto failed;
3244 }
3245
3246 memset(&param_cp, 0, sizeof(param_cp));
3247 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003248 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3249 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003250 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003251 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3252 &param_cp);
3253
3254 memset(&enable_cp, 0, sizeof(enable_cp));
3255 enable_cp.enable = LE_SCAN_ENABLE;
3256 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3257 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3258 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003259 break;
3260
Andre Guedesf39799f2012-02-17 20:39:35 -03003261 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003262 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3263 MGMT_STATUS_INVALID_PARAMS);
3264 mgmt_pending_remove(cmd);
3265 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003266 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003267
Andre Guedes7c307722013-04-30 15:29:28 -03003268 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003269 if (err < 0)
3270 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003271 else
3272 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003273
3274failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003275 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003276 return err;
3277}
3278
Andre Guedes1183fdc2013-04-30 15:29:35 -03003279static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3280{
3281 struct pending_cmd *cmd;
3282 int err;
3283
3284 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3285 if (!cmd)
3286 return -ENOENT;
3287
3288 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3289 &hdev->discovery.type, sizeof(hdev->discovery.type));
3290 mgmt_pending_remove(cmd);
3291
3292 return err;
3293}
3294
Andre Guedes0e05bba2013-04-30 15:29:33 -03003295static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3296{
3297 BT_DBG("status %d", status);
3298
3299 hci_dev_lock(hdev);
3300
3301 if (status) {
3302 mgmt_stop_discovery_failed(hdev, status);
3303 goto unlock;
3304 }
3305
3306 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3307
3308unlock:
3309 hci_dev_unlock(hdev);
3310}
3311
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003312static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003313 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003314{
Johan Hedbergd9306502012-02-20 23:25:18 +02003315 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003316 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003317 struct hci_cp_remote_name_req_cancel cp;
3318 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003319 struct hci_request req;
3320 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003321 int err;
3322
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003323 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003324
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003325 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003326
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003327 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003328 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003329 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3330 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003331 goto unlock;
3332 }
3333
3334 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003335 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003336 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3337 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003338 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003339 }
3340
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003341 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003342 if (!cmd) {
3343 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003344 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003345 }
3346
Andre Guedes0e05bba2013-04-30 15:29:33 -03003347 hci_req_init(&req, hdev);
3348
Andre Guedese0d9727e2012-03-20 15:15:36 -03003349 switch (hdev->discovery.state) {
3350 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003351 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3352 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3353 } else {
3354 cancel_delayed_work(&hdev->le_scan_disable);
3355
3356 memset(&enable_cp, 0, sizeof(enable_cp));
3357 enable_cp.enable = LE_SCAN_DISABLE;
3358 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3359 sizeof(enable_cp), &enable_cp);
3360 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003361
Andre Guedese0d9727e2012-03-20 15:15:36 -03003362 break;
3363
3364 case DISCOVERY_RESOLVING:
3365 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003366 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003367 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003368 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003369 err = cmd_complete(sk, hdev->id,
3370 MGMT_OP_STOP_DISCOVERY, 0,
3371 &mgmt_cp->type,
3372 sizeof(mgmt_cp->type));
3373 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3374 goto unlock;
3375 }
3376
3377 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003378 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3379 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003380
3381 break;
3382
3383 default:
3384 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003385
3386 mgmt_pending_remove(cmd);
3387 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3388 MGMT_STATUS_FAILED, &mgmt_cp->type,
3389 sizeof(mgmt_cp->type));
3390 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003391 }
3392
Andre Guedes0e05bba2013-04-30 15:29:33 -03003393 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003394 if (err < 0)
3395 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003396 else
3397 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003398
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003399unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003400 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003401 return err;
3402}
3403
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003404static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003405 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003406{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003407 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003408 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003409 int err;
3410
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003411 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003412
Johan Hedberg561aafb2012-01-04 13:31:59 +02003413 hci_dev_lock(hdev);
3414
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003415 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003416 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003417 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003418 goto failed;
3419 }
3420
Johan Hedberga198e7b2012-02-17 14:27:06 +02003421 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003422 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003423 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003424 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003425 goto failed;
3426 }
3427
3428 if (cp->name_known) {
3429 e->name_state = NAME_KNOWN;
3430 list_del(&e->list);
3431 } else {
3432 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003433 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003434 }
3435
Johan Hedberge3846622013-01-09 15:29:33 +02003436 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3437 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003438
3439failed:
3440 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003441 return err;
3442}
3443
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003444static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003445 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003446{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003447 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003448 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003449 int err;
3450
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003451 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003452
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003453 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003454 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3455 MGMT_STATUS_INVALID_PARAMS,
3456 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003457
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003458 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003459
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003460 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003461 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003462 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003463 else
Szymon Janca6785be2012-12-13 15:11:21 +01003464 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003465
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003466 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003467 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003468
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003469 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003470
3471 return err;
3472}
3473
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003474static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003475 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003476{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003477 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003478 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003479 int err;
3480
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003481 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003482
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003483 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003484 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3485 MGMT_STATUS_INVALID_PARAMS,
3486 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003487
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003488 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003489
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003490 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003491 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003492 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003493 else
Szymon Janca6785be2012-12-13 15:11:21 +01003494 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003496 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003497 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003498
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003499 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003500
3501 return err;
3502}
3503
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003504static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3505 u16 len)
3506{
3507 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003508 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003509 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003510 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003511
3512 BT_DBG("%s", hdev->name);
3513
Szymon Jancc72d4b82012-03-16 16:02:57 +01003514 source = __le16_to_cpu(cp->source);
3515
3516 if (source > 0x0002)
3517 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3518 MGMT_STATUS_INVALID_PARAMS);
3519
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003520 hci_dev_lock(hdev);
3521
Szymon Jancc72d4b82012-03-16 16:02:57 +01003522 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003523 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3524 hdev->devid_product = __le16_to_cpu(cp->product);
3525 hdev->devid_version = __le16_to_cpu(cp->version);
3526
3527 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3528
Johan Hedberg890ea892013-03-15 17:06:52 -05003529 hci_req_init(&req, hdev);
3530 update_eir(&req);
3531 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003532
3533 hci_dev_unlock(hdev);
3534
3535 return err;
3536}
3537
Johan Hedberg4375f102013-09-25 13:26:10 +03003538static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3539{
3540 struct cmd_lookup match = { NULL, hdev };
3541
3542 if (status) {
3543 u8 mgmt_err = mgmt_status(status);
3544
3545 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3546 cmd_status_rsp, &mgmt_err);
3547 return;
3548 }
3549
3550 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3551 &match);
3552
3553 new_settings(hdev, match.sk);
3554
3555 if (match.sk)
3556 sock_put(match.sk);
3557}
3558
Marcel Holtmann21b51872013-10-10 09:47:53 -07003559static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3560 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003561{
3562 struct mgmt_mode *cp = data;
3563 struct pending_cmd *cmd;
3564 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003565 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003566 int err;
3567
3568 BT_DBG("request for %s", hdev->name);
3569
Johan Hedberge6fe7982013-10-02 15:45:22 +03003570 status = mgmt_le_support(hdev);
3571 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003572 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003573 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003574
3575 if (cp->val != 0x00 && cp->val != 0x01)
3576 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3577 MGMT_STATUS_INVALID_PARAMS);
3578
3579 hci_dev_lock(hdev);
3580
3581 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003582 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003583
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003584 /* The following conditions are ones which mean that we should
3585 * not do any HCI communication but directly send a mgmt
3586 * response to user space (after toggling the flag if
3587 * necessary).
3588 */
3589 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003590 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003591 bool changed = false;
3592
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003593 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3594 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003595 changed = true;
3596 }
3597
3598 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3599 if (err < 0)
3600 goto unlock;
3601
3602 if (changed)
3603 err = new_settings(hdev, sk);
3604
3605 goto unlock;
3606 }
3607
3608 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3609 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3610 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3611 MGMT_STATUS_BUSY);
3612 goto unlock;
3613 }
3614
3615 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3616 if (!cmd) {
3617 err = -ENOMEM;
3618 goto unlock;
3619 }
3620
3621 hci_req_init(&req, hdev);
3622
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003623 if (val)
3624 enable_advertising(&req);
3625 else
3626 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003627
3628 err = hci_req_run(&req, set_advertising_complete);
3629 if (err < 0)
3630 mgmt_pending_remove(cmd);
3631
3632unlock:
3633 hci_dev_unlock(hdev);
3634 return err;
3635}
3636
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003637static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3638 void *data, u16 len)
3639{
3640 struct mgmt_cp_set_static_address *cp = data;
3641 int err;
3642
3643 BT_DBG("%s", hdev->name);
3644
Marcel Holtmann62af4442013-10-02 22:10:32 -07003645 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003646 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003647 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003648
3649 if (hdev_is_powered(hdev))
3650 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3651 MGMT_STATUS_REJECTED);
3652
3653 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3654 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3655 return cmd_status(sk, hdev->id,
3656 MGMT_OP_SET_STATIC_ADDRESS,
3657 MGMT_STATUS_INVALID_PARAMS);
3658
3659 /* Two most significant bits shall be set */
3660 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3661 return cmd_status(sk, hdev->id,
3662 MGMT_OP_SET_STATIC_ADDRESS,
3663 MGMT_STATUS_INVALID_PARAMS);
3664 }
3665
3666 hci_dev_lock(hdev);
3667
3668 bacpy(&hdev->static_addr, &cp->bdaddr);
3669
3670 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3671
3672 hci_dev_unlock(hdev);
3673
3674 return err;
3675}
3676
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003677static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3678 void *data, u16 len)
3679{
3680 struct mgmt_cp_set_scan_params *cp = data;
3681 __u16 interval, window;
3682 int err;
3683
3684 BT_DBG("%s", hdev->name);
3685
3686 if (!lmp_le_capable(hdev))
3687 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3688 MGMT_STATUS_NOT_SUPPORTED);
3689
3690 interval = __le16_to_cpu(cp->interval);
3691
3692 if (interval < 0x0004 || interval > 0x4000)
3693 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3694 MGMT_STATUS_INVALID_PARAMS);
3695
3696 window = __le16_to_cpu(cp->window);
3697
3698 if (window < 0x0004 || window > 0x4000)
3699 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3700 MGMT_STATUS_INVALID_PARAMS);
3701
Marcel Holtmann899e1072013-10-14 09:55:32 -07003702 if (window > interval)
3703 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3704 MGMT_STATUS_INVALID_PARAMS);
3705
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003706 hci_dev_lock(hdev);
3707
3708 hdev->le_scan_interval = interval;
3709 hdev->le_scan_window = window;
3710
3711 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3712
3713 hci_dev_unlock(hdev);
3714
3715 return err;
3716}
3717
Johan Hedberg33e38b32013-03-15 17:07:05 -05003718static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3719{
3720 struct pending_cmd *cmd;
3721
3722 BT_DBG("status 0x%02x", status);
3723
3724 hci_dev_lock(hdev);
3725
3726 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3727 if (!cmd)
3728 goto unlock;
3729
3730 if (status) {
3731 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3732 mgmt_status(status));
3733 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003734 struct mgmt_mode *cp = cmd->param;
3735
3736 if (cp->val)
3737 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3738 else
3739 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3740
Johan Hedberg33e38b32013-03-15 17:07:05 -05003741 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3742 new_settings(hdev, cmd->sk);
3743 }
3744
3745 mgmt_pending_remove(cmd);
3746
3747unlock:
3748 hci_dev_unlock(hdev);
3749}
3750
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003751static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003752 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003753{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003754 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003755 struct pending_cmd *cmd;
3756 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003757 int err;
3758
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003759 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003760
Johan Hedberg56f87902013-10-02 13:43:13 +03003761 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3762 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003763 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3764 MGMT_STATUS_NOT_SUPPORTED);
3765
Johan Hedberga7e80f22013-01-09 16:05:19 +02003766 if (cp->val != 0x00 && cp->val != 0x01)
3767 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3768 MGMT_STATUS_INVALID_PARAMS);
3769
Johan Hedberg5400c042012-02-21 16:40:33 +02003770 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003771 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003772 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003773
3774 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003775 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003776 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003777
3778 hci_dev_lock(hdev);
3779
Johan Hedberg05cbf292013-03-15 17:07:07 -05003780 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3781 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3782 MGMT_STATUS_BUSY);
3783 goto unlock;
3784 }
3785
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003786 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3787 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3788 hdev);
3789 goto unlock;
3790 }
3791
Johan Hedberg33e38b32013-03-15 17:07:05 -05003792 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3793 data, len);
3794 if (!cmd) {
3795 err = -ENOMEM;
3796 goto unlock;
3797 }
3798
3799 hci_req_init(&req, hdev);
3800
Johan Hedberg406d7802013-03-15 17:07:09 -05003801 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003802
3803 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003804 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003805 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003806 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003807 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003808 }
3809
Johan Hedberg33e38b32013-03-15 17:07:05 -05003810unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003811 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003812
Antti Julkuf6422ec2011-06-22 13:11:56 +03003813 return err;
3814}
3815
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003816static void set_bredr_scan(struct hci_request *req)
3817{
3818 struct hci_dev *hdev = req->hdev;
3819 u8 scan = 0;
3820
3821 /* Ensure that fast connectable is disabled. This function will
3822 * not do anything if the page scan parameters are already what
3823 * they should be.
3824 */
3825 write_fast_connectable(req, false);
3826
3827 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3828 scan |= SCAN_PAGE;
3829 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3830 scan |= SCAN_INQUIRY;
3831
3832 if (scan)
3833 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3834}
3835
Johan Hedberg0663ca22013-10-02 13:43:14 +03003836static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3837{
3838 struct pending_cmd *cmd;
3839
3840 BT_DBG("status 0x%02x", status);
3841
3842 hci_dev_lock(hdev);
3843
3844 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3845 if (!cmd)
3846 goto unlock;
3847
3848 if (status) {
3849 u8 mgmt_err = mgmt_status(status);
3850
3851 /* We need to restore the flag if related HCI commands
3852 * failed.
3853 */
3854 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3855
3856 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3857 } else {
3858 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3859 new_settings(hdev, cmd->sk);
3860 }
3861
3862 mgmt_pending_remove(cmd);
3863
3864unlock:
3865 hci_dev_unlock(hdev);
3866}
3867
3868static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3869{
3870 struct mgmt_mode *cp = data;
3871 struct pending_cmd *cmd;
3872 struct hci_request req;
3873 int err;
3874
3875 BT_DBG("request for %s", hdev->name);
3876
3877 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3878 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3879 MGMT_STATUS_NOT_SUPPORTED);
3880
3881 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3882 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3883 MGMT_STATUS_REJECTED);
3884
3885 if (cp->val != 0x00 && cp->val != 0x01)
3886 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3887 MGMT_STATUS_INVALID_PARAMS);
3888
3889 hci_dev_lock(hdev);
3890
3891 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3892 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3893 goto unlock;
3894 }
3895
3896 if (!hdev_is_powered(hdev)) {
3897 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003898 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3899 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3900 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3901 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3902 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3903 }
3904
3905 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3906
3907 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3908 if (err < 0)
3909 goto unlock;
3910
3911 err = new_settings(hdev, sk);
3912 goto unlock;
3913 }
3914
3915 /* Reject disabling when powered on */
3916 if (!cp->val) {
3917 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3918 MGMT_STATUS_REJECTED);
3919 goto unlock;
3920 }
3921
3922 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3923 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3924 MGMT_STATUS_BUSY);
3925 goto unlock;
3926 }
3927
3928 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3929 if (!cmd) {
3930 err = -ENOMEM;
3931 goto unlock;
3932 }
3933
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003934 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03003935 * generates the correct flags.
3936 */
3937 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3938
3939 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003940
3941 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3942 set_bredr_scan(&req);
3943
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07003944 /* Since only the advertising data flags will change, there
3945 * is no need to update the scan response data.
3946 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003947 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003948
Johan Hedberg0663ca22013-10-02 13:43:14 +03003949 err = hci_req_run(&req, set_bredr_complete);
3950 if (err < 0)
3951 mgmt_pending_remove(cmd);
3952
3953unlock:
3954 hci_dev_unlock(hdev);
3955 return err;
3956}
3957
Johan Hedberg3f706b72013-01-20 14:27:16 +02003958static bool ltk_is_valid(struct mgmt_ltk_info *key)
3959{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003960 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3961 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003962 if (key->master != 0x00 && key->master != 0x01)
3963 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003964 if (!bdaddr_type_is_le(key->addr.type))
3965 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003966 return true;
3967}
3968
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003969static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003970 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003971{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003972 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3973 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003974 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003975
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003976 BT_DBG("request for %s", hdev->name);
3977
3978 if (!lmp_le_capable(hdev))
3979 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3980 MGMT_STATUS_NOT_SUPPORTED);
3981
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003982 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003983
3984 expected_len = sizeof(*cp) + key_count *
3985 sizeof(struct mgmt_ltk_info);
3986 if (expected_len != len) {
3987 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003988 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003989 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003990 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003991 }
3992
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003993 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003994
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003995 for (i = 0; i < key_count; i++) {
3996 struct mgmt_ltk_info *key = &cp->keys[i];
3997
Johan Hedberg3f706b72013-01-20 14:27:16 +02003998 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003999 return cmd_status(sk, hdev->id,
4000 MGMT_OP_LOAD_LONG_TERM_KEYS,
4001 MGMT_STATUS_INVALID_PARAMS);
4002 }
4003
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004004 hci_dev_lock(hdev);
4005
4006 hci_smp_ltks_clear(hdev);
4007
4008 for (i = 0; i < key_count; i++) {
4009 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004010 u8 type, addr_type;
4011
4012 if (key->addr.type == BDADDR_LE_PUBLIC)
4013 addr_type = ADDR_LE_DEV_PUBLIC;
4014 else
4015 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004016
4017 if (key->master)
4018 type = HCI_SMP_LTK;
4019 else
4020 type = HCI_SMP_LTK_SLAVE;
4021
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004022 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004023 type, 0, key->authenticated, key->val,
4024 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004025 }
4026
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004027 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4028 NULL, 0);
4029
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004030 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004031
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004032 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004033}
4034
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004035static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004036 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4037 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004038 bool var_len;
4039 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004040} mgmt_handlers[] = {
4041 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004042 { read_version, false, MGMT_READ_VERSION_SIZE },
4043 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4044 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4045 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4046 { set_powered, false, MGMT_SETTING_SIZE },
4047 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4048 { set_connectable, false, MGMT_SETTING_SIZE },
4049 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4050 { set_pairable, false, MGMT_SETTING_SIZE },
4051 { set_link_security, false, MGMT_SETTING_SIZE },
4052 { set_ssp, false, MGMT_SETTING_SIZE },
4053 { set_hs, false, MGMT_SETTING_SIZE },
4054 { set_le, false, MGMT_SETTING_SIZE },
4055 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4056 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4057 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4058 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4059 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4060 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4061 { disconnect, false, MGMT_DISCONNECT_SIZE },
4062 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4063 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4064 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4065 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4066 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4067 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4068 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4069 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4070 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4071 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4072 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4073 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
4074 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
4075 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4076 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4077 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4078 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4079 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4080 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004081 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004082 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004083 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004084 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004085 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004086};
4087
4088
Johan Hedberg03811012010-12-08 00:21:06 +02004089int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4090{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004091 void *buf;
4092 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004093 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004094 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004095 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004096 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004097 int err;
4098
4099 BT_DBG("got %zu bytes", msglen);
4100
4101 if (msglen < sizeof(*hdr))
4102 return -EINVAL;
4103
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004104 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004105 if (!buf)
4106 return -ENOMEM;
4107
4108 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4109 err = -EFAULT;
4110 goto done;
4111 }
4112
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004113 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004114 opcode = __le16_to_cpu(hdr->opcode);
4115 index = __le16_to_cpu(hdr->index);
4116 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004117
4118 if (len != msglen - sizeof(*hdr)) {
4119 err = -EINVAL;
4120 goto done;
4121 }
4122
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004123 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004124 hdev = hci_dev_get(index);
4125 if (!hdev) {
4126 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004127 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004128 goto done;
4129 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004130
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004131 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4132 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004133 err = cmd_status(sk, index, opcode,
4134 MGMT_STATUS_INVALID_INDEX);
4135 goto done;
4136 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004137 }
4138
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004139 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004140 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004141 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004142 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004143 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004144 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004145 }
4146
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004147 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004148 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004149 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004150 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004151 goto done;
4152 }
4153
Johan Hedbergbe22b542012-03-01 22:24:41 +02004154 handler = &mgmt_handlers[opcode];
4155
4156 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004157 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004158 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004159 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004160 goto done;
4161 }
4162
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004163 if (hdev)
4164 mgmt_init_hdev(sk, hdev);
4165
4166 cp = buf + sizeof(*hdr);
4167
Johan Hedbergbe22b542012-03-01 22:24:41 +02004168 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004169 if (err < 0)
4170 goto done;
4171
Johan Hedberg03811012010-12-08 00:21:06 +02004172 err = msglen;
4173
4174done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004175 if (hdev)
4176 hci_dev_put(hdev);
4177
Johan Hedberg03811012010-12-08 00:21:06 +02004178 kfree(buf);
4179 return err;
4180}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004181
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004182void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004183{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004184 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004185 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004186
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004187 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004188}
4189
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004190void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004191{
Johan Hedberg5f159032012-03-02 03:13:19 +02004192 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004193
Marcel Holtmann1514b892013-10-06 08:25:01 -07004194 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004195 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004196
Johan Hedberg744cf192011-11-08 20:40:14 +02004197 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004198
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004199 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004200}
4201
Johan Hedberg229ab392013-03-15 17:06:53 -05004202static void powered_complete(struct hci_dev *hdev, u8 status)
4203{
4204 struct cmd_lookup match = { NULL, hdev };
4205
4206 BT_DBG("status 0x%02x", status);
4207
4208 hci_dev_lock(hdev);
4209
4210 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4211
4212 new_settings(hdev, match.sk);
4213
4214 hci_dev_unlock(hdev);
4215
4216 if (match.sk)
4217 sock_put(match.sk);
4218}
4219
Johan Hedberg70da6242013-03-15 17:06:51 -05004220static int powered_update_hci(struct hci_dev *hdev)
4221{
Johan Hedberg890ea892013-03-15 17:06:52 -05004222 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004223 u8 link_sec;
4224
Johan Hedberg890ea892013-03-15 17:06:52 -05004225 hci_req_init(&req, hdev);
4226
Johan Hedberg70da6242013-03-15 17:06:51 -05004227 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4228 !lmp_host_ssp_capable(hdev)) {
4229 u8 ssp = 1;
4230
Johan Hedberg890ea892013-03-15 17:06:52 -05004231 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004232 }
4233
Johan Hedbergc73eee92013-04-19 18:35:21 +03004234 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4235 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004236 struct hci_cp_write_le_host_supported cp;
4237
4238 cp.le = 1;
4239 cp.simul = lmp_le_br_capable(hdev);
4240
4241 /* Check first if we already have the right
4242 * host state (host features set)
4243 */
4244 if (cp.le != lmp_host_le_capable(hdev) ||
4245 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004246 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4247 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004248 }
4249
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004250 if (lmp_le_capable(hdev)) {
4251 /* Set random address to static address if configured */
4252 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4253 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4254 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004255
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004256 /* Make sure the controller has a good default for
4257 * advertising data. This also applies to the case
4258 * where BR/EDR was toggled during the AUTO_OFF phase.
4259 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004260 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004261 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004262 update_scan_rsp_data(&req);
4263 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004264
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004265 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4266 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004267 }
4268
Johan Hedberg70da6242013-03-15 17:06:51 -05004269 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4270 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004271 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4272 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004273
4274 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004275 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4276 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004277 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004278 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004279 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004280 }
4281
Johan Hedberg229ab392013-03-15 17:06:53 -05004282 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004283}
4284
Johan Hedberg744cf192011-11-08 20:40:14 +02004285int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004286{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004287 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004288 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4289 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004290 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004291
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004292 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4293 return 0;
4294
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004295 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004296 if (powered_update_hci(hdev) == 0)
4297 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004298
Johan Hedberg229ab392013-03-15 17:06:53 -05004299 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4300 &match);
4301 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004302 }
4303
Johan Hedberg229ab392013-03-15 17:06:53 -05004304 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4305 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4306
4307 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4308 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4309 zero_cod, sizeof(zero_cod), NULL);
4310
4311new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004312 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004313
4314 if (match.sk)
4315 sock_put(match.sk);
4316
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004317 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004318}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004319
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004320void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004321{
4322 struct pending_cmd *cmd;
4323 u8 status;
4324
4325 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4326 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004327 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004328
4329 if (err == -ERFKILL)
4330 status = MGMT_STATUS_RFKILLED;
4331 else
4332 status = MGMT_STATUS_FAILED;
4333
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004334 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004335
4336 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004337}
4338
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004339void mgmt_discoverable_timeout(struct hci_dev *hdev)
4340{
4341 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004342
4343 hci_dev_lock(hdev);
4344
4345 /* When discoverable timeout triggers, then just make sure
4346 * the limited discoverable flag is cleared. Even in the case
4347 * of a timeout triggered from general discoverable, it is
4348 * safe to unconditionally clear the flag.
4349 */
4350 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
4351
4352 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004353 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4354 u8 scan = SCAN_PAGE;
4355 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4356 sizeof(scan), &scan);
4357 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004358 update_class(&req);
4359 hci_req_run(&req, NULL);
4360
4361 hdev->discov_timeout = 0;
4362
4363 hci_dev_unlock(hdev);
4364}
4365
Marcel Holtmann86a75642013-10-15 06:33:54 -07004366void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004367{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004368 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004369
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004370 /* Nothing needed here if there's a pending command since that
4371 * commands request completion callback takes care of everything
4372 * necessary.
4373 */
4374 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004375 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004376
Marcel Holtmann86a75642013-10-15 06:33:54 -07004377 if (discoverable)
4378 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4379 else
4380 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004381
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004382 if (changed)
Marcel Holtmann86a75642013-10-15 06:33:54 -07004383 new_settings(hdev, NULL);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004384}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004385
Marcel Holtmanna3309162013-10-15 06:33:55 -07004386void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004387{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004388 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004389
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004390 /* Nothing needed here if there's a pending command since that
4391 * commands request completion callback takes care of everything
4392 * necessary.
4393 */
4394 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004395 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004396
Marcel Holtmanna3309162013-10-15 06:33:55 -07004397 if (connectable)
4398 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4399 else
4400 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004401
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004402 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004403 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004404}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004405
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004406void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004407{
Johan Hedbergca69b792011-11-11 18:10:00 +02004408 u8 mgmt_err = mgmt_status(status);
4409
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004410 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004411 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004412 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004413
4414 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004415 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004416 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004417}
4418
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004419void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4420 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004421{
Johan Hedberg86742e12011-11-07 23:13:38 +02004422 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004423
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004424 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004425
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004426 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004427 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004428 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004429 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004430 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004431 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004432
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004433 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004434}
Johan Hedbergf7520542011-01-20 12:34:39 +02004435
Marcel Holtmann083368f2013-10-15 14:26:29 -07004436void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004437{
4438 struct mgmt_ev_new_long_term_key ev;
4439
4440 memset(&ev, 0, sizeof(ev));
4441
4442 ev.store_hint = persistent;
4443 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004444 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004445 ev.key.authenticated = key->authenticated;
4446 ev.key.enc_size = key->enc_size;
4447 ev.key.ediv = key->ediv;
4448
4449 if (key->type == HCI_SMP_LTK)
4450 ev.key.master = 1;
4451
4452 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4453 memcpy(ev.key.val, key->val, sizeof(key->val));
4454
Marcel Holtmann083368f2013-10-15 14:26:29 -07004455 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004456}
4457
Marcel Holtmann94933992013-10-15 10:26:39 -07004458static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4459 u8 data_len)
4460{
4461 eir[eir_len++] = sizeof(type) + data_len;
4462 eir[eir_len++] = type;
4463 memcpy(&eir[eir_len], data, data_len);
4464 eir_len += data_len;
4465
4466 return eir_len;
4467}
4468
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004469void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4470 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4471 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004472{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004473 char buf[512];
4474 struct mgmt_ev_device_connected *ev = (void *) buf;
4475 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004476
Johan Hedbergb644ba32012-01-17 21:48:47 +02004477 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004478 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004479
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004480 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004481
Johan Hedbergb644ba32012-01-17 21:48:47 +02004482 if (name_len > 0)
4483 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004484 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004485
4486 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004487 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004488 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004489
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004490 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004491
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004492 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4493 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004494}
4495
Johan Hedberg8962ee72011-01-20 12:40:27 +02004496static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4497{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004498 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004499 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004500 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004501
Johan Hedberg88c3df12012-02-09 14:27:38 +02004502 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4503 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004504
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004505 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004506 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004507
4508 *sk = cmd->sk;
4509 sock_hold(*sk);
4510
Johan Hedberga664b5b2011-02-19 12:06:02 -03004511 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004512}
4513
Johan Hedberg124f6e32012-02-09 13:50:12 +02004514static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004515{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004516 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004517 struct mgmt_cp_unpair_device *cp = cmd->param;
4518 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004519
4520 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004521 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4522 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004523
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004524 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4525
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004526 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004527
4528 mgmt_pending_remove(cmd);
4529}
4530
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004531void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4532 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004533{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004534 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004535 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004536
Johan Hedberg744cf192011-11-08 20:40:14 +02004537 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004538
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004539 bacpy(&ev.addr.bdaddr, bdaddr);
4540 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4541 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004542
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004543 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004544
4545 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004546 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004547
Johan Hedberg124f6e32012-02-09 13:50:12 +02004548 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004549 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004550}
4551
Marcel Holtmann78929242013-10-06 23:55:47 -07004552void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4553 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004554{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004555 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004556 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004557
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004558 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4559 hdev);
4560
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004561 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004562 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004563 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004564
Johan Hedberg88c3df12012-02-09 14:27:38 +02004565 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004566 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004567
Marcel Holtmann78929242013-10-06 23:55:47 -07004568 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4569 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004570
Johan Hedberga664b5b2011-02-19 12:06:02 -03004571 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004572}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004573
Marcel Holtmann445608d2013-10-06 23:55:48 -07004574void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4575 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004576{
4577 struct mgmt_ev_connect_failed ev;
4578
Johan Hedberg4c659c32011-11-07 23:13:39 +02004579 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004580 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004581 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004582
Marcel Holtmann445608d2013-10-06 23:55:48 -07004583 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004584}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004585
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004586void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004587{
4588 struct mgmt_ev_pin_code_request ev;
4589
Johan Hedbergd8457692012-02-17 14:24:57 +02004590 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004591 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004592 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004593
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004594 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004595}
4596
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004597void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4598 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004599{
4600 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004601 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004602
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004603 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004604 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004605 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004606
Johan Hedbergd8457692012-02-17 14:24:57 +02004607 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004608 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004609
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004610 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4611 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004612
Johan Hedberga664b5b2011-02-19 12:06:02 -03004613 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004614}
4615
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004616void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4617 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004618{
4619 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004620 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004621
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004622 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004623 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004624 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004625
Johan Hedbergd8457692012-02-17 14:24:57 +02004626 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004627 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004628
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004629 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4630 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004631
Johan Hedberga664b5b2011-02-19 12:06:02 -03004632 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004633}
Johan Hedberga5c29682011-02-19 12:05:57 -03004634
Johan Hedberg744cf192011-11-08 20:40:14 +02004635int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004636 u8 link_type, u8 addr_type, __le32 value,
4637 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004638{
4639 struct mgmt_ev_user_confirm_request ev;
4640
Johan Hedberg744cf192011-11-08 20:40:14 +02004641 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004642
Johan Hedberg272d90d2012-02-09 15:26:12 +02004643 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004644 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004645 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02004646 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004647
Johan Hedberg744cf192011-11-08 20:40:14 +02004648 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004649 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004650}
4651
Johan Hedberg272d90d2012-02-09 15:26:12 +02004652int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004653 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004654{
4655 struct mgmt_ev_user_passkey_request ev;
4656
4657 BT_DBG("%s", hdev->name);
4658
Johan Hedberg272d90d2012-02-09 15:26:12 +02004659 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004660 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004661
4662 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004663 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004664}
4665
Brian Gix0df4c182011-11-16 13:53:13 -08004666static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004667 u8 link_type, u8 addr_type, u8 status,
4668 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004669{
4670 struct pending_cmd *cmd;
4671 struct mgmt_rp_user_confirm_reply rp;
4672 int err;
4673
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004674 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004675 if (!cmd)
4676 return -ENOENT;
4677
Johan Hedberg272d90d2012-02-09 15:26:12 +02004678 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004679 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004680 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004681 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004682
Johan Hedberga664b5b2011-02-19 12:06:02 -03004683 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004684
4685 return err;
4686}
4687
Johan Hedberg744cf192011-11-08 20:40:14 +02004688int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004689 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004690{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004691 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004692 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004693}
4694
Johan Hedberg272d90d2012-02-09 15:26:12 +02004695int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004696 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004697{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004698 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004699 status,
4700 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004701}
Johan Hedberg2a611692011-02-19 12:06:00 -03004702
Brian Gix604086b2011-11-23 08:28:33 -08004703int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004704 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004705{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004706 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004707 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004708}
4709
Johan Hedberg272d90d2012-02-09 15:26:12 +02004710int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004711 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004712{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004713 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004714 status,
4715 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004716}
4717
Johan Hedberg92a25252012-09-06 18:39:26 +03004718int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4719 u8 link_type, u8 addr_type, u32 passkey,
4720 u8 entered)
4721{
4722 struct mgmt_ev_passkey_notify ev;
4723
4724 BT_DBG("%s", hdev->name);
4725
4726 bacpy(&ev.addr.bdaddr, bdaddr);
4727 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4728 ev.passkey = __cpu_to_le32(passkey);
4729 ev.entered = entered;
4730
4731 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4732}
4733
Marcel Holtmanne5460992013-10-15 14:26:23 -07004734void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4735 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004736{
4737 struct mgmt_ev_auth_failed ev;
4738
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004739 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004740 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004741 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004742
Marcel Holtmanne5460992013-10-15 14:26:23 -07004743 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004744}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004745
Marcel Holtmann464996a2013-10-15 14:26:24 -07004746void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004747{
4748 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004749 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004750
4751 if (status) {
4752 u8 mgmt_err = mgmt_status(status);
4753 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004754 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004755 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004756 }
4757
Marcel Holtmann464996a2013-10-15 14:26:24 -07004758 if (test_bit(HCI_AUTH, &hdev->flags))
4759 changed = !test_and_set_bit(HCI_LINK_SECURITY,
4760 &hdev->dev_flags);
4761 else
4762 changed = test_and_clear_bit(HCI_LINK_SECURITY,
4763 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02004764
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004765 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004766 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004767
Johan Hedberg47990ea2012-02-22 11:58:37 +02004768 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07004769 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004770
4771 if (match.sk)
4772 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004773}
4774
Johan Hedberg890ea892013-03-15 17:06:52 -05004775static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004776{
Johan Hedberg890ea892013-03-15 17:06:52 -05004777 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004778 struct hci_cp_write_eir cp;
4779
Johan Hedberg976eb202012-10-24 21:12:01 +03004780 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004781 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004782
Johan Hedbergc80da272012-02-22 15:38:48 +02004783 memset(hdev->eir, 0, sizeof(hdev->eir));
4784
Johan Hedbergcacaf522012-02-21 00:52:42 +02004785 memset(&cp, 0, sizeof(cp));
4786
Johan Hedberg890ea892013-03-15 17:06:52 -05004787 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004788}
4789
Marcel Holtmann3e248562013-10-15 14:26:25 -07004790void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004791{
4792 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004793 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004794 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004795
4796 if (status) {
4797 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004798
4799 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004800 &hdev->dev_flags)) {
4801 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004802 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004803 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004804
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004805 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4806 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004807 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004808 }
4809
4810 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004811 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004812 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004813 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4814 if (!changed)
4815 changed = test_and_clear_bit(HCI_HS_ENABLED,
4816 &hdev->dev_flags);
4817 else
4818 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004819 }
4820
4821 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4822
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004823 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07004824 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004825
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004826 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004827 sock_put(match.sk);
4828
Johan Hedberg890ea892013-03-15 17:06:52 -05004829 hci_req_init(&req, hdev);
4830
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004831 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004832 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004833 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004834 clear_eir(&req);
4835
4836 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004837}
4838
Johan Hedberg92da6092013-03-15 17:06:55 -05004839static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004840{
4841 struct cmd_lookup *match = data;
4842
Johan Hedberg90e70452012-02-23 23:09:40 +02004843 if (match->sk == NULL) {
4844 match->sk = cmd->sk;
4845 sock_hold(match->sk);
4846 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004847}
4848
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004849void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
4850 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004851{
Johan Hedberg90e70452012-02-23 23:09:40 +02004852 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004853
Johan Hedberg92da6092013-03-15 17:06:55 -05004854 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4855 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4856 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004857
4858 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004859 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
4860 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004861
4862 if (match.sk)
4863 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004864}
4865
Marcel Holtmann7667da32013-10-15 14:26:27 -07004866void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004867{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004868 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004869 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004870
Johan Hedberg13928972013-03-15 17:07:00 -05004871 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07004872 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004873
4874 memset(&ev, 0, sizeof(ev));
4875 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004876 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004877
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004878 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004879 if (!cmd) {
4880 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004881
Johan Hedberg13928972013-03-15 17:07:00 -05004882 /* If this is a HCI command related to powering on the
4883 * HCI dev don't send any mgmt signals.
4884 */
4885 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07004886 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004887 }
4888
Marcel Holtmann7667da32013-10-15 14:26:27 -07004889 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4890 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004891}
Szymon Jancc35938b2011-03-22 13:12:21 +01004892
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004893void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
4894 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004895{
4896 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01004897
Johan Hedberg744cf192011-11-08 20:40:14 +02004898 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004899
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004900 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004901 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004902 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01004903
4904 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004905 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4906 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004907 } else {
4908 struct mgmt_rp_read_local_oob_data rp;
4909
4910 memcpy(rp.hash, hash, sizeof(rp.hash));
4911 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4912
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004913 cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4914 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004915 }
4916
4917 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01004918}
Johan Hedberge17acd42011-03-30 23:57:16 +03004919
Marcel Holtmann901801b2013-10-06 23:55:51 -07004920void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4921 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4922 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004923{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004924 char buf[512];
4925 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004926 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004927
Andre Guedes12602d02013-04-30 15:29:40 -03004928 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004929 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004930
Johan Hedberg1dc06092012-01-15 21:01:23 +02004931 /* Leave 5 bytes for a potential CoD field */
4932 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004933 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004934
Johan Hedberg1dc06092012-01-15 21:01:23 +02004935 memset(buf, 0, sizeof(buf));
4936
Johan Hedberge319d2e2012-01-15 19:51:59 +02004937 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004938 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004939 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004940 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304941 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004942 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304943 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004944
Johan Hedberg1dc06092012-01-15 21:01:23 +02004945 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004946 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004947
Johan Hedberg1dc06092012-01-15 21:01:23 +02004948 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4949 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004950 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004951
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004952 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004953 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004954
Marcel Holtmann901801b2013-10-06 23:55:51 -07004955 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004956}
Johan Hedberga88a9652011-03-30 13:18:12 +03004957
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004958void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4959 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004960{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004961 struct mgmt_ev_device_found *ev;
4962 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4963 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004964
Johan Hedbergb644ba32012-01-17 21:48:47 +02004965 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004966
Johan Hedbergb644ba32012-01-17 21:48:47 +02004967 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004968
Johan Hedbergb644ba32012-01-17 21:48:47 +02004969 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004970 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004971 ev->rssi = rssi;
4972
4973 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004974 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004975
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004976 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004977
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004978 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004979}
Johan Hedberg314b2382011-04-27 10:29:57 -04004980
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004981void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004982{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004983 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004984 struct pending_cmd *cmd;
4985
Andre Guedes343fb142011-11-22 17:14:19 -03004986 BT_DBG("%s discovering %u", hdev->name, discovering);
4987
Johan Hedberg164a6e72011-11-01 17:06:44 +02004988 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004989 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004990 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004991 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004992
4993 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004994 u8 type = hdev->discovery.type;
4995
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004996 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4997 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004998 mgmt_pending_remove(cmd);
4999 }
5000
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005001 memset(&ev, 0, sizeof(ev));
5002 ev.type = hdev->discovery.type;
5003 ev.discovering = discovering;
5004
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005005 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005006}
Antti Julku5e762442011-08-25 16:48:02 +03005007
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005008int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005009{
5010 struct pending_cmd *cmd;
5011 struct mgmt_ev_device_blocked ev;
5012
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005013 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005014
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005015 bacpy(&ev.addr.bdaddr, bdaddr);
5016 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005017
Johan Hedberg744cf192011-11-08 20:40:14 +02005018 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005019 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005020}
5021
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005022int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005023{
5024 struct pending_cmd *cmd;
5025 struct mgmt_ev_device_unblocked ev;
5026
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005027 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005028
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005029 bacpy(&ev.addr.bdaddr, bdaddr);
5030 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005031
Johan Hedberg744cf192011-11-08 20:40:14 +02005032 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005033 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005034}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005035
5036static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5037{
5038 BT_DBG("%s status %u", hdev->name, status);
5039
5040 /* Clear the advertising mgmt setting if we failed to re-enable it */
5041 if (status) {
5042 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005043 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005044 }
5045}
5046
5047void mgmt_reenable_advertising(struct hci_dev *hdev)
5048{
5049 struct hci_request req;
5050
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005051 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005052 return;
5053
5054 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5055 return;
5056
5057 hci_req_init(&req, hdev);
5058 enable_advertising(&req);
5059
5060 /* If this fails we have no option but to let user space know
5061 * that we've disabled advertising.
5062 */
5063 if (hci_req_run(&req, adv_enable_complete) < 0) {
5064 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005065 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005066 }
5067}