blob: 074d83690a414c8e668499d7f7e7c86215c563ea [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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200203
Andre Guedes790eff42012-06-07 19:05:46 -0300204 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200220 kfree_skb(skb);
221
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300222 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223}
224
Johan Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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
Johan Hedberg9a43e252013-10-20 19:00:07 +0300602static u8 get_adv_discov_flags(struct hci_dev *hdev)
603{
604 struct pending_cmd *cmd;
605
606 /* If there's a pending mgmt command the flags will not yet have
607 * their final values, so check for this first.
608 */
609 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
610 if (cmd) {
611 struct mgmt_mode *cp = cmd->param;
612 if (cp->val == 0x01)
613 return LE_AD_GENERAL;
614 else if (cp->val == 0x02)
615 return LE_AD_LIMITED;
616 } else {
617 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
618 return LE_AD_LIMITED;
619 else if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
620 return LE_AD_GENERAL;
621 }
622
623 return 0;
624}
625
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700626static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700627{
628 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700629
Johan Hedberg9a43e252013-10-20 19:00:07 +0300630 flags |= get_adv_discov_flags(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700631
632 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
633 if (lmp_le_br_capable(hdev))
634 flags |= LE_AD_SIM_LE_BREDR_CTRL;
635 if (lmp_host_le_br_capable(hdev))
636 flags |= LE_AD_SIM_LE_BREDR_HOST;
637 } else {
638 flags |= LE_AD_NO_BREDR;
639 }
640
641 if (flags) {
642 BT_DBG("adv flags 0x%02x", flags);
643
644 ptr[0] = 2;
645 ptr[1] = EIR_FLAGS;
646 ptr[2] = flags;
647
648 ad_len += 3;
649 ptr += 3;
650 }
651
652 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
653 ptr[0] = 2;
654 ptr[1] = EIR_TX_POWER;
655 ptr[2] = (u8) hdev->adv_tx_power;
656
657 ad_len += 3;
658 ptr += 3;
659 }
660
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700661 return ad_len;
662}
663
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700664static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700665{
666 struct hci_dev *hdev = req->hdev;
667 struct hci_cp_le_set_adv_data cp;
668 u8 len;
669
Johan Hedberg10994ce2013-10-19 23:38:16 +0300670 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700671 return;
672
673 memset(&cp, 0, sizeof(cp));
674
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700675 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700676
677 if (hdev->adv_data_len == len &&
678 memcmp(cp.data, hdev->adv_data, len) == 0)
679 return;
680
681 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
682 hdev->adv_data_len = len;
683
684 cp.length = len;
685
686 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
687}
688
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300689static void create_eir(struct hci_dev *hdev, u8 *data)
690{
691 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300692 size_t name_len;
693
694 name_len = strlen(hdev->dev_name);
695
696 if (name_len > 0) {
697 /* EIR Data type */
698 if (name_len > 48) {
699 name_len = 48;
700 ptr[1] = EIR_NAME_SHORT;
701 } else
702 ptr[1] = EIR_NAME_COMPLETE;
703
704 /* EIR Data length */
705 ptr[0] = name_len + 1;
706
707 memcpy(ptr + 2, hdev->dev_name, name_len);
708
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300709 ptr += (name_len + 2);
710 }
711
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100712 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700713 ptr[0] = 2;
714 ptr[1] = EIR_TX_POWER;
715 ptr[2] = (u8) hdev->inq_tx_power;
716
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700717 ptr += 3;
718 }
719
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700720 if (hdev->devid_source > 0) {
721 ptr[0] = 9;
722 ptr[1] = EIR_DEVICE_ID;
723
724 put_unaligned_le16(hdev->devid_source, ptr + 2);
725 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
726 put_unaligned_le16(hdev->devid_product, ptr + 6);
727 put_unaligned_le16(hdev->devid_version, ptr + 8);
728
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700729 ptr += 10;
730 }
731
Johan Hedberg213202e2013-01-27 00:31:33 +0200732 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200733 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200734 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300735}
736
Johan Hedberg890ea892013-03-15 17:06:52 -0500737static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300738{
Johan Hedberg890ea892013-03-15 17:06:52 -0500739 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300740 struct hci_cp_write_eir cp;
741
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200742 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500743 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200744
Johan Hedberg976eb202012-10-24 21:12:01 +0300745 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500746 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300747
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200748 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500749 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300750
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200751 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500752 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300753
754 memset(&cp, 0, sizeof(cp));
755
756 create_eir(hdev, cp.data);
757
758 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500759 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300760
761 memcpy(hdev->eir, cp.data, sizeof(cp.data));
762
Johan Hedberg890ea892013-03-15 17:06:52 -0500763 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300764}
765
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200766static u8 get_service_classes(struct hci_dev *hdev)
767{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300768 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200769 u8 val = 0;
770
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300771 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200772 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200773
774 return val;
775}
776
Johan Hedberg890ea892013-03-15 17:06:52 -0500777static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200778{
Johan Hedberg890ea892013-03-15 17:06:52 -0500779 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200780 u8 cod[3];
781
782 BT_DBG("%s", hdev->name);
783
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200784 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500785 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200786
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300787 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
788 return;
789
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200790 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500791 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200792
793 cod[0] = hdev->minor_class;
794 cod[1] = hdev->major_class;
795 cod[2] = get_service_classes(hdev);
796
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700797 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
798 cod[1] |= 0x20;
799
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200800 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500801 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200802
Johan Hedberg890ea892013-03-15 17:06:52 -0500803 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200804}
805
Johan Hedberg7d785252011-12-15 00:47:39 +0200806static void service_cache_off(struct work_struct *work)
807{
808 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300809 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500810 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200811
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200812 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200813 return;
814
Johan Hedberg890ea892013-03-15 17:06:52 -0500815 hci_req_init(&req, hdev);
816
Johan Hedberg7d785252011-12-15 00:47:39 +0200817 hci_dev_lock(hdev);
818
Johan Hedberg890ea892013-03-15 17:06:52 -0500819 update_eir(&req);
820 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200821
822 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500823
824 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200825}
826
Johan Hedberg6a919082012-02-28 06:17:26 +0200827static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200828{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200829 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200830 return;
831
Johan Hedberg4f87da82012-03-02 19:55:56 +0200832 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200833
Johan Hedberg4f87da82012-03-02 19:55:56 +0200834 /* Non-mgmt controlled devices get this bit set
835 * implicitly so that pairing works for them, however
836 * for mgmt we require user-space to explicitly enable
837 * it
838 */
839 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200840}
841
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200842static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300843 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200844{
845 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200846
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200847 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200848
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300849 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200850
Johan Hedberg03811012010-12-08 00:21:06 +0200851 memset(&rp, 0, sizeof(rp));
852
Johan Hedberg03811012010-12-08 00:21:06 +0200853 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200854
855 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200856 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200857
858 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
859 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
860
861 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200862
863 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200864 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200865
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300866 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200867
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200868 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300869 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200870}
871
872static void mgmt_pending_free(struct pending_cmd *cmd)
873{
874 sock_put(cmd->sk);
875 kfree(cmd->param);
876 kfree(cmd);
877}
878
879static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300880 struct hci_dev *hdev, void *data,
881 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200882{
883 struct pending_cmd *cmd;
884
Andre Guedes12b94562012-06-07 19:05:45 -0300885 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200886 if (!cmd)
887 return NULL;
888
889 cmd->opcode = opcode;
890 cmd->index = hdev->id;
891
Andre Guedes12b94562012-06-07 19:05:45 -0300892 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200893 if (!cmd->param) {
894 kfree(cmd);
895 return NULL;
896 }
897
898 if (data)
899 memcpy(cmd->param, data, len);
900
901 cmd->sk = sk;
902 sock_hold(sk);
903
904 list_add(&cmd->list, &hdev->mgmt_pending);
905
906 return cmd;
907}
908
909static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300910 void (*cb)(struct pending_cmd *cmd,
911 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300912 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200913{
Andre Guedesa3d09352013-02-01 11:21:30 -0300914 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200915
Andre Guedesa3d09352013-02-01 11:21:30 -0300916 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200917 if (opcode > 0 && cmd->opcode != opcode)
918 continue;
919
920 cb(cmd, data);
921 }
922}
923
Johan Hedberg03811012010-12-08 00:21:06 +0200924static void mgmt_pending_remove(struct pending_cmd *cmd)
925{
926 list_del(&cmd->list);
927 mgmt_pending_free(cmd);
928}
929
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200930static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200931{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200932 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200933
Johan Hedbergaee9b212012-02-18 15:07:59 +0200934 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300935 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200936}
937
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200938static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300939 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200940{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300941 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200942 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200943 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200944
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200945 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200946
Johan Hedberga7e80f22013-01-09 16:05:19 +0200947 if (cp->val != 0x00 && cp->val != 0x01)
948 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
949 MGMT_STATUS_INVALID_PARAMS);
950
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300951 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200952
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300953 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
954 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
955 MGMT_STATUS_BUSY);
956 goto failed;
957 }
958
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100959 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
960 cancel_delayed_work(&hdev->power_off);
961
962 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200963 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
964 data, len);
965 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100966 goto failed;
967 }
968 }
969
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200970 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200971 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200972 goto failed;
973 }
974
Johan Hedberg03811012010-12-08 00:21:06 +0200975 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
976 if (!cmd) {
977 err = -ENOMEM;
978 goto failed;
979 }
980
981 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200982 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200983 else
Johan Hedberg19202572013-01-14 22:33:51 +0200984 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200985
986 err = 0;
987
988failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300989 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200990 return err;
991}
992
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300993static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
994 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200995{
996 struct sk_buff *skb;
997 struct mgmt_hdr *hdr;
998
Andre Guedes790eff42012-06-07 19:05:46 -0300999 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001000 if (!skb)
1001 return -ENOMEM;
1002
1003 hdr = (void *) skb_put(skb, sizeof(*hdr));
1004 hdr->opcode = cpu_to_le16(event);
1005 if (hdev)
1006 hdr->index = cpu_to_le16(hdev->id);
1007 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05301008 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001009 hdr->len = cpu_to_le16(data_len);
1010
1011 if (data)
1012 memcpy(skb_put(skb, data_len), data, data_len);
1013
Marcel Holtmann97e0bde2012-02-22 13:49:28 +01001014 /* Time stamp */
1015 __net_timestamp(skb);
1016
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001017 hci_send_to_control(skb, skip_sk);
1018 kfree_skb(skb);
1019
1020 return 0;
1021}
1022
1023static int new_settings(struct hci_dev *hdev, struct sock *skip)
1024{
1025 __le32 ev;
1026
1027 ev = cpu_to_le32(get_current_settings(hdev));
1028
1029 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1030}
1031
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001032struct cmd_lookup {
1033 struct sock *sk;
1034 struct hci_dev *hdev;
1035 u8 mgmt_status;
1036};
1037
1038static void settings_rsp(struct pending_cmd *cmd, void *data)
1039{
1040 struct cmd_lookup *match = data;
1041
1042 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1043
1044 list_del(&cmd->list);
1045
1046 if (match->sk == NULL) {
1047 match->sk = cmd->sk;
1048 sock_hold(match->sk);
1049 }
1050
1051 mgmt_pending_free(cmd);
1052}
1053
1054static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1055{
1056 u8 *status = data;
1057
1058 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1059 mgmt_pending_remove(cmd);
1060}
1061
Johan Hedberge6fe7982013-10-02 15:45:22 +03001062static u8 mgmt_bredr_support(struct hci_dev *hdev)
1063{
1064 if (!lmp_bredr_capable(hdev))
1065 return MGMT_STATUS_NOT_SUPPORTED;
1066 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1067 return MGMT_STATUS_REJECTED;
1068 else
1069 return MGMT_STATUS_SUCCESS;
1070}
1071
1072static u8 mgmt_le_support(struct hci_dev *hdev)
1073{
1074 if (!lmp_le_capable(hdev))
1075 return MGMT_STATUS_NOT_SUPPORTED;
1076 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1077 return MGMT_STATUS_REJECTED;
1078 else
1079 return MGMT_STATUS_SUCCESS;
1080}
1081
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001082static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1083{
1084 struct pending_cmd *cmd;
1085 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001086 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001087 bool changed;
1088
1089 BT_DBG("status 0x%02x", status);
1090
1091 hci_dev_lock(hdev);
1092
1093 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1094 if (!cmd)
1095 goto unlock;
1096
1097 if (status) {
1098 u8 mgmt_err = mgmt_status(status);
1099 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001100 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001101 goto remove_cmd;
1102 }
1103
1104 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001105 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001106 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1107 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001108
1109 if (hdev->discov_timeout > 0) {
1110 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1111 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1112 to);
1113 }
1114 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001115 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1116 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001117 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001118
1119 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1120
1121 if (changed)
1122 new_settings(hdev, cmd->sk);
1123
Marcel Holtmann970ba522013-10-15 06:33:57 -07001124 /* When the discoverable mode gets changed, make sure
1125 * that class of device has the limited discoverable
1126 * bit correctly set.
1127 */
1128 hci_req_init(&req, hdev);
1129 update_class(&req);
1130 hci_req_run(&req, NULL);
1131
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001132remove_cmd:
1133 mgmt_pending_remove(cmd);
1134
1135unlock:
1136 hci_dev_unlock(hdev);
1137}
1138
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001139static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001140 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001141{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001142 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001143 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001144 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001145 u16 timeout;
Johan Hedberg9a43e252013-10-20 19:00:07 +03001146 u8 scan;
Johan Hedberg03811012010-12-08 00:21:06 +02001147 int err;
1148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001149 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001150
Johan Hedberg9a43e252013-10-20 19:00:07 +03001151 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1152 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001153 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberg9a43e252013-10-20 19:00:07 +03001154 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001155
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001156 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001157 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1158 MGMT_STATUS_INVALID_PARAMS);
1159
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001160 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001161
1162 /* Disabling discoverable requires that no timeout is set,
1163 * and enabling limited discoverable requires a timeout.
1164 */
1165 if ((cp->val == 0x00 && timeout > 0) ||
1166 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001167 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001168 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001169
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001170 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001171
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001172 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001173 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001174 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001175 goto failed;
1176 }
1177
1178 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001179 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001180 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001181 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001182 goto failed;
1183 }
1184
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001185 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001186 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001187 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001188 goto failed;
1189 }
1190
1191 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001192 bool changed = false;
1193
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001194 /* Setting limited discoverable when powered off is
1195 * not a valid operation since it requires a timeout
1196 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1197 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001198 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1199 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1200 changed = true;
1201 }
1202
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001203 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001204 if (err < 0)
1205 goto failed;
1206
1207 if (changed)
1208 err = new_settings(hdev, sk);
1209
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001210 goto failed;
1211 }
1212
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001213 /* If the current mode is the same, then just update the timeout
1214 * value with the new value. And if only the timeout gets updated,
1215 * then no need for any HCI transactions.
1216 */
1217 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1218 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1219 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001220 cancel_delayed_work(&hdev->discov_off);
1221 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001222
Marcel Holtmann36261542013-10-15 08:28:51 -07001223 if (cp->val && hdev->discov_timeout > 0) {
1224 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001225 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001226 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001227 }
1228
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001229 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001230 goto failed;
1231 }
1232
1233 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1234 if (!cmd) {
1235 err = -ENOMEM;
1236 goto failed;
1237 }
1238
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001239 /* Cancel any potential discoverable timeout that might be
1240 * still active and store new timeout value. The arming of
1241 * the timeout happens in the complete handler.
1242 */
1243 cancel_delayed_work(&hdev->discov_off);
1244 hdev->discov_timeout = timeout;
1245
Johan Hedbergb456f872013-10-19 23:38:22 +03001246 /* Limited discoverable mode */
1247 if (cp->val == 0x02)
1248 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1249 else
1250 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1251
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001252 hci_req_init(&req, hdev);
1253
Johan Hedberg9a43e252013-10-20 19:00:07 +03001254 /* The procedure for LE-only controllers is much simpler - just
1255 * update the advertising data.
1256 */
1257 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1258 goto update_ad;
1259
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001260 scan = SCAN_PAGE;
1261
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001262 if (cp->val) {
1263 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001264
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001265 if (cp->val == 0x02) {
1266 /* Limited discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001267 hci_cp.num_iac = 2;
1268 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1269 hci_cp.iac_lap[1] = 0x8b;
1270 hci_cp.iac_lap[2] = 0x9e;
1271 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1272 hci_cp.iac_lap[4] = 0x8b;
1273 hci_cp.iac_lap[5] = 0x9e;
1274 } else {
1275 /* General discoverable mode */
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001276 hci_cp.num_iac = 1;
1277 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1278 hci_cp.iac_lap[1] = 0x8b;
1279 hci_cp.iac_lap[2] = 0x9e;
1280 }
1281
1282 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1283 (hci_cp.num_iac * 3) + 1, &hci_cp);
1284
1285 scan |= SCAN_INQUIRY;
1286 } else {
1287 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1288 }
1289
1290 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001291
Johan Hedberg9a43e252013-10-20 19:00:07 +03001292update_ad:
1293 update_adv_data(&req);
1294
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001295 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001296 if (err < 0)
1297 mgmt_pending_remove(cmd);
1298
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001299failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001300 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001301 return err;
1302}
1303
Johan Hedberg406d7802013-03-15 17:07:09 -05001304static void write_fast_connectable(struct hci_request *req, bool enable)
1305{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001306 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001307 struct hci_cp_write_page_scan_activity acp;
1308 u8 type;
1309
Johan Hedberg547003b2013-10-21 16:51:53 +03001310 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1311 return;
1312
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001313 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1314 return;
1315
Johan Hedberg406d7802013-03-15 17:07:09 -05001316 if (enable) {
1317 type = PAGE_SCAN_TYPE_INTERLACED;
1318
1319 /* 160 msec page scan interval */
1320 acp.interval = __constant_cpu_to_le16(0x0100);
1321 } else {
1322 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1323
1324 /* default 1.28 sec page scan */
1325 acp.interval = __constant_cpu_to_le16(0x0800);
1326 }
1327
1328 acp.window = __constant_cpu_to_le16(0x0012);
1329
Johan Hedbergbd98b992013-03-15 17:07:13 -05001330 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1331 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1332 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1333 sizeof(acp), &acp);
1334
1335 if (hdev->page_scan_type != type)
1336 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001337}
1338
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001339static u8 get_adv_type(struct hci_dev *hdev)
1340{
1341 struct pending_cmd *cmd;
1342 bool connectable;
1343
1344 /* If there's a pending mgmt command the flag will not yet have
1345 * it's final value, so check for this first.
1346 */
1347 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1348 if (cmd) {
1349 struct mgmt_mode *cp = cmd->param;
1350 connectable = !!cp->val;
1351 } else {
1352 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1353 }
1354
1355 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1356}
1357
Johan Hedberg95c66e72013-10-14 16:20:06 +03001358static void enable_advertising(struct hci_request *req)
1359{
1360 struct hci_dev *hdev = req->hdev;
1361 struct hci_cp_le_set_adv_param cp;
1362 u8 enable = 0x01;
1363
1364 memset(&cp, 0, sizeof(cp));
1365 cp.min_interval = __constant_cpu_to_le16(0x0800);
1366 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001367 cp.type = get_adv_type(hdev);
Marcel Holtmann79830f62013-10-18 16:38:09 -07001368 cp.own_address_type = hdev->own_addr_type;
Johan Hedberg95c66e72013-10-14 16:20:06 +03001369 cp.channel_map = 0x07;
1370
1371 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1372
1373 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1374}
1375
1376static void disable_advertising(struct hci_request *req)
1377{
1378 u8 enable = 0x00;
1379
1380 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1381}
1382
Johan Hedberg2b76f452013-03-15 17:07:04 -05001383static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1384{
1385 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001386 struct mgmt_mode *cp;
1387 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001388
1389 BT_DBG("status 0x%02x", status);
1390
1391 hci_dev_lock(hdev);
1392
1393 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1394 if (!cmd)
1395 goto unlock;
1396
Johan Hedberg37438c12013-10-14 16:20:05 +03001397 if (status) {
1398 u8 mgmt_err = mgmt_status(status);
1399 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1400 goto remove_cmd;
1401 }
1402
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001403 cp = cmd->param;
1404 if (cp->val)
1405 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1406 else
1407 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1408
Johan Hedberg2b76f452013-03-15 17:07:04 -05001409 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1410
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001411 if (changed)
1412 new_settings(hdev, cmd->sk);
1413
Johan Hedberg37438c12013-10-14 16:20:05 +03001414remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001415 mgmt_pending_remove(cmd);
1416
1417unlock:
1418 hci_dev_unlock(hdev);
1419}
1420
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001421static int set_connectable_update_settings(struct hci_dev *hdev,
1422 struct sock *sk, u8 val)
1423{
1424 bool changed = false;
1425 int err;
1426
1427 if (!!val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1428 changed = true;
1429
1430 if (val) {
1431 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1432 } else {
1433 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1434 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1435 }
1436
1437 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
1438 if (err < 0)
1439 return err;
1440
1441 if (changed)
1442 return new_settings(hdev, sk);
1443
1444 return 0;
1445}
1446
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001447static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001448 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001449{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001450 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001451 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001452 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001453 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001454 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001455
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001456 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001457
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001458 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1459 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001460 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001461 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001462
Johan Hedberga7e80f22013-01-09 16:05:19 +02001463 if (cp->val != 0x00 && cp->val != 0x01)
1464 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1465 MGMT_STATUS_INVALID_PARAMS);
1466
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001467 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001468
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001469 if (!hdev_is_powered(hdev)) {
Johan Hedberge8ba3a12013-10-19 23:38:18 +03001470 err = set_connectable_update_settings(hdev, sk, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001471 goto failed;
1472 }
1473
1474 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001475 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001476 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001477 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001478 goto failed;
1479 }
1480
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001481 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1482 if (!cmd) {
1483 err = -ENOMEM;
1484 goto failed;
1485 }
1486
Johan Hedberg2b76f452013-03-15 17:07:04 -05001487 hci_req_init(&req, hdev);
1488
Johan Hedberg9a43e252013-10-20 19:00:07 +03001489 /* If BR/EDR is not enabled and we disable advertising as a
1490 * by-product of disabling connectable, we need to update the
1491 * advertising flags.
1492 */
1493 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
1494 if (!cp->val) {
1495 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1496 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1497 }
1498 update_adv_data(&req);
1499 } else if (cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001500 if (cp->val) {
1501 scan = SCAN_PAGE;
1502 } else {
1503 scan = 0;
1504
1505 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001506 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001507 cancel_delayed_work(&hdev->discov_off);
1508 }
1509
1510 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1511 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001512
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001513 /* If we're going from non-connectable to connectable or
1514 * vice-versa when fast connectable is enabled ensure that fast
1515 * connectable gets disabled. write_fast_connectable won't do
1516 * anything if the page scan parameters are already what they
1517 * should be.
1518 */
1519 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001520 write_fast_connectable(&req, false);
1521
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001522 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1523 hci_conn_num(hdev, LE_LINK) == 0) {
1524 disable_advertising(&req);
1525 enable_advertising(&req);
1526 }
1527
Johan Hedberg2b76f452013-03-15 17:07:04 -05001528 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001529 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001530 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001531 if (err == -ENODATA)
Johan Hedberga81070b2013-10-19 23:38:19 +03001532 err = set_connectable_update_settings(hdev, sk,
1533 cp->val);
Johan Hedberg9b742462013-10-14 16:20:03 +03001534 goto failed;
1535 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001536
1537failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001538 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001539 return err;
1540}
1541
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001542static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001543 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001544{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001545 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001546 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001547 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001549 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001550
Johan Hedberga7e80f22013-01-09 16:05:19 +02001551 if (cp->val != 0x00 && cp->val != 0x01)
1552 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1553 MGMT_STATUS_INVALID_PARAMS);
1554
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001555 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001556
1557 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001558 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001559 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001560 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001561
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001562 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001563 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001564 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001565
Marcel Holtmann55594352013-10-06 16:11:57 -07001566 if (changed)
1567 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001568
Marcel Holtmann55594352013-10-06 16:11:57 -07001569unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001570 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001571 return err;
1572}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001573
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001574static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1575 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001576{
1577 struct mgmt_mode *cp = data;
1578 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001579 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001580 int err;
1581
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001582 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001583
Johan Hedberge6fe7982013-10-02 15:45:22 +03001584 status = mgmt_bredr_support(hdev);
1585 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001586 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001587 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001588
Johan Hedberga7e80f22013-01-09 16:05:19 +02001589 if (cp->val != 0x00 && cp->val != 0x01)
1590 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1591 MGMT_STATUS_INVALID_PARAMS);
1592
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001593 hci_dev_lock(hdev);
1594
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001595 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001596 bool changed = false;
1597
1598 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001599 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001600 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1601 changed = true;
1602 }
1603
1604 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1605 if (err < 0)
1606 goto failed;
1607
1608 if (changed)
1609 err = new_settings(hdev, sk);
1610
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001611 goto failed;
1612 }
1613
1614 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001615 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001616 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001617 goto failed;
1618 }
1619
1620 val = !!cp->val;
1621
1622 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1623 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1624 goto failed;
1625 }
1626
1627 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1628 if (!cmd) {
1629 err = -ENOMEM;
1630 goto failed;
1631 }
1632
1633 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1634 if (err < 0) {
1635 mgmt_pending_remove(cmd);
1636 goto failed;
1637 }
1638
1639failed:
1640 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001641 return err;
1642}
1643
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001644static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001645{
1646 struct mgmt_mode *cp = data;
1647 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001648 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001649 int err;
1650
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001651 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001652
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001653 status = mgmt_bredr_support(hdev);
1654 if (status)
1655 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1656
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001657 if (!lmp_ssp_capable(hdev))
1658 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1659 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001660
Johan Hedberga7e80f22013-01-09 16:05:19 +02001661 if (cp->val != 0x00 && cp->val != 0x01)
1662 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1663 MGMT_STATUS_INVALID_PARAMS);
1664
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001665 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001666
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001667 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001668 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001669
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001670 if (cp->val) {
1671 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1672 &hdev->dev_flags);
1673 } else {
1674 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1675 &hdev->dev_flags);
1676 if (!changed)
1677 changed = test_and_clear_bit(HCI_HS_ENABLED,
1678 &hdev->dev_flags);
1679 else
1680 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001681 }
1682
1683 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1684 if (err < 0)
1685 goto failed;
1686
1687 if (changed)
1688 err = new_settings(hdev, sk);
1689
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001690 goto failed;
1691 }
1692
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001693 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1694 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001695 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1696 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001697 goto failed;
1698 }
1699
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001700 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001701 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1702 goto failed;
1703 }
1704
1705 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1706 if (!cmd) {
1707 err = -ENOMEM;
1708 goto failed;
1709 }
1710
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001711 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001712 if (err < 0) {
1713 mgmt_pending_remove(cmd);
1714 goto failed;
1715 }
1716
1717failed:
1718 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001719 return err;
1720}
1721
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001722static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001723{
1724 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001725 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001726 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001727 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001728
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001729 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001730
Johan Hedberge6fe7982013-10-02 15:45:22 +03001731 status = mgmt_bredr_support(hdev);
1732 if (status)
1733 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001734
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001735 if (!lmp_ssp_capable(hdev))
1736 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1737 MGMT_STATUS_NOT_SUPPORTED);
1738
1739 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1740 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1741 MGMT_STATUS_REJECTED);
1742
Johan Hedberga7e80f22013-01-09 16:05:19 +02001743 if (cp->val != 0x00 && cp->val != 0x01)
1744 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1745 MGMT_STATUS_INVALID_PARAMS);
1746
Marcel Holtmannee392692013-10-01 22:59:23 -07001747 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001748
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001749 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001750 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001751 } else {
1752 if (hdev_is_powered(hdev)) {
1753 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1754 MGMT_STATUS_REJECTED);
1755 goto unlock;
1756 }
1757
Marcel Holtmannee392692013-10-01 22:59:23 -07001758 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001759 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001760
1761 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1762 if (err < 0)
1763 goto unlock;
1764
1765 if (changed)
1766 err = new_settings(hdev, sk);
1767
1768unlock:
1769 hci_dev_unlock(hdev);
1770 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001771}
1772
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001773static void le_enable_complete(struct hci_dev *hdev, u8 status)
1774{
1775 struct cmd_lookup match = { NULL, hdev };
1776
1777 if (status) {
1778 u8 mgmt_err = mgmt_status(status);
1779
1780 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1781 &mgmt_err);
1782 return;
1783 }
1784
1785 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1786
1787 new_settings(hdev, match.sk);
1788
1789 if (match.sk)
1790 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001791
1792 /* Make sure the controller has a good default for
1793 * advertising data. Restrict the update to when LE
1794 * has actually been enabled. During power on, the
1795 * update in powered_update_hci will take care of it.
1796 */
1797 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1798 struct hci_request req;
1799
1800 hci_dev_lock(hdev);
1801
1802 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001803 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001804 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001805 hci_req_run(&req, NULL);
1806
1807 hci_dev_unlock(hdev);
1808 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001809}
1810
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001811static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001812{
1813 struct mgmt_mode *cp = data;
1814 struct hci_cp_write_le_host_supported hci_cp;
1815 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001816 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001817 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001818 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001819
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001820 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001821
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001822 if (!lmp_le_capable(hdev))
1823 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1824 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001825
Johan Hedberga7e80f22013-01-09 16:05:19 +02001826 if (cp->val != 0x00 && cp->val != 0x01)
1827 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1828 MGMT_STATUS_INVALID_PARAMS);
1829
Johan Hedbergc73eee92013-04-19 18:35:21 +03001830 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001831 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001832 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1833 MGMT_STATUS_REJECTED);
1834
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001835 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001836
1837 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001838 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001839
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001840 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001841 bool changed = false;
1842
1843 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1844 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1845 changed = true;
1846 }
1847
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001848 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1849 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001850 changed = true;
1851 }
1852
Johan Hedberg06199cf2012-02-22 16:37:11 +02001853 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1854 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001855 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001856
1857 if (changed)
1858 err = new_settings(hdev, sk);
1859
Johan Hedberg1de028c2012-02-29 19:55:35 -08001860 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001861 }
1862
Johan Hedberg4375f102013-09-25 13:26:10 +03001863 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1864 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001865 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001866 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001867 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001868 }
1869
1870 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1871 if (!cmd) {
1872 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001873 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001874 }
1875
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001876 hci_req_init(&req, hdev);
1877
Johan Hedberg06199cf2012-02-22 16:37:11 +02001878 memset(&hci_cp, 0, sizeof(hci_cp));
1879
1880 if (val) {
1881 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001882 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001883 } else {
1884 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1885 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001886 }
1887
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001888 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1889 &hci_cp);
1890
1891 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301892 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001893 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001894
Johan Hedberg1de028c2012-02-29 19:55:35 -08001895unlock:
1896 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001897 return err;
1898}
1899
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001900/* This is a helper function to test for pending mgmt commands that can
1901 * cause CoD or EIR HCI commands. We can only allow one such pending
1902 * mgmt command at a time since otherwise we cannot easily track what
1903 * the current values are, will be, and based on that calculate if a new
1904 * HCI command needs to be sent and if yes with what value.
1905 */
1906static bool pending_eir_or_class(struct hci_dev *hdev)
1907{
1908 struct pending_cmd *cmd;
1909
1910 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1911 switch (cmd->opcode) {
1912 case MGMT_OP_ADD_UUID:
1913 case MGMT_OP_REMOVE_UUID:
1914 case MGMT_OP_SET_DEV_CLASS:
1915 case MGMT_OP_SET_POWERED:
1916 return true;
1917 }
1918 }
1919
1920 return false;
1921}
1922
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001923static const u8 bluetooth_base_uuid[] = {
1924 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1925 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1926};
1927
1928static u8 get_uuid_size(const u8 *uuid)
1929{
1930 u32 val;
1931
1932 if (memcmp(uuid, bluetooth_base_uuid, 12))
1933 return 128;
1934
1935 val = get_unaligned_le32(&uuid[12]);
1936 if (val > 0xffff)
1937 return 32;
1938
1939 return 16;
1940}
1941
Johan Hedberg92da6092013-03-15 17:06:55 -05001942static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1943{
1944 struct pending_cmd *cmd;
1945
1946 hci_dev_lock(hdev);
1947
1948 cmd = mgmt_pending_find(mgmt_op, hdev);
1949 if (!cmd)
1950 goto unlock;
1951
1952 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1953 hdev->dev_class, 3);
1954
1955 mgmt_pending_remove(cmd);
1956
1957unlock:
1958 hci_dev_unlock(hdev);
1959}
1960
1961static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1962{
1963 BT_DBG("status 0x%02x", status);
1964
1965 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1966}
1967
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001968static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001969{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001970 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001971 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001972 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001973 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001974 int err;
1975
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001976 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001977
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001978 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001979
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001980 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001981 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001982 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001983 goto failed;
1984 }
1985
Andre Guedes92c4c202012-06-07 19:05:44 -03001986 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001987 if (!uuid) {
1988 err = -ENOMEM;
1989 goto failed;
1990 }
1991
1992 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001993 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001994 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001995
Johan Hedbergde66aa62013-01-27 00:31:27 +02001996 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001997
Johan Hedberg890ea892013-03-15 17:06:52 -05001998 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001999
Johan Hedberg890ea892013-03-15 17:06:52 -05002000 update_class(&req);
2001 update_eir(&req);
2002
Johan Hedberg92da6092013-03-15 17:06:55 -05002003 err = hci_req_run(&req, add_uuid_complete);
2004 if (err < 0) {
2005 if (err != -ENODATA)
2006 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002007
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002008 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002009 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002010 goto failed;
2011 }
2012
2013 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002014 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002015 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002016 goto failed;
2017 }
2018
2019 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002020
2021failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002022 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002023 return err;
2024}
2025
Johan Hedberg24b78d02012-02-23 23:24:30 +02002026static bool enable_service_cache(struct hci_dev *hdev)
2027{
2028 if (!hdev_is_powered(hdev))
2029 return false;
2030
2031 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02002032 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
2033 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002034 return true;
2035 }
2036
2037 return false;
2038}
2039
Johan Hedberg92da6092013-03-15 17:06:55 -05002040static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
2041{
2042 BT_DBG("status 0x%02x", status);
2043
2044 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
2045}
2046
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002047static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002048 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002049{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002050 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002051 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02002052 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002053 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 -05002054 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002055 int err, found;
2056
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002057 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002058
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002059 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002060
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002061 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002062 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002063 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002064 goto unlock;
2065 }
2066
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002067 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
2068 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002069
Johan Hedberg24b78d02012-02-23 23:24:30 +02002070 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002071 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002072 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002073 goto unlock;
2074 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002075
Johan Hedberg9246a862012-02-23 21:33:16 +02002076 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002077 }
2078
2079 found = 0;
2080
Johan Hedberg056341c2013-01-27 00:31:30 +02002081 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002082 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2083 continue;
2084
2085 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002086 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002087 found++;
2088 }
2089
2090 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002091 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002092 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002093 goto unlock;
2094 }
2095
Johan Hedberg9246a862012-02-23 21:33:16 +02002096update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002097 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002098
Johan Hedberg890ea892013-03-15 17:06:52 -05002099 update_class(&req);
2100 update_eir(&req);
2101
Johan Hedberg92da6092013-03-15 17:06:55 -05002102 err = hci_req_run(&req, remove_uuid_complete);
2103 if (err < 0) {
2104 if (err != -ENODATA)
2105 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002106
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002107 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002108 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002109 goto unlock;
2110 }
2111
2112 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002113 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002114 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002115 goto unlock;
2116 }
2117
2118 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002119
2120unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002121 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002122 return err;
2123}
2124
Johan Hedberg92da6092013-03-15 17:06:55 -05002125static void set_class_complete(struct hci_dev *hdev, u8 status)
2126{
2127 BT_DBG("status 0x%02x", status);
2128
2129 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2130}
2131
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002132static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002133 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002134{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002135 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002136 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002137 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002138 int err;
2139
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002140 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002141
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002142 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002143 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2144 MGMT_STATUS_NOT_SUPPORTED);
2145
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002146 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002147
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002148 if (pending_eir_or_class(hdev)) {
2149 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2150 MGMT_STATUS_BUSY);
2151 goto unlock;
2152 }
2153
2154 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2155 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2156 MGMT_STATUS_INVALID_PARAMS);
2157 goto unlock;
2158 }
2159
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002160 hdev->major_class = cp->major;
2161 hdev->minor_class = cp->minor;
2162
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002163 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002164 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002165 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002166 goto unlock;
2167 }
2168
Johan Hedberg890ea892013-03-15 17:06:52 -05002169 hci_req_init(&req, hdev);
2170
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002171 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002172 hci_dev_unlock(hdev);
2173 cancel_delayed_work_sync(&hdev->service_cache);
2174 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002175 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002176 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002177
Johan Hedberg890ea892013-03-15 17:06:52 -05002178 update_class(&req);
2179
Johan Hedberg92da6092013-03-15 17:06:55 -05002180 err = hci_req_run(&req, set_class_complete);
2181 if (err < 0) {
2182 if (err != -ENODATA)
2183 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002184
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002185 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002186 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002187 goto unlock;
2188 }
2189
2190 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002191 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002192 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002193 goto unlock;
2194 }
2195
2196 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002197
Johan Hedbergb5235a62012-02-21 14:32:24 +02002198unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002199 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002200 return err;
2201}
2202
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002203static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002204 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002205{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002206 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002207 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002208 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002209
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002210 BT_DBG("request for %s", hdev->name);
2211
2212 if (!lmp_bredr_capable(hdev))
2213 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2214 MGMT_STATUS_NOT_SUPPORTED);
2215
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002216 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002217
Johan Hedberg86742e12011-11-07 23:13:38 +02002218 expected_len = sizeof(*cp) + key_count *
2219 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002220 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002221 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002222 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002223 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002224 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002225 }
2226
Johan Hedberg4ae14302013-01-20 14:27:13 +02002227 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2228 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2229 MGMT_STATUS_INVALID_PARAMS);
2230
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002231 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002232 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002233
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002234 for (i = 0; i < key_count; i++) {
2235 struct mgmt_link_key_info *key = &cp->keys[i];
2236
2237 if (key->addr.type != BDADDR_BREDR)
2238 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2239 MGMT_STATUS_INVALID_PARAMS);
2240 }
2241
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002242 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002243
2244 hci_link_keys_clear(hdev);
2245
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002246 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002247 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002248 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002249 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002250
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002251 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002252 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002253
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002254 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002255 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002256 }
2257
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002258 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002259
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002260 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002261
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002262 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002263}
2264
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002265static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002266 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002267{
2268 struct mgmt_ev_device_unpaired ev;
2269
2270 bacpy(&ev.addr.bdaddr, bdaddr);
2271 ev.addr.type = addr_type;
2272
2273 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002274 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002275}
2276
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002277static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002278 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002279{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002280 struct mgmt_cp_unpair_device *cp = data;
2281 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002282 struct hci_cp_disconnect dc;
2283 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002284 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002285 int err;
2286
Johan Hedberga8a1d192011-11-10 15:54:38 +02002287 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002288 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2289 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002290
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002291 if (!bdaddr_type_is_valid(cp->addr.type))
2292 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2293 MGMT_STATUS_INVALID_PARAMS,
2294 &rp, sizeof(rp));
2295
Johan Hedberg118da702013-01-20 14:27:20 +02002296 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2297 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2298 MGMT_STATUS_INVALID_PARAMS,
2299 &rp, sizeof(rp));
2300
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002301 hci_dev_lock(hdev);
2302
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002303 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002304 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002305 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002306 goto unlock;
2307 }
2308
Andre Guedes591f47f2012-04-24 21:02:49 -03002309 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002310 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2311 else
2312 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002313
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002314 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002315 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002316 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002317 goto unlock;
2318 }
2319
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002320 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002321 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002322 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002323 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002324 else
2325 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002326 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002327 } else {
2328 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002329 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002330
Johan Hedberga8a1d192011-11-10 15:54:38 +02002331 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002332 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002333 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002334 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002335 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002336 }
2337
Johan Hedberg124f6e32012-02-09 13:50:12 +02002338 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002339 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002340 if (!cmd) {
2341 err = -ENOMEM;
2342 goto unlock;
2343 }
2344
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002345 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002346 dc.reason = 0x13; /* Remote User Terminated Connection */
2347 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2348 if (err < 0)
2349 mgmt_pending_remove(cmd);
2350
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002351unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002352 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002353 return err;
2354}
2355
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002356static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002357 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002358{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002359 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002360 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002361 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002362 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002363 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002364 int err;
2365
2366 BT_DBG("");
2367
Johan Hedberg06a63b12013-01-20 14:27:21 +02002368 memset(&rp, 0, sizeof(rp));
2369 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2370 rp.addr.type = cp->addr.type;
2371
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002372 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002373 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2374 MGMT_STATUS_INVALID_PARAMS,
2375 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002376
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002377 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002378
2379 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002380 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2381 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002382 goto failed;
2383 }
2384
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002385 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002386 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2387 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002388 goto failed;
2389 }
2390
Andre Guedes591f47f2012-04-24 21:02:49 -03002391 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002392 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2393 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002394 else
2395 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002396
Vishal Agarwalf9607272012-06-13 05:32:43 +05302397 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002398 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2399 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002400 goto failed;
2401 }
2402
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002403 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002404 if (!cmd) {
2405 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002406 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002407 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002408
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002409 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002410 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002411
2412 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2413 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002414 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002415
2416failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002417 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002418 return err;
2419}
2420
Andre Guedes57c14772012-04-24 21:02:50 -03002421static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002422{
2423 switch (link_type) {
2424 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002425 switch (addr_type) {
2426 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002427 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002428
Johan Hedberg48264f02011-11-09 13:58:58 +02002429 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002430 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002431 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002432 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002433
Johan Hedberg4c659c32011-11-07 23:13:39 +02002434 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002435 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002436 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002437 }
2438}
2439
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002440static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2441 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002442{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002443 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002444 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002445 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002446 int err;
2447 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002448
2449 BT_DBG("");
2450
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002451 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002452
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002453 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002454 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002455 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002456 goto unlock;
2457 }
2458
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002459 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002460 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2461 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002462 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002463 }
2464
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002465 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002466 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002467 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002468 err = -ENOMEM;
2469 goto unlock;
2470 }
2471
Johan Hedberg2784eb42011-01-21 13:56:35 +02002472 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002473 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002474 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2475 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002476 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002477 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002478 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002479 continue;
2480 i++;
2481 }
2482
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002483 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002484
Johan Hedberg4c659c32011-11-07 23:13:39 +02002485 /* Recalculate length in case of filtered SCO connections, etc */
2486 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002487
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002488 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002489 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002490
Johan Hedberga38528f2011-01-22 06:46:43 +02002491 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002492
2493unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002494 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002495 return err;
2496}
2497
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002498static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002499 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002500{
2501 struct pending_cmd *cmd;
2502 int err;
2503
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002504 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002505 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002506 if (!cmd)
2507 return -ENOMEM;
2508
Johan Hedbergd8457692012-02-17 14:24:57 +02002509 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002510 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002511 if (err < 0)
2512 mgmt_pending_remove(cmd);
2513
2514 return err;
2515}
2516
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002517static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002518 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002519{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002520 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002521 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002522 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002523 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002524 int err;
2525
2526 BT_DBG("");
2527
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002528 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002529
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002530 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002531 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002532 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002533 goto failed;
2534 }
2535
Johan Hedbergd8457692012-02-17 14:24:57 +02002536 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002537 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002538 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002539 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002540 goto failed;
2541 }
2542
2543 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002544 struct mgmt_cp_pin_code_neg_reply ncp;
2545
2546 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002547
2548 BT_ERR("PIN code is not 16 bytes long");
2549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002550 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002551 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002552 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002553 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002554
2555 goto failed;
2556 }
2557
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002558 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002559 if (!cmd) {
2560 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002561 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002562 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002563
Johan Hedbergd8457692012-02-17 14:24:57 +02002564 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002565 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002566 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002567
2568 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2569 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002570 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002571
2572failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002573 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002574 return err;
2575}
2576
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002577static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2578 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002579{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002580 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002581
2582 BT_DBG("");
2583
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002584 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002585
2586 hdev->io_capability = cp->io_capability;
2587
2588 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002589 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002590
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002591 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002592
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002593 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2594 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002595}
2596
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002597static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002598{
2599 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002600 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002601
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002602 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002603 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2604 continue;
2605
Johan Hedberge9a416b2011-02-19 12:05:56 -03002606 if (cmd->user_data != conn)
2607 continue;
2608
2609 return cmd;
2610 }
2611
2612 return NULL;
2613}
2614
2615static void pairing_complete(struct pending_cmd *cmd, u8 status)
2616{
2617 struct mgmt_rp_pair_device rp;
2618 struct hci_conn *conn = cmd->user_data;
2619
Johan Hedbergba4e5642011-11-11 00:07:34 +02002620 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002621 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002622
Johan Hedbergaee9b212012-02-18 15:07:59 +02002623 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002624 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002625
2626 /* So we don't get further callbacks for this connection */
2627 conn->connect_cfm_cb = NULL;
2628 conn->security_cfm_cb = NULL;
2629 conn->disconn_cfm_cb = NULL;
2630
David Herrmann76a68ba2013-04-06 20:28:37 +02002631 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002632
Johan Hedberga664b5b2011-02-19 12:06:02 -03002633 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002634}
2635
2636static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2637{
2638 struct pending_cmd *cmd;
2639
2640 BT_DBG("status %u", status);
2641
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002642 cmd = find_pairing(conn);
2643 if (!cmd)
2644 BT_DBG("Unable to find a pending command");
2645 else
Johan Hedberge2113262012-02-18 15:20:03 +02002646 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002647}
2648
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302649static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2650{
2651 struct pending_cmd *cmd;
2652
2653 BT_DBG("status %u", status);
2654
2655 if (!status)
2656 return;
2657
2658 cmd = find_pairing(conn);
2659 if (!cmd)
2660 BT_DBG("Unable to find a pending command");
2661 else
2662 pairing_complete(cmd, mgmt_status(status));
2663}
2664
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002665static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002666 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002667{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002668 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002669 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002670 struct pending_cmd *cmd;
2671 u8 sec_level, auth_type;
2672 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002673 int err;
2674
2675 BT_DBG("");
2676
Szymon Jancf950a30e2013-01-18 12:48:07 +01002677 memset(&rp, 0, sizeof(rp));
2678 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2679 rp.addr.type = cp->addr.type;
2680
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002681 if (!bdaddr_type_is_valid(cp->addr.type))
2682 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2683 MGMT_STATUS_INVALID_PARAMS,
2684 &rp, sizeof(rp));
2685
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002686 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002687
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002688 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002689 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2690 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002691 goto unlock;
2692 }
2693
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002694 sec_level = BT_SECURITY_MEDIUM;
2695 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002696 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002697 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002698 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002699
Andre Guedes591f47f2012-04-24 21:02:49 -03002700 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002701 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2702 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002703 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002704 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2705 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002706
Ville Tervo30e76272011-02-22 16:10:53 -03002707 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002708 int status;
2709
2710 if (PTR_ERR(conn) == -EBUSY)
2711 status = MGMT_STATUS_BUSY;
2712 else
2713 status = MGMT_STATUS_CONNECT_FAILED;
2714
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002715 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002716 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002717 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002718 goto unlock;
2719 }
2720
2721 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002722 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002723 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002724 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002725 goto unlock;
2726 }
2727
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002728 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002729 if (!cmd) {
2730 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002731 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002732 goto unlock;
2733 }
2734
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002735 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002736 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002737 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302738 else
2739 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002740
Johan Hedberge9a416b2011-02-19 12:05:56 -03002741 conn->security_cfm_cb = pairing_complete_cb;
2742 conn->disconn_cfm_cb = pairing_complete_cb;
2743 conn->io_capability = cp->io_cap;
2744 cmd->user_data = conn;
2745
2746 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002747 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002748 pairing_complete(cmd, 0);
2749
2750 err = 0;
2751
2752unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002753 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002754 return err;
2755}
2756
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002757static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2758 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002759{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002760 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002761 struct pending_cmd *cmd;
2762 struct hci_conn *conn;
2763 int err;
2764
2765 BT_DBG("");
2766
Johan Hedberg28424702012-02-02 04:02:29 +02002767 hci_dev_lock(hdev);
2768
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002769 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002770 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002771 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002772 goto unlock;
2773 }
2774
Johan Hedberg28424702012-02-02 04:02:29 +02002775 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2776 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002777 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002778 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002779 goto unlock;
2780 }
2781
2782 conn = cmd->user_data;
2783
2784 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002785 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002786 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002787 goto unlock;
2788 }
2789
2790 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2791
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002792 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002793 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002794unlock:
2795 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002796 return err;
2797}
2798
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002799static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002800 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002801 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002802{
Johan Hedberga5c29682011-02-19 12:05:57 -03002803 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002804 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002805 int err;
2806
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002807 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002808
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002809 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002810 err = cmd_complete(sk, hdev->id, mgmt_op,
2811 MGMT_STATUS_NOT_POWERED, addr,
2812 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002813 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002814 }
2815
Johan Hedberg1707c602013-03-15 17:07:15 -05002816 if (addr->type == BDADDR_BREDR)
2817 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002818 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002819 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002820
Johan Hedberg272d90d2012-02-09 15:26:12 +02002821 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002822 err = cmd_complete(sk, hdev->id, mgmt_op,
2823 MGMT_STATUS_NOT_CONNECTED, addr,
2824 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002825 goto done;
2826 }
2827
Johan Hedberg1707c602013-03-15 17:07:15 -05002828 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002829 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002830 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002831
Brian Gix5fe57d92011-12-21 16:12:13 -08002832 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002833 err = cmd_complete(sk, hdev->id, mgmt_op,
2834 MGMT_STATUS_SUCCESS, addr,
2835 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002836 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002837 err = cmd_complete(sk, hdev->id, mgmt_op,
2838 MGMT_STATUS_FAILED, addr,
2839 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002840
Brian Gix47c15e22011-11-16 13:53:14 -08002841 goto done;
2842 }
2843
Johan Hedberg1707c602013-03-15 17:07:15 -05002844 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002845 if (!cmd) {
2846 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002847 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002848 }
2849
Brian Gix0df4c182011-11-16 13:53:13 -08002850 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002851 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2852 struct hci_cp_user_passkey_reply cp;
2853
Johan Hedberg1707c602013-03-15 17:07:15 -05002854 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002855 cp.passkey = passkey;
2856 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2857 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002858 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2859 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002860
Johan Hedberga664b5b2011-02-19 12:06:02 -03002861 if (err < 0)
2862 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002863
Brian Gix0df4c182011-11-16 13:53:13 -08002864done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002865 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002866 return err;
2867}
2868
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302869static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2870 void *data, u16 len)
2871{
2872 struct mgmt_cp_pin_code_neg_reply *cp = data;
2873
2874 BT_DBG("");
2875
Johan Hedberg1707c602013-03-15 17:07:15 -05002876 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302877 MGMT_OP_PIN_CODE_NEG_REPLY,
2878 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2879}
2880
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002881static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2882 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002883{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002884 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002885
2886 BT_DBG("");
2887
2888 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002889 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002890 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002891
Johan Hedberg1707c602013-03-15 17:07:15 -05002892 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002893 MGMT_OP_USER_CONFIRM_REPLY,
2894 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002895}
2896
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002897static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002898 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002899{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002900 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002901
2902 BT_DBG("");
2903
Johan Hedberg1707c602013-03-15 17:07:15 -05002904 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002905 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2906 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002907}
2908
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002909static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2910 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002911{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002912 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002913
2914 BT_DBG("");
2915
Johan Hedberg1707c602013-03-15 17:07:15 -05002916 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002917 MGMT_OP_USER_PASSKEY_REPLY,
2918 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002919}
2920
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002921static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002922 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002923{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002924 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002925
2926 BT_DBG("");
2927
Johan Hedberg1707c602013-03-15 17:07:15 -05002928 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002929 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2930 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002931}
2932
Johan Hedberg13928972013-03-15 17:07:00 -05002933static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002934{
Johan Hedberg13928972013-03-15 17:07:00 -05002935 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002936 struct hci_cp_write_local_name cp;
2937
Johan Hedberg13928972013-03-15 17:07:00 -05002938 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002939
Johan Hedberg890ea892013-03-15 17:06:52 -05002940 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002941}
2942
Johan Hedberg13928972013-03-15 17:07:00 -05002943static void set_name_complete(struct hci_dev *hdev, u8 status)
2944{
2945 struct mgmt_cp_set_local_name *cp;
2946 struct pending_cmd *cmd;
2947
2948 BT_DBG("status 0x%02x", status);
2949
2950 hci_dev_lock(hdev);
2951
2952 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2953 if (!cmd)
2954 goto unlock;
2955
2956 cp = cmd->param;
2957
2958 if (status)
2959 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2960 mgmt_status(status));
2961 else
2962 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2963 cp, sizeof(*cp));
2964
2965 mgmt_pending_remove(cmd);
2966
2967unlock:
2968 hci_dev_unlock(hdev);
2969}
2970
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002971static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002972 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002973{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002974 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002975 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002976 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002977 int err;
2978
2979 BT_DBG("");
2980
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002981 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002982
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002983 /* If the old values are the same as the new ones just return a
2984 * direct command complete event.
2985 */
2986 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2987 !memcmp(hdev->short_name, cp->short_name,
2988 sizeof(hdev->short_name))) {
2989 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2990 data, len);
2991 goto failed;
2992 }
2993
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002994 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002995
Johan Hedbergb5235a62012-02-21 14:32:24 +02002996 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002997 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002998
2999 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003000 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003001 if (err < 0)
3002 goto failed;
3003
3004 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003005 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003006
Johan Hedbergb5235a62012-02-21 14:32:24 +02003007 goto failed;
3008 }
3009
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003010 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003011 if (!cmd) {
3012 err = -ENOMEM;
3013 goto failed;
3014 }
3015
Johan Hedberg13928972013-03-15 17:07:00 -05003016 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
3017
Johan Hedberg890ea892013-03-15 17:06:52 -05003018 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05003019
3020 if (lmp_bredr_capable(hdev)) {
3021 update_name(&req);
3022 update_eir(&req);
3023 }
3024
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003025 /* The name is stored in the scan response data and so
3026 * no need to udpate the advertising data here.
3027 */
Johan Hedberg3f985052013-03-15 17:07:02 -05003028 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07003029 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05003030
Johan Hedberg13928972013-03-15 17:07:00 -05003031 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003032 if (err < 0)
3033 mgmt_pending_remove(cmd);
3034
3035failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003036 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003037 return err;
3038}
3039
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003040static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003041 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01003042{
Szymon Jancc35938b2011-03-22 13:12:21 +01003043 struct pending_cmd *cmd;
3044 int err;
3045
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003046 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01003047
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003048 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003049
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003050 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003051 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003052 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003053 goto unlock;
3054 }
3055
Andre Guedes9a1a1992012-07-24 15:03:48 -03003056 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003057 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003058 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003059 goto unlock;
3060 }
3061
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003062 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003063 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003064 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003065 goto unlock;
3066 }
3067
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003068 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003069 if (!cmd) {
3070 err = -ENOMEM;
3071 goto unlock;
3072 }
3073
3074 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3075 if (err < 0)
3076 mgmt_pending_remove(cmd);
3077
3078unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003079 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003080 return err;
3081}
3082
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003083static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003084 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003085{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003086 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003087 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003088 int err;
3089
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003090 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003091
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003092 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003093
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003094 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003095 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01003096 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003097 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01003098 else
Szymon Janca6785be2012-12-13 15:11:21 +01003099 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003100
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003101 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003102 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003103
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003104 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003105 return err;
3106}
3107
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003108static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003109 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003110{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003111 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003112 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003113 int err;
3114
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003115 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003116
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003117 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003118
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003119 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003120 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003121 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003122 else
Szymon Janca6785be2012-12-13 15:11:21 +01003123 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003124
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003125 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003126 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003127
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003128 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003129 return err;
3130}
3131
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003132static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3133{
3134 struct pending_cmd *cmd;
3135 u8 type;
3136 int err;
3137
3138 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3139
3140 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3141 if (!cmd)
3142 return -ENOENT;
3143
3144 type = hdev->discovery.type;
3145
3146 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3147 &type, sizeof(type));
3148 mgmt_pending_remove(cmd);
3149
3150 return err;
3151}
3152
Andre Guedes7c307722013-04-30 15:29:28 -03003153static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3154{
3155 BT_DBG("status %d", status);
3156
3157 if (status) {
3158 hci_dev_lock(hdev);
3159 mgmt_start_discovery_failed(hdev, status);
3160 hci_dev_unlock(hdev);
3161 return;
3162 }
3163
3164 hci_dev_lock(hdev);
3165 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3166 hci_dev_unlock(hdev);
3167
3168 switch (hdev->discovery.type) {
3169 case DISCOV_TYPE_LE:
3170 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003171 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003172 break;
3173
3174 case DISCOV_TYPE_INTERLEAVED:
3175 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003176 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003177 break;
3178
3179 case DISCOV_TYPE_BREDR:
3180 break;
3181
3182 default:
3183 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3184 }
3185}
3186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003187static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003188 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003189{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003190 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003191 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003192 struct hci_cp_le_set_scan_param param_cp;
3193 struct hci_cp_le_set_scan_enable enable_cp;
3194 struct hci_cp_inquiry inq_cp;
3195 struct hci_request req;
3196 /* General inquiry access code (GIAC) */
3197 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003198 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003199 int err;
3200
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003201 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003202
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003203 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003204
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003205 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003206 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003207 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003208 goto failed;
3209 }
3210
Andre Guedes642be6c2012-03-21 00:03:37 -03003211 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3212 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3213 MGMT_STATUS_BUSY);
3214 goto failed;
3215 }
3216
Johan Hedbergff9ef572012-01-04 14:23:45 +02003217 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003218 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003219 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003220 goto failed;
3221 }
3222
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003223 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003224 if (!cmd) {
3225 err = -ENOMEM;
3226 goto failed;
3227 }
3228
Andre Guedes4aab14e2012-02-17 20:39:36 -03003229 hdev->discovery.type = cp->type;
3230
Andre Guedes7c307722013-04-30 15:29:28 -03003231 hci_req_init(&req, hdev);
3232
Andre Guedes4aab14e2012-02-17 20:39:36 -03003233 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003234 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003235 status = mgmt_bredr_support(hdev);
3236 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003237 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003238 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003239 mgmt_pending_remove(cmd);
3240 goto failed;
3241 }
3242
Andre Guedes7c307722013-04-30 15:29:28 -03003243 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3244 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3245 MGMT_STATUS_BUSY);
3246 mgmt_pending_remove(cmd);
3247 goto failed;
3248 }
3249
3250 hci_inquiry_cache_flush(hdev);
3251
3252 memset(&inq_cp, 0, sizeof(inq_cp));
3253 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003254 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003255 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003256 break;
3257
3258 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003259 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003260 status = mgmt_le_support(hdev);
3261 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003262 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003263 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003264 mgmt_pending_remove(cmd);
3265 goto failed;
3266 }
3267
Andre Guedes7c307722013-04-30 15:29:28 -03003268 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003269 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003270 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3271 MGMT_STATUS_NOT_SUPPORTED);
3272 mgmt_pending_remove(cmd);
3273 goto failed;
3274 }
3275
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003276 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003277 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3278 MGMT_STATUS_REJECTED);
3279 mgmt_pending_remove(cmd);
3280 goto failed;
3281 }
3282
3283 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3284 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3285 MGMT_STATUS_BUSY);
3286 mgmt_pending_remove(cmd);
3287 goto failed;
3288 }
3289
3290 memset(&param_cp, 0, sizeof(param_cp));
3291 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003292 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3293 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003294 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003295 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3296 &param_cp);
3297
3298 memset(&enable_cp, 0, sizeof(enable_cp));
3299 enable_cp.enable = LE_SCAN_ENABLE;
3300 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3301 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3302 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003303 break;
3304
Andre Guedesf39799f2012-02-17 20:39:35 -03003305 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003306 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3307 MGMT_STATUS_INVALID_PARAMS);
3308 mgmt_pending_remove(cmd);
3309 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003310 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003311
Andre Guedes7c307722013-04-30 15:29:28 -03003312 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003313 if (err < 0)
3314 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003315 else
3316 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003317
3318failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003319 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003320 return err;
3321}
3322
Andre Guedes1183fdc2013-04-30 15:29:35 -03003323static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3324{
3325 struct pending_cmd *cmd;
3326 int err;
3327
3328 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3329 if (!cmd)
3330 return -ENOENT;
3331
3332 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3333 &hdev->discovery.type, sizeof(hdev->discovery.type));
3334 mgmt_pending_remove(cmd);
3335
3336 return err;
3337}
3338
Andre Guedes0e05bba2013-04-30 15:29:33 -03003339static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3340{
3341 BT_DBG("status %d", status);
3342
3343 hci_dev_lock(hdev);
3344
3345 if (status) {
3346 mgmt_stop_discovery_failed(hdev, status);
3347 goto unlock;
3348 }
3349
3350 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3351
3352unlock:
3353 hci_dev_unlock(hdev);
3354}
3355
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003356static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003357 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003358{
Johan Hedbergd9306502012-02-20 23:25:18 +02003359 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003360 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003361 struct hci_cp_remote_name_req_cancel cp;
3362 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003363 struct hci_request req;
3364 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003365 int err;
3366
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003367 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003368
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003369 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003370
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003371 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003372 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003373 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3374 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003375 goto unlock;
3376 }
3377
3378 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003379 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003380 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3381 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003382 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003383 }
3384
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003385 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003386 if (!cmd) {
3387 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003388 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003389 }
3390
Andre Guedes0e05bba2013-04-30 15:29:33 -03003391 hci_req_init(&req, hdev);
3392
Andre Guedese0d9727e2012-03-20 15:15:36 -03003393 switch (hdev->discovery.state) {
3394 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003395 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3396 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3397 } else {
3398 cancel_delayed_work(&hdev->le_scan_disable);
3399
3400 memset(&enable_cp, 0, sizeof(enable_cp));
3401 enable_cp.enable = LE_SCAN_DISABLE;
3402 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3403 sizeof(enable_cp), &enable_cp);
3404 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003405
Andre Guedese0d9727e2012-03-20 15:15:36 -03003406 break;
3407
3408 case DISCOVERY_RESOLVING:
3409 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003410 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003411 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003412 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003413 err = cmd_complete(sk, hdev->id,
3414 MGMT_OP_STOP_DISCOVERY, 0,
3415 &mgmt_cp->type,
3416 sizeof(mgmt_cp->type));
3417 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3418 goto unlock;
3419 }
3420
3421 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003422 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3423 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003424
3425 break;
3426
3427 default:
3428 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003429
3430 mgmt_pending_remove(cmd);
3431 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3432 MGMT_STATUS_FAILED, &mgmt_cp->type,
3433 sizeof(mgmt_cp->type));
3434 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003435 }
3436
Andre Guedes0e05bba2013-04-30 15:29:33 -03003437 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003438 if (err < 0)
3439 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003440 else
3441 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003442
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003443unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003444 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003445 return err;
3446}
3447
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003448static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003449 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003450{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003451 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003452 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003453 int err;
3454
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003455 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003456
Johan Hedberg561aafb2012-01-04 13:31:59 +02003457 hci_dev_lock(hdev);
3458
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003459 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003460 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003461 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003462 goto failed;
3463 }
3464
Johan Hedberga198e7b2012-02-17 14:27:06 +02003465 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003466 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003467 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003468 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003469 goto failed;
3470 }
3471
3472 if (cp->name_known) {
3473 e->name_state = NAME_KNOWN;
3474 list_del(&e->list);
3475 } else {
3476 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003477 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003478 }
3479
Johan Hedberge3846622013-01-09 15:29:33 +02003480 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3481 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003482
3483failed:
3484 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003485 return err;
3486}
3487
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003488static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003489 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003490{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003491 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003492 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003493 int err;
3494
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003495 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003496
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003497 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003498 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3499 MGMT_STATUS_INVALID_PARAMS,
3500 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003501
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003502 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003503
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003504 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003505 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003506 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003507 else
Szymon Janca6785be2012-12-13 15:11:21 +01003508 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003509
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003510 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003511 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003512
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003513 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003514
3515 return err;
3516}
3517
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003518static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003519 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003520{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003521 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003522 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003523 int err;
3524
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003525 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003526
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003527 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003528 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3529 MGMT_STATUS_INVALID_PARAMS,
3530 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003531
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003532 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003533
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003534 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003535 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003536 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003537 else
Szymon Janca6785be2012-12-13 15:11:21 +01003538 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003539
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003540 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003541 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003542
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003543 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003544
3545 return err;
3546}
3547
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003548static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3549 u16 len)
3550{
3551 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003552 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003553 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003554 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003555
3556 BT_DBG("%s", hdev->name);
3557
Szymon Jancc72d4b82012-03-16 16:02:57 +01003558 source = __le16_to_cpu(cp->source);
3559
3560 if (source > 0x0002)
3561 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3562 MGMT_STATUS_INVALID_PARAMS);
3563
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003564 hci_dev_lock(hdev);
3565
Szymon Jancc72d4b82012-03-16 16:02:57 +01003566 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003567 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3568 hdev->devid_product = __le16_to_cpu(cp->product);
3569 hdev->devid_version = __le16_to_cpu(cp->version);
3570
3571 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3572
Johan Hedberg890ea892013-03-15 17:06:52 -05003573 hci_req_init(&req, hdev);
3574 update_eir(&req);
3575 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003576
3577 hci_dev_unlock(hdev);
3578
3579 return err;
3580}
3581
Johan Hedberg4375f102013-09-25 13:26:10 +03003582static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3583{
3584 struct cmd_lookup match = { NULL, hdev };
3585
3586 if (status) {
3587 u8 mgmt_err = mgmt_status(status);
3588
3589 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3590 cmd_status_rsp, &mgmt_err);
3591 return;
3592 }
3593
3594 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3595 &match);
3596
3597 new_settings(hdev, match.sk);
3598
3599 if (match.sk)
3600 sock_put(match.sk);
3601}
3602
Marcel Holtmann21b51872013-10-10 09:47:53 -07003603static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3604 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003605{
3606 struct mgmt_mode *cp = data;
3607 struct pending_cmd *cmd;
3608 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003609 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003610 int err;
3611
3612 BT_DBG("request for %s", hdev->name);
3613
Johan Hedberge6fe7982013-10-02 15:45:22 +03003614 status = mgmt_le_support(hdev);
3615 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003616 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003617 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003618
3619 if (cp->val != 0x00 && cp->val != 0x01)
3620 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3621 MGMT_STATUS_INVALID_PARAMS);
3622
3623 hci_dev_lock(hdev);
3624
3625 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003626 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003627
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003628 /* The following conditions are ones which mean that we should
3629 * not do any HCI communication but directly send a mgmt
3630 * response to user space (after toggling the flag if
3631 * necessary).
3632 */
3633 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003634 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003635 bool changed = false;
3636
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003637 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3638 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003639 changed = true;
3640 }
3641
3642 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3643 if (err < 0)
3644 goto unlock;
3645
3646 if (changed)
3647 err = new_settings(hdev, sk);
3648
3649 goto unlock;
3650 }
3651
3652 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3653 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3654 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3655 MGMT_STATUS_BUSY);
3656 goto unlock;
3657 }
3658
3659 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3660 if (!cmd) {
3661 err = -ENOMEM;
3662 goto unlock;
3663 }
3664
3665 hci_req_init(&req, hdev);
3666
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003667 if (val)
3668 enable_advertising(&req);
3669 else
3670 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003671
3672 err = hci_req_run(&req, set_advertising_complete);
3673 if (err < 0)
3674 mgmt_pending_remove(cmd);
3675
3676unlock:
3677 hci_dev_unlock(hdev);
3678 return err;
3679}
3680
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003681static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3682 void *data, u16 len)
3683{
3684 struct mgmt_cp_set_static_address *cp = data;
3685 int err;
3686
3687 BT_DBG("%s", hdev->name);
3688
Marcel Holtmann62af4442013-10-02 22:10:32 -07003689 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003690 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003691 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003692
3693 if (hdev_is_powered(hdev))
3694 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3695 MGMT_STATUS_REJECTED);
3696
3697 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3698 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3699 return cmd_status(sk, hdev->id,
3700 MGMT_OP_SET_STATIC_ADDRESS,
3701 MGMT_STATUS_INVALID_PARAMS);
3702
3703 /* Two most significant bits shall be set */
3704 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3705 return cmd_status(sk, hdev->id,
3706 MGMT_OP_SET_STATIC_ADDRESS,
3707 MGMT_STATUS_INVALID_PARAMS);
3708 }
3709
3710 hci_dev_lock(hdev);
3711
3712 bacpy(&hdev->static_addr, &cp->bdaddr);
3713
3714 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3715
3716 hci_dev_unlock(hdev);
3717
3718 return err;
3719}
3720
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003721static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3722 void *data, u16 len)
3723{
3724 struct mgmt_cp_set_scan_params *cp = data;
3725 __u16 interval, window;
3726 int err;
3727
3728 BT_DBG("%s", hdev->name);
3729
3730 if (!lmp_le_capable(hdev))
3731 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3732 MGMT_STATUS_NOT_SUPPORTED);
3733
3734 interval = __le16_to_cpu(cp->interval);
3735
3736 if (interval < 0x0004 || interval > 0x4000)
3737 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3738 MGMT_STATUS_INVALID_PARAMS);
3739
3740 window = __le16_to_cpu(cp->window);
3741
3742 if (window < 0x0004 || window > 0x4000)
3743 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3744 MGMT_STATUS_INVALID_PARAMS);
3745
Marcel Holtmann899e1072013-10-14 09:55:32 -07003746 if (window > interval)
3747 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3748 MGMT_STATUS_INVALID_PARAMS);
3749
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003750 hci_dev_lock(hdev);
3751
3752 hdev->le_scan_interval = interval;
3753 hdev->le_scan_window = window;
3754
3755 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3756
3757 hci_dev_unlock(hdev);
3758
3759 return err;
3760}
3761
Johan Hedberg33e38b32013-03-15 17:07:05 -05003762static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3763{
3764 struct pending_cmd *cmd;
3765
3766 BT_DBG("status 0x%02x", status);
3767
3768 hci_dev_lock(hdev);
3769
3770 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3771 if (!cmd)
3772 goto unlock;
3773
3774 if (status) {
3775 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3776 mgmt_status(status));
3777 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003778 struct mgmt_mode *cp = cmd->param;
3779
3780 if (cp->val)
3781 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3782 else
3783 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3784
Johan Hedberg33e38b32013-03-15 17:07:05 -05003785 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3786 new_settings(hdev, cmd->sk);
3787 }
3788
3789 mgmt_pending_remove(cmd);
3790
3791unlock:
3792 hci_dev_unlock(hdev);
3793}
3794
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003795static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003796 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003797{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003798 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003799 struct pending_cmd *cmd;
3800 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003801 int err;
3802
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003803 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003804
Johan Hedberg56f87902013-10-02 13:43:13 +03003805 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3806 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003807 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3808 MGMT_STATUS_NOT_SUPPORTED);
3809
Johan Hedberga7e80f22013-01-09 16:05:19 +02003810 if (cp->val != 0x00 && cp->val != 0x01)
3811 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3812 MGMT_STATUS_INVALID_PARAMS);
3813
Johan Hedberg5400c042012-02-21 16:40:33 +02003814 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003815 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003816 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003817
3818 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003819 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003820 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003821
3822 hci_dev_lock(hdev);
3823
Johan Hedberg05cbf292013-03-15 17:07:07 -05003824 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3825 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3826 MGMT_STATUS_BUSY);
3827 goto unlock;
3828 }
3829
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003830 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3831 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3832 hdev);
3833 goto unlock;
3834 }
3835
Johan Hedberg33e38b32013-03-15 17:07:05 -05003836 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3837 data, len);
3838 if (!cmd) {
3839 err = -ENOMEM;
3840 goto unlock;
3841 }
3842
3843 hci_req_init(&req, hdev);
3844
Johan Hedberg406d7802013-03-15 17:07:09 -05003845 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003846
3847 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003848 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003849 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003850 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003851 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003852 }
3853
Johan Hedberg33e38b32013-03-15 17:07:05 -05003854unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003855 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003856
Antti Julkuf6422ec2011-06-22 13:11:56 +03003857 return err;
3858}
3859
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003860static void set_bredr_scan(struct hci_request *req)
3861{
3862 struct hci_dev *hdev = req->hdev;
3863 u8 scan = 0;
3864
3865 /* Ensure that fast connectable is disabled. This function will
3866 * not do anything if the page scan parameters are already what
3867 * they should be.
3868 */
3869 write_fast_connectable(req, false);
3870
3871 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3872 scan |= SCAN_PAGE;
3873 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3874 scan |= SCAN_INQUIRY;
3875
3876 if (scan)
3877 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3878}
3879
Johan Hedberg0663ca22013-10-02 13:43:14 +03003880static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3881{
3882 struct pending_cmd *cmd;
3883
3884 BT_DBG("status 0x%02x", status);
3885
3886 hci_dev_lock(hdev);
3887
3888 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3889 if (!cmd)
3890 goto unlock;
3891
3892 if (status) {
3893 u8 mgmt_err = mgmt_status(status);
3894
3895 /* We need to restore the flag if related HCI commands
3896 * failed.
3897 */
3898 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3899
3900 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3901 } else {
3902 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3903 new_settings(hdev, cmd->sk);
3904 }
3905
3906 mgmt_pending_remove(cmd);
3907
3908unlock:
3909 hci_dev_unlock(hdev);
3910}
3911
3912static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3913{
3914 struct mgmt_mode *cp = data;
3915 struct pending_cmd *cmd;
3916 struct hci_request req;
3917 int err;
3918
3919 BT_DBG("request for %s", hdev->name);
3920
3921 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3922 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3923 MGMT_STATUS_NOT_SUPPORTED);
3924
3925 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3926 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3927 MGMT_STATUS_REJECTED);
3928
3929 if (cp->val != 0x00 && cp->val != 0x01)
3930 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3931 MGMT_STATUS_INVALID_PARAMS);
3932
3933 hci_dev_lock(hdev);
3934
3935 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3936 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3937 goto unlock;
3938 }
3939
3940 if (!hdev_is_powered(hdev)) {
3941 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003942 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3943 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3944 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3945 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3946 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3947 }
3948
3949 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3950
3951 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3952 if (err < 0)
3953 goto unlock;
3954
3955 err = new_settings(hdev, sk);
3956 goto unlock;
3957 }
3958
3959 /* Reject disabling when powered on */
3960 if (!cp->val) {
3961 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3962 MGMT_STATUS_REJECTED);
3963 goto unlock;
3964 }
3965
3966 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3967 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3968 MGMT_STATUS_BUSY);
3969 goto unlock;
3970 }
3971
3972 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3973 if (!cmd) {
3974 err = -ENOMEM;
3975 goto unlock;
3976 }
3977
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003978 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03003979 * generates the correct flags.
3980 */
3981 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3982
3983 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003984
3985 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3986 set_bredr_scan(&req);
3987
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07003988 /* Since only the advertising data flags will change, there
3989 * is no need to update the scan response data.
3990 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003991 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003992
Johan Hedberg0663ca22013-10-02 13:43:14 +03003993 err = hci_req_run(&req, set_bredr_complete);
3994 if (err < 0)
3995 mgmt_pending_remove(cmd);
3996
3997unlock:
3998 hci_dev_unlock(hdev);
3999 return err;
4000}
4001
Johan Hedberg3f706b72013-01-20 14:27:16 +02004002static bool ltk_is_valid(struct mgmt_ltk_info *key)
4003{
Johan Hedberg44b20d32013-01-20 14:27:17 +02004004 if (key->authenticated != 0x00 && key->authenticated != 0x01)
4005 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004006 if (key->master != 0x00 && key->master != 0x01)
4007 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02004008 if (!bdaddr_type_is_le(key->addr.type))
4009 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02004010 return true;
4011}
4012
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004013static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004014 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004015{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004016 struct mgmt_cp_load_long_term_keys *cp = cp_data;
4017 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004018 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004019
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07004020 BT_DBG("request for %s", hdev->name);
4021
4022 if (!lmp_le_capable(hdev))
4023 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
4024 MGMT_STATUS_NOT_SUPPORTED);
4025
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004026 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004027
4028 expected_len = sizeof(*cp) + key_count *
4029 sizeof(struct mgmt_ltk_info);
4030 if (expected_len != len) {
4031 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004032 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004033 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02004034 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004035 }
4036
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004037 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004038
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004039 for (i = 0; i < key_count; i++) {
4040 struct mgmt_ltk_info *key = &cp->keys[i];
4041
Johan Hedberg3f706b72013-01-20 14:27:16 +02004042 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02004043 return cmd_status(sk, hdev->id,
4044 MGMT_OP_LOAD_LONG_TERM_KEYS,
4045 MGMT_STATUS_INVALID_PARAMS);
4046 }
4047
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004048 hci_dev_lock(hdev);
4049
4050 hci_smp_ltks_clear(hdev);
4051
4052 for (i = 0; i < key_count; i++) {
4053 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004054 u8 type, addr_type;
4055
4056 if (key->addr.type == BDADDR_LE_PUBLIC)
4057 addr_type = ADDR_LE_DEV_PUBLIC;
4058 else
4059 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004060
4061 if (key->master)
4062 type = HCI_SMP_LTK;
4063 else
4064 type = HCI_SMP_LTK_SLAVE;
4065
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004066 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004067 type, 0, key->authenticated, key->val,
4068 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004069 }
4070
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004071 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4072 NULL, 0);
4073
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004074 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004075
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004076 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004077}
4078
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004079static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004080 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4081 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004082 bool var_len;
4083 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004084} mgmt_handlers[] = {
4085 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004086 { read_version, false, MGMT_READ_VERSION_SIZE },
4087 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4088 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4089 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4090 { set_powered, false, MGMT_SETTING_SIZE },
4091 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4092 { set_connectable, false, MGMT_SETTING_SIZE },
4093 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4094 { set_pairable, false, MGMT_SETTING_SIZE },
4095 { set_link_security, false, MGMT_SETTING_SIZE },
4096 { set_ssp, false, MGMT_SETTING_SIZE },
4097 { set_hs, false, MGMT_SETTING_SIZE },
4098 { set_le, false, MGMT_SETTING_SIZE },
4099 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4100 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4101 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4102 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4103 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4104 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4105 { disconnect, false, MGMT_DISCONNECT_SIZE },
4106 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4107 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4108 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4109 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4110 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4111 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4112 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4113 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4114 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4115 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4116 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4117 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
4118 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
4119 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4120 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4121 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4122 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4123 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4124 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004125 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004126 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004127 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004128 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004129 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004130};
4131
4132
Johan Hedberg03811012010-12-08 00:21:06 +02004133int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4134{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004135 void *buf;
4136 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004137 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004138 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004139 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004140 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004141 int err;
4142
4143 BT_DBG("got %zu bytes", msglen);
4144
4145 if (msglen < sizeof(*hdr))
4146 return -EINVAL;
4147
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004148 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004149 if (!buf)
4150 return -ENOMEM;
4151
4152 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4153 err = -EFAULT;
4154 goto done;
4155 }
4156
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004157 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004158 opcode = __le16_to_cpu(hdr->opcode);
4159 index = __le16_to_cpu(hdr->index);
4160 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004161
4162 if (len != msglen - sizeof(*hdr)) {
4163 err = -EINVAL;
4164 goto done;
4165 }
4166
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004167 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004168 hdev = hci_dev_get(index);
4169 if (!hdev) {
4170 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004171 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004172 goto done;
4173 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004174
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004175 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4176 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004177 err = cmd_status(sk, index, opcode,
4178 MGMT_STATUS_INVALID_INDEX);
4179 goto done;
4180 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004181 }
4182
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004183 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004184 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004185 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004186 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004187 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004188 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004189 }
4190
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004191 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004192 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004193 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004194 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004195 goto done;
4196 }
4197
Johan Hedbergbe22b542012-03-01 22:24:41 +02004198 handler = &mgmt_handlers[opcode];
4199
4200 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004201 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004202 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004203 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004204 goto done;
4205 }
4206
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004207 if (hdev)
4208 mgmt_init_hdev(sk, hdev);
4209
4210 cp = buf + sizeof(*hdr);
4211
Johan Hedbergbe22b542012-03-01 22:24:41 +02004212 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004213 if (err < 0)
4214 goto done;
4215
Johan Hedberg03811012010-12-08 00:21:06 +02004216 err = msglen;
4217
4218done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004219 if (hdev)
4220 hci_dev_put(hdev);
4221
Johan Hedberg03811012010-12-08 00:21:06 +02004222 kfree(buf);
4223 return err;
4224}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004225
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004226void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004227{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004228 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004229 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004230
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004231 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004232}
4233
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004234void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004235{
Johan Hedberg5f159032012-03-02 03:13:19 +02004236 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004237
Marcel Holtmann1514b892013-10-06 08:25:01 -07004238 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004239 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004240
Johan Hedberg744cf192011-11-08 20:40:14 +02004241 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004242
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004243 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004244}
4245
Johan Hedberg229ab392013-03-15 17:06:53 -05004246static void powered_complete(struct hci_dev *hdev, u8 status)
4247{
4248 struct cmd_lookup match = { NULL, hdev };
4249
4250 BT_DBG("status 0x%02x", status);
4251
4252 hci_dev_lock(hdev);
4253
4254 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4255
4256 new_settings(hdev, match.sk);
4257
4258 hci_dev_unlock(hdev);
4259
4260 if (match.sk)
4261 sock_put(match.sk);
4262}
4263
Johan Hedberg70da6242013-03-15 17:06:51 -05004264static int powered_update_hci(struct hci_dev *hdev)
4265{
Johan Hedberg890ea892013-03-15 17:06:52 -05004266 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004267 u8 link_sec;
4268
Johan Hedberg890ea892013-03-15 17:06:52 -05004269 hci_req_init(&req, hdev);
4270
Johan Hedberg70da6242013-03-15 17:06:51 -05004271 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4272 !lmp_host_ssp_capable(hdev)) {
4273 u8 ssp = 1;
4274
Johan Hedberg890ea892013-03-15 17:06:52 -05004275 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004276 }
4277
Johan Hedbergc73eee92013-04-19 18:35:21 +03004278 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4279 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004280 struct hci_cp_write_le_host_supported cp;
4281
4282 cp.le = 1;
4283 cp.simul = lmp_le_br_capable(hdev);
4284
4285 /* Check first if we already have the right
4286 * host state (host features set)
4287 */
4288 if (cp.le != lmp_host_le_capable(hdev) ||
4289 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004290 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4291 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004292 }
4293
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004294 if (lmp_le_capable(hdev)) {
4295 /* Set random address to static address if configured */
4296 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4297 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4298 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004299
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004300 /* Make sure the controller has a good default for
4301 * advertising data. This also applies to the case
4302 * where BR/EDR was toggled during the AUTO_OFF phase.
4303 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004304 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004305 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004306 update_scan_rsp_data(&req);
4307 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004308
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004309 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4310 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004311 }
4312
Johan Hedberg70da6242013-03-15 17:06:51 -05004313 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4314 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004315 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4316 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004317
4318 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004319 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4320 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004321 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004322 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004323 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004324 }
4325
Johan Hedberg229ab392013-03-15 17:06:53 -05004326 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004327}
4328
Johan Hedberg744cf192011-11-08 20:40:14 +02004329int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004330{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004331 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004332 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4333 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004334 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004335
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004336 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4337 return 0;
4338
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004339 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004340 if (powered_update_hci(hdev) == 0)
4341 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004342
Johan Hedberg229ab392013-03-15 17:06:53 -05004343 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4344 &match);
4345 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004346 }
4347
Johan Hedberg229ab392013-03-15 17:06:53 -05004348 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4349 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4350
4351 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4352 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4353 zero_cod, sizeof(zero_cod), NULL);
4354
4355new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004356 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004357
4358 if (match.sk)
4359 sock_put(match.sk);
4360
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004361 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004362}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004363
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004364void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004365{
4366 struct pending_cmd *cmd;
4367 u8 status;
4368
4369 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4370 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004371 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004372
4373 if (err == -ERFKILL)
4374 status = MGMT_STATUS_RFKILLED;
4375 else
4376 status = MGMT_STATUS_FAILED;
4377
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004378 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004379
4380 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004381}
4382
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004383void mgmt_discoverable_timeout(struct hci_dev *hdev)
4384{
4385 struct hci_request req;
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004386
4387 hci_dev_lock(hdev);
4388
4389 /* When discoverable timeout triggers, then just make sure
4390 * the limited discoverable flag is cleared. Even in the case
4391 * of a timeout triggered from general discoverable, it is
4392 * safe to unconditionally clear the flag.
4393 */
4394 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004395 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004396
4397 hci_req_init(&req, hdev);
Johan Hedberg4b580612013-10-19 23:38:21 +03004398 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
4399 u8 scan = SCAN_PAGE;
4400 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE,
4401 sizeof(scan), &scan);
4402 }
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004403 update_class(&req);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004404 update_adv_data(&req);
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004405 hci_req_run(&req, NULL);
4406
4407 hdev->discov_timeout = 0;
4408
Johan Hedberg9a43e252013-10-20 19:00:07 +03004409 new_settings(hdev, NULL);
4410
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004411 hci_dev_unlock(hdev);
4412}
4413
Marcel Holtmann86a75642013-10-15 06:33:54 -07004414void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004415{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004416 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004417
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004418 /* Nothing needed here if there's a pending command since that
4419 * commands request completion callback takes care of everything
4420 * necessary.
4421 */
4422 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004423 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004424
Johan Hedberg9a43e252013-10-20 19:00:07 +03004425 if (discoverable) {
Marcel Holtmann86a75642013-10-15 06:33:54 -07004426 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004427 } else {
4428 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Marcel Holtmann86a75642013-10-15 06:33:54 -07004429 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004430 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004431
Johan Hedberg9a43e252013-10-20 19:00:07 +03004432 if (changed) {
4433 struct hci_request req;
4434
4435 /* In case this change in discoverable was triggered by
4436 * a disabling of connectable there could be a need to
4437 * update the advertising flags.
4438 */
4439 hci_req_init(&req, hdev);
4440 update_adv_data(&req);
4441 hci_req_run(&req, NULL);
4442
Marcel Holtmann86a75642013-10-15 06:33:54 -07004443 new_settings(hdev, NULL);
Johan Hedberg9a43e252013-10-20 19:00:07 +03004444 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004445}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004446
Marcel Holtmanna3309162013-10-15 06:33:55 -07004447void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004448{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004449 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004450
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004451 /* Nothing needed here if there's a pending command since that
4452 * commands request completion callback takes care of everything
4453 * necessary.
4454 */
4455 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004456 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004457
Marcel Holtmanna3309162013-10-15 06:33:55 -07004458 if (connectable)
4459 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4460 else
4461 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004462
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004463 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004464 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004465}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004466
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004467void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004468{
Johan Hedbergca69b792011-11-11 18:10:00 +02004469 u8 mgmt_err = mgmt_status(status);
4470
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004471 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004472 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004473 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004474
4475 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004476 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004477 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004478}
4479
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004480void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4481 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004482{
Johan Hedberg86742e12011-11-07 23:13:38 +02004483 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004484
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004485 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004486
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004487 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004488 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004489 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004490 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004491 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004492 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004493
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004494 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004495}
Johan Hedbergf7520542011-01-20 12:34:39 +02004496
Marcel Holtmann083368f2013-10-15 14:26:29 -07004497void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004498{
4499 struct mgmt_ev_new_long_term_key ev;
4500
4501 memset(&ev, 0, sizeof(ev));
4502
4503 ev.store_hint = persistent;
4504 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004505 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004506 ev.key.authenticated = key->authenticated;
4507 ev.key.enc_size = key->enc_size;
4508 ev.key.ediv = key->ediv;
4509
4510 if (key->type == HCI_SMP_LTK)
4511 ev.key.master = 1;
4512
4513 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4514 memcpy(ev.key.val, key->val, sizeof(key->val));
4515
Marcel Holtmann083368f2013-10-15 14:26:29 -07004516 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004517}
4518
Marcel Holtmann94933992013-10-15 10:26:39 -07004519static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4520 u8 data_len)
4521{
4522 eir[eir_len++] = sizeof(type) + data_len;
4523 eir[eir_len++] = type;
4524 memcpy(&eir[eir_len], data, data_len);
4525 eir_len += data_len;
4526
4527 return eir_len;
4528}
4529
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004530void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4531 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4532 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004533{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004534 char buf[512];
4535 struct mgmt_ev_device_connected *ev = (void *) buf;
4536 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004537
Johan Hedbergb644ba32012-01-17 21:48:47 +02004538 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004539 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004540
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004541 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004542
Johan Hedbergb644ba32012-01-17 21:48:47 +02004543 if (name_len > 0)
4544 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004545 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004546
4547 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004548 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004549 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004550
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004551 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004552
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004553 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4554 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004555}
4556
Johan Hedberg8962ee72011-01-20 12:40:27 +02004557static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4558{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004559 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004560 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004561 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004562
Johan Hedberg88c3df12012-02-09 14:27:38 +02004563 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4564 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004565
Johan Hedbergaee9b212012-02-18 15:07:59 +02004566 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004567 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004568
4569 *sk = cmd->sk;
4570 sock_hold(*sk);
4571
Johan Hedberga664b5b2011-02-19 12:06:02 -03004572 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004573}
4574
Johan Hedberg124f6e32012-02-09 13:50:12 +02004575static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004576{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004577 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004578 struct mgmt_cp_unpair_device *cp = cmd->param;
4579 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004580
4581 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004582 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4583 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004584
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004585 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4586
Johan Hedbergaee9b212012-02-18 15:07:59 +02004587 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004588
4589 mgmt_pending_remove(cmd);
4590}
4591
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004592void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4593 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004594{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004595 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004596 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004597
Johan Hedberg744cf192011-11-08 20:40:14 +02004598 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004599
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004600 bacpy(&ev.addr.bdaddr, bdaddr);
4601 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4602 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004603
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004604 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004605
4606 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004607 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004608
Johan Hedberg124f6e32012-02-09 13:50:12 +02004609 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004610 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004611}
4612
Marcel Holtmann78929242013-10-06 23:55:47 -07004613void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4614 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004615{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004616 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004617 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004618
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004619 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4620 hdev);
4621
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004622 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004623 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004624 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004625
Johan Hedberg88c3df12012-02-09 14:27:38 +02004626 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004627 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004628
Marcel Holtmann78929242013-10-06 23:55:47 -07004629 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4630 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004631
Johan Hedberga664b5b2011-02-19 12:06:02 -03004632 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004633}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004634
Marcel Holtmann445608d2013-10-06 23:55:48 -07004635void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4636 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004637{
4638 struct mgmt_ev_connect_failed ev;
4639
Johan Hedberg4c659c32011-11-07 23:13:39 +02004640 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004641 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004642 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004643
Marcel Holtmann445608d2013-10-06 23:55:48 -07004644 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004645}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004646
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004647void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004648{
4649 struct mgmt_ev_pin_code_request ev;
4650
Johan Hedbergd8457692012-02-17 14:24:57 +02004651 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004652 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004653 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004654
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004655 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004656}
4657
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004658void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4659 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004660{
4661 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004662 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004663
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004664 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004665 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004666 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004667
Johan Hedbergd8457692012-02-17 14:24:57 +02004668 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004669 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004670
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004671 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4672 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004673
Johan Hedberga664b5b2011-02-19 12:06:02 -03004674 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004675}
4676
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004677void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4678 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004679{
4680 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004681 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004682
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004683 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004684 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004685 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004686
Johan Hedbergd8457692012-02-17 14:24:57 +02004687 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004688 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004689
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004690 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4691 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004692
Johan Hedberga664b5b2011-02-19 12:06:02 -03004693 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004694}
Johan Hedberga5c29682011-02-19 12:05:57 -03004695
Johan Hedberg744cf192011-11-08 20:40:14 +02004696int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004697 u8 link_type, u8 addr_type, __le32 value,
4698 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004699{
4700 struct mgmt_ev_user_confirm_request ev;
4701
Johan Hedberg744cf192011-11-08 20:40:14 +02004702 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004703
Johan Hedberg272d90d2012-02-09 15:26:12 +02004704 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004705 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004706 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004707 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004708
Johan Hedberg744cf192011-11-08 20:40:14 +02004709 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004710 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004711}
4712
Johan Hedberg272d90d2012-02-09 15:26:12 +02004713int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004714 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004715{
4716 struct mgmt_ev_user_passkey_request ev;
4717
4718 BT_DBG("%s", hdev->name);
4719
Johan Hedberg272d90d2012-02-09 15:26:12 +02004720 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004721 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004722
4723 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004724 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004725}
4726
Brian Gix0df4c182011-11-16 13:53:13 -08004727static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004728 u8 link_type, u8 addr_type, u8 status,
4729 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004730{
4731 struct pending_cmd *cmd;
4732 struct mgmt_rp_user_confirm_reply rp;
4733 int err;
4734
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004735 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004736 if (!cmd)
4737 return -ENOENT;
4738
Johan Hedberg272d90d2012-02-09 15:26:12 +02004739 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004740 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004741 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004742 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004743
Johan Hedberga664b5b2011-02-19 12:06:02 -03004744 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004745
4746 return err;
4747}
4748
Johan Hedberg744cf192011-11-08 20:40:14 +02004749int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004750 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004751{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004752 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004753 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004754}
4755
Johan Hedberg272d90d2012-02-09 15:26:12 +02004756int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004757 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004758{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004759 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004760 status,
4761 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004762}
Johan Hedberg2a611692011-02-19 12:06:00 -03004763
Brian Gix604086b2011-11-23 08:28:33 -08004764int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004765 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004766{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004767 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004768 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004769}
4770
Johan Hedberg272d90d2012-02-09 15:26:12 +02004771int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004772 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004773{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004774 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004775 status,
4776 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004777}
4778
Johan Hedberg92a25252012-09-06 18:39:26 +03004779int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4780 u8 link_type, u8 addr_type, u32 passkey,
4781 u8 entered)
4782{
4783 struct mgmt_ev_passkey_notify ev;
4784
4785 BT_DBG("%s", hdev->name);
4786
4787 bacpy(&ev.addr.bdaddr, bdaddr);
4788 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4789 ev.passkey = __cpu_to_le32(passkey);
4790 ev.entered = entered;
4791
4792 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4793}
4794
Marcel Holtmanne5460992013-10-15 14:26:23 -07004795void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4796 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004797{
4798 struct mgmt_ev_auth_failed ev;
4799
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004800 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004801 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004802 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004803
Marcel Holtmanne5460992013-10-15 14:26:23 -07004804 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004805}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004806
Marcel Holtmann464996a2013-10-15 14:26:24 -07004807void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004808{
4809 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004810 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004811
4812 if (status) {
4813 u8 mgmt_err = mgmt_status(status);
4814 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004815 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004816 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004817 }
4818
Marcel Holtmann464996a2013-10-15 14:26:24 -07004819 if (test_bit(HCI_AUTH, &hdev->flags))
4820 changed = !test_and_set_bit(HCI_LINK_SECURITY,
4821 &hdev->dev_flags);
4822 else
4823 changed = test_and_clear_bit(HCI_LINK_SECURITY,
4824 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02004825
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004826 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004827 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004828
Johan Hedberg47990ea2012-02-22 11:58:37 +02004829 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07004830 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004831
4832 if (match.sk)
4833 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004834}
4835
Johan Hedberg890ea892013-03-15 17:06:52 -05004836static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004837{
Johan Hedberg890ea892013-03-15 17:06:52 -05004838 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004839 struct hci_cp_write_eir cp;
4840
Johan Hedberg976eb202012-10-24 21:12:01 +03004841 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004842 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004843
Johan Hedbergc80da272012-02-22 15:38:48 +02004844 memset(hdev->eir, 0, sizeof(hdev->eir));
4845
Johan Hedbergcacaf522012-02-21 00:52:42 +02004846 memset(&cp, 0, sizeof(cp));
4847
Johan Hedberg890ea892013-03-15 17:06:52 -05004848 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004849}
4850
Marcel Holtmann3e248562013-10-15 14:26:25 -07004851void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004852{
4853 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004854 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004855 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004856
4857 if (status) {
4858 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004859
4860 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004861 &hdev->dev_flags)) {
4862 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004863 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004864 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004865
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004866 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4867 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004868 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004869 }
4870
4871 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004872 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004873 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004874 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4875 if (!changed)
4876 changed = test_and_clear_bit(HCI_HS_ENABLED,
4877 &hdev->dev_flags);
4878 else
4879 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004880 }
4881
4882 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4883
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004884 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07004885 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004886
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004887 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004888 sock_put(match.sk);
4889
Johan Hedberg890ea892013-03-15 17:06:52 -05004890 hci_req_init(&req, hdev);
4891
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004892 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004893 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004894 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004895 clear_eir(&req);
4896
4897 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004898}
4899
Johan Hedberg92da6092013-03-15 17:06:55 -05004900static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004901{
4902 struct cmd_lookup *match = data;
4903
Johan Hedberg90e70452012-02-23 23:09:40 +02004904 if (match->sk == NULL) {
4905 match->sk = cmd->sk;
4906 sock_hold(match->sk);
4907 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004908}
4909
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004910void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
4911 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004912{
Johan Hedberg90e70452012-02-23 23:09:40 +02004913 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004914
Johan Hedberg92da6092013-03-15 17:06:55 -05004915 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4916 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4917 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004918
4919 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004920 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
4921 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004922
4923 if (match.sk)
4924 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004925}
4926
Marcel Holtmann7667da32013-10-15 14:26:27 -07004927void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004928{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004929 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004930 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004931
Johan Hedberg13928972013-03-15 17:07:00 -05004932 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07004933 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004934
4935 memset(&ev, 0, sizeof(ev));
4936 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004937 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004938
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004939 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004940 if (!cmd) {
4941 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004942
Johan Hedberg13928972013-03-15 17:07:00 -05004943 /* If this is a HCI command related to powering on the
4944 * HCI dev don't send any mgmt signals.
4945 */
4946 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07004947 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004948 }
4949
Marcel Holtmann7667da32013-10-15 14:26:27 -07004950 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4951 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004952}
Szymon Jancc35938b2011-03-22 13:12:21 +01004953
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004954void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
4955 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004956{
4957 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01004958
Johan Hedberg744cf192011-11-08 20:40:14 +02004959 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004960
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004961 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004962 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004963 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01004964
4965 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004966 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4967 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004968 } else {
4969 struct mgmt_rp_read_local_oob_data rp;
4970
4971 memcpy(rp.hash, hash, sizeof(rp.hash));
4972 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4973
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004974 cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4975 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004976 }
4977
4978 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01004979}
Johan Hedberge17acd42011-03-30 23:57:16 +03004980
Marcel Holtmann901801b2013-10-06 23:55:51 -07004981void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4982 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4983 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004984{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004985 char buf[512];
4986 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004987 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004988
Andre Guedes12602d02013-04-30 15:29:40 -03004989 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004990 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004991
Johan Hedberg1dc06092012-01-15 21:01:23 +02004992 /* Leave 5 bytes for a potential CoD field */
4993 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004994 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004995
Johan Hedberg1dc06092012-01-15 21:01:23 +02004996 memset(buf, 0, sizeof(buf));
4997
Johan Hedberge319d2e2012-01-15 19:51:59 +02004998 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004999 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02005000 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02005001 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305002 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02005003 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05305004 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03005005
Johan Hedberg1dc06092012-01-15 21:01:23 +02005006 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02005007 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03005008
Johan Hedberg1dc06092012-01-15 21:01:23 +02005009 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
5010 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005011 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005012
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005013 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02005014 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03005015
Marcel Holtmann901801b2013-10-06 23:55:51 -07005016 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03005017}
Johan Hedberga88a9652011-03-30 13:18:12 +03005018
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005019void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
5020 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03005021{
Johan Hedbergb644ba32012-01-17 21:48:47 +02005022 struct mgmt_ev_device_found *ev;
5023 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
5024 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03005025
Johan Hedbergb644ba32012-01-17 21:48:47 +02005026 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03005027
Johan Hedbergb644ba32012-01-17 21:48:47 +02005028 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03005029
Johan Hedbergb644ba32012-01-17 21:48:47 +02005030 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03005031 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005032 ev->rssi = rssi;
5033
5034 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005035 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005036
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02005037 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02005038
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07005039 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03005040}
Johan Hedberg314b2382011-04-27 10:29:57 -04005041
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005042void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04005043{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005044 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02005045 struct pending_cmd *cmd;
5046
Andre Guedes343fb142011-11-22 17:14:19 -03005047 BT_DBG("%s discovering %u", hdev->name, discovering);
5048
Johan Hedberg164a6e72011-11-01 17:06:44 +02005049 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005050 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005051 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005052 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02005053
5054 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02005055 u8 type = hdev->discovery.type;
5056
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005057 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
5058 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02005059 mgmt_pending_remove(cmd);
5060 }
5061
Johan Hedbergf963e8e2012-02-20 23:30:44 +02005062 memset(&ev, 0, sizeof(ev));
5063 ev.type = hdev->discovery.type;
5064 ev.discovering = discovering;
5065
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07005066 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04005067}
Antti Julku5e762442011-08-25 16:48:02 +03005068
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005069int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005070{
5071 struct pending_cmd *cmd;
5072 struct mgmt_ev_device_blocked ev;
5073
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005074 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005075
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005076 bacpy(&ev.addr.bdaddr, bdaddr);
5077 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005078
Johan Hedberg744cf192011-11-08 20:40:14 +02005079 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005080 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005081}
5082
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005083int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005084{
5085 struct pending_cmd *cmd;
5086 struct mgmt_ev_device_unblocked ev;
5087
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005088 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005089
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005090 bacpy(&ev.addr.bdaddr, bdaddr);
5091 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005092
Johan Hedberg744cf192011-11-08 20:40:14 +02005093 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005094 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005095}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005096
5097static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5098{
5099 BT_DBG("%s status %u", hdev->name, status);
5100
5101 /* Clear the advertising mgmt setting if we failed to re-enable it */
5102 if (status) {
5103 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005104 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005105 }
5106}
5107
5108void mgmt_reenable_advertising(struct hci_dev *hdev)
5109{
5110 struct hci_request req;
5111
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005112 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005113 return;
5114
5115 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5116 return;
5117
5118 hci_req_init(&req, hdev);
5119 enable_advertising(&req);
5120
5121 /* If this fails we have no option but to let user space know
5122 * that we've disabled advertising.
5123 */
5124 if (hci_req_run(&req, adv_enable_complete) < 0) {
5125 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005126 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005127 }
5128}