blob: 0bf823b5d90e7be892670ebc78aaf74d31cb9f4e [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 Hedberg84bde9d6c2012-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
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700539static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
540{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700541 u8 ad_len = 0;
542 size_t name_len;
543
544 name_len = strlen(hdev->dev_name);
545 if (name_len > 0) {
546 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
547
548 if (name_len > max_len) {
549 name_len = max_len;
550 ptr[1] = EIR_NAME_SHORT;
551 } else
552 ptr[1] = EIR_NAME_COMPLETE;
553
554 ptr[0] = name_len + 1;
555
556 memcpy(ptr + 2, hdev->dev_name, name_len);
557
558 ad_len += (name_len + 2);
559 ptr += (name_len + 2);
560 }
561
562 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700563}
564
565static void update_scan_rsp_data(struct hci_request *req)
566{
567 struct hci_dev *hdev = req->hdev;
568 struct hci_cp_le_set_scan_rsp_data cp;
569 u8 len;
570
571 if (!lmp_le_capable(hdev))
572 return;
573
574 memset(&cp, 0, sizeof(cp));
575
576 len = create_scan_rsp_data(hdev, cp.data);
577
578 if (hdev->adv_data_len == len &&
579 memcmp(cp.data, hdev->adv_data, len) == 0)
580 return;
581
582 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
583 hdev->adv_data_len = len;
584
585 cp.length = len;
586
587 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
588}
589
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700590static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700591{
592 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700593
594 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
595 flags |= LE_AD_GENERAL;
596
597 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
598 if (lmp_le_br_capable(hdev))
599 flags |= LE_AD_SIM_LE_BREDR_CTRL;
600 if (lmp_host_le_br_capable(hdev))
601 flags |= LE_AD_SIM_LE_BREDR_HOST;
602 } else {
603 flags |= LE_AD_NO_BREDR;
604 }
605
606 if (flags) {
607 BT_DBG("adv flags 0x%02x", flags);
608
609 ptr[0] = 2;
610 ptr[1] = EIR_FLAGS;
611 ptr[2] = flags;
612
613 ad_len += 3;
614 ptr += 3;
615 }
616
617 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
618 ptr[0] = 2;
619 ptr[1] = EIR_TX_POWER;
620 ptr[2] = (u8) hdev->adv_tx_power;
621
622 ad_len += 3;
623 ptr += 3;
624 }
625
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700626 return ad_len;
627}
628
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700629static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700630{
631 struct hci_dev *hdev = req->hdev;
632 struct hci_cp_le_set_adv_data cp;
633 u8 len;
634
635 if (!lmp_le_capable(hdev))
636 return;
637
638 memset(&cp, 0, sizeof(cp));
639
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700640 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700641
642 if (hdev->adv_data_len == len &&
643 memcmp(cp.data, hdev->adv_data, len) == 0)
644 return;
645
646 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
647 hdev->adv_data_len = len;
648
649 cp.length = len;
650
651 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
652}
653
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300654static void create_eir(struct hci_dev *hdev, u8 *data)
655{
656 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300657 size_t name_len;
658
659 name_len = strlen(hdev->dev_name);
660
661 if (name_len > 0) {
662 /* EIR Data type */
663 if (name_len > 48) {
664 name_len = 48;
665 ptr[1] = EIR_NAME_SHORT;
666 } else
667 ptr[1] = EIR_NAME_COMPLETE;
668
669 /* EIR Data length */
670 ptr[0] = name_len + 1;
671
672 memcpy(ptr + 2, hdev->dev_name, name_len);
673
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300674 ptr += (name_len + 2);
675 }
676
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100677 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700678 ptr[0] = 2;
679 ptr[1] = EIR_TX_POWER;
680 ptr[2] = (u8) hdev->inq_tx_power;
681
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700682 ptr += 3;
683 }
684
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700685 if (hdev->devid_source > 0) {
686 ptr[0] = 9;
687 ptr[1] = EIR_DEVICE_ID;
688
689 put_unaligned_le16(hdev->devid_source, ptr + 2);
690 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
691 put_unaligned_le16(hdev->devid_product, ptr + 6);
692 put_unaligned_le16(hdev->devid_version, ptr + 8);
693
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700694 ptr += 10;
695 }
696
Johan Hedberg213202e2013-01-27 00:31:33 +0200697 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200698 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200699 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300700}
701
Johan Hedberg890ea892013-03-15 17:06:52 -0500702static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300703{
Johan Hedberg890ea892013-03-15 17:06:52 -0500704 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300705 struct hci_cp_write_eir cp;
706
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200707 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500708 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200709
Johan Hedberg976eb202012-10-24 21:12:01 +0300710 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500711 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300712
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200713 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500714 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300715
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200716 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500717 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300718
719 memset(&cp, 0, sizeof(cp));
720
721 create_eir(hdev, cp.data);
722
723 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500724 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300725
726 memcpy(hdev->eir, cp.data, sizeof(cp.data));
727
Johan Hedberg890ea892013-03-15 17:06:52 -0500728 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300729}
730
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200731static u8 get_service_classes(struct hci_dev *hdev)
732{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300733 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200734 u8 val = 0;
735
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300736 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200737 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200738
739 return val;
740}
741
Johan Hedberg890ea892013-03-15 17:06:52 -0500742static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200743{
Johan Hedberg890ea892013-03-15 17:06:52 -0500744 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200745 u8 cod[3];
746
747 BT_DBG("%s", hdev->name);
748
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200749 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500750 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200751
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200752 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500753 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200754
755 cod[0] = hdev->minor_class;
756 cod[1] = hdev->major_class;
757 cod[2] = get_service_classes(hdev);
758
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700759 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
760 cod[1] |= 0x20;
761
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200762 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500763 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200764
Johan Hedberg890ea892013-03-15 17:06:52 -0500765 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200766}
767
Johan Hedberg7d785252011-12-15 00:47:39 +0200768static void service_cache_off(struct work_struct *work)
769{
770 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300771 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500772 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200773
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200774 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200775 return;
776
Johan Hedberg890ea892013-03-15 17:06:52 -0500777 hci_req_init(&req, hdev);
778
Johan Hedberg7d785252011-12-15 00:47:39 +0200779 hci_dev_lock(hdev);
780
Johan Hedberg890ea892013-03-15 17:06:52 -0500781 update_eir(&req);
782 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200783
784 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500785
786 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200787}
788
Johan Hedberg6a919082012-02-28 06:17:26 +0200789static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200790{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200791 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200792 return;
793
Johan Hedberg4f87da82012-03-02 19:55:56 +0200794 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200795
Johan Hedberg4f87da82012-03-02 19:55:56 +0200796 /* Non-mgmt controlled devices get this bit set
797 * implicitly so that pairing works for them, however
798 * for mgmt we require user-space to explicitly enable
799 * it
800 */
801 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200802}
803
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200804static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300805 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200806{
807 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200808
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200809 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300811 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200812
Johan Hedberg03811012010-12-08 00:21:06 +0200813 memset(&rp, 0, sizeof(rp));
814
Johan Hedberg03811012010-12-08 00:21:06 +0200815 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200816
817 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200818 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200819
820 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
821 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
822
823 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200824
825 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200826 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200827
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300828 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200829
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200830 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300831 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200832}
833
834static void mgmt_pending_free(struct pending_cmd *cmd)
835{
836 sock_put(cmd->sk);
837 kfree(cmd->param);
838 kfree(cmd);
839}
840
841static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300842 struct hci_dev *hdev, void *data,
843 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200844{
845 struct pending_cmd *cmd;
846
Andre Guedes12b94562012-06-07 19:05:45 -0300847 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200848 if (!cmd)
849 return NULL;
850
851 cmd->opcode = opcode;
852 cmd->index = hdev->id;
853
Andre Guedes12b94562012-06-07 19:05:45 -0300854 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200855 if (!cmd->param) {
856 kfree(cmd);
857 return NULL;
858 }
859
860 if (data)
861 memcpy(cmd->param, data, len);
862
863 cmd->sk = sk;
864 sock_hold(sk);
865
866 list_add(&cmd->list, &hdev->mgmt_pending);
867
868 return cmd;
869}
870
871static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300872 void (*cb)(struct pending_cmd *cmd,
873 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300874 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200875{
Andre Guedesa3d09352013-02-01 11:21:30 -0300876 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200877
Andre Guedesa3d09352013-02-01 11:21:30 -0300878 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200879 if (opcode > 0 && cmd->opcode != opcode)
880 continue;
881
882 cb(cmd, data);
883 }
884}
885
886static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
887{
888 struct pending_cmd *cmd;
889
890 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
891 if (cmd->opcode == opcode)
892 return cmd;
893 }
894
895 return NULL;
896}
897
898static void mgmt_pending_remove(struct pending_cmd *cmd)
899{
900 list_del(&cmd->list);
901 mgmt_pending_free(cmd);
902}
903
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200904static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200905{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200906 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200907
Johan Hedbergaee9b212012-02-18 15:07:59 +0200908 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300909 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200910}
911
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200912static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300913 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200914{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300915 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200916 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200917 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200918
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200919 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200920
Johan Hedberga7e80f22013-01-09 16:05:19 +0200921 if (cp->val != 0x00 && cp->val != 0x01)
922 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
923 MGMT_STATUS_INVALID_PARAMS);
924
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300925 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200926
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300927 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
928 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
929 MGMT_STATUS_BUSY);
930 goto failed;
931 }
932
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100933 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
934 cancel_delayed_work(&hdev->power_off);
935
936 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200937 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
938 data, len);
939 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100940 goto failed;
941 }
942 }
943
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200944 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200945 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200946 goto failed;
947 }
948
Johan Hedberg03811012010-12-08 00:21:06 +0200949 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
950 if (!cmd) {
951 err = -ENOMEM;
952 goto failed;
953 }
954
955 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200956 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200957 else
Johan Hedberg19202572013-01-14 22:33:51 +0200958 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200959
960 err = 0;
961
962failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300963 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200964 return err;
965}
966
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300967static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
968 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200969{
970 struct sk_buff *skb;
971 struct mgmt_hdr *hdr;
972
Andre Guedes790eff42012-06-07 19:05:46 -0300973 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200974 if (!skb)
975 return -ENOMEM;
976
977 hdr = (void *) skb_put(skb, sizeof(*hdr));
978 hdr->opcode = cpu_to_le16(event);
979 if (hdev)
980 hdr->index = cpu_to_le16(hdev->id);
981 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530982 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200983 hdr->len = cpu_to_le16(data_len);
984
985 if (data)
986 memcpy(skb_put(skb, data_len), data, data_len);
987
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100988 /* Time stamp */
989 __net_timestamp(skb);
990
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200991 hci_send_to_control(skb, skip_sk);
992 kfree_skb(skb);
993
994 return 0;
995}
996
997static int new_settings(struct hci_dev *hdev, struct sock *skip)
998{
999 __le32 ev;
1000
1001 ev = cpu_to_le32(get_current_settings(hdev));
1002
1003 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1004}
1005
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001006struct cmd_lookup {
1007 struct sock *sk;
1008 struct hci_dev *hdev;
1009 u8 mgmt_status;
1010};
1011
1012static void settings_rsp(struct pending_cmd *cmd, void *data)
1013{
1014 struct cmd_lookup *match = data;
1015
1016 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1017
1018 list_del(&cmd->list);
1019
1020 if (match->sk == NULL) {
1021 match->sk = cmd->sk;
1022 sock_hold(match->sk);
1023 }
1024
1025 mgmt_pending_free(cmd);
1026}
1027
1028static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1029{
1030 u8 *status = data;
1031
1032 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1033 mgmt_pending_remove(cmd);
1034}
1035
Johan Hedberge6fe7982013-10-02 15:45:22 +03001036static u8 mgmt_bredr_support(struct hci_dev *hdev)
1037{
1038 if (!lmp_bredr_capable(hdev))
1039 return MGMT_STATUS_NOT_SUPPORTED;
1040 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1041 return MGMT_STATUS_REJECTED;
1042 else
1043 return MGMT_STATUS_SUCCESS;
1044}
1045
1046static u8 mgmt_le_support(struct hci_dev *hdev)
1047{
1048 if (!lmp_le_capable(hdev))
1049 return MGMT_STATUS_NOT_SUPPORTED;
1050 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1051 return MGMT_STATUS_REJECTED;
1052 else
1053 return MGMT_STATUS_SUCCESS;
1054}
1055
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001056static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1057{
1058 struct pending_cmd *cmd;
1059 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001060 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001061 bool changed;
1062
1063 BT_DBG("status 0x%02x", status);
1064
1065 hci_dev_lock(hdev);
1066
1067 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1068 if (!cmd)
1069 goto unlock;
1070
1071 if (status) {
1072 u8 mgmt_err = mgmt_status(status);
1073 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001074 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001075 goto remove_cmd;
1076 }
1077
1078 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001079 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001080 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1081 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001082
1083 if (hdev->discov_timeout > 0) {
1084 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1085 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1086 to);
1087 }
1088 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001089 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1090 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001091 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001092
1093 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1094
1095 if (changed)
1096 new_settings(hdev, cmd->sk);
1097
Marcel Holtmann970ba522013-10-15 06:33:57 -07001098 /* When the discoverable mode gets changed, make sure
1099 * that class of device has the limited discoverable
1100 * bit correctly set.
1101 */
1102 hci_req_init(&req, hdev);
1103 update_class(&req);
1104 hci_req_run(&req, NULL);
1105
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001106remove_cmd:
1107 mgmt_pending_remove(cmd);
1108
1109unlock:
1110 hci_dev_unlock(hdev);
1111}
1112
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001113static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001114 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001115{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001116 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001117 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001118 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001119 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001120 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001121 int err;
1122
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001123 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001124
Johan Hedberge6fe7982013-10-02 15:45:22 +03001125 status = mgmt_bredr_support(hdev);
1126 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001127 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001128 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001129
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001130 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001131 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1132 MGMT_STATUS_INVALID_PARAMS);
1133
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001134 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001135
1136 /* Disabling discoverable requires that no timeout is set,
1137 * and enabling limited discoverable requires a timeout.
1138 */
1139 if ((cp->val == 0x00 && timeout > 0) ||
1140 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001141 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001142 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001143
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001144 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001145
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001146 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001147 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001148 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001149 goto failed;
1150 }
1151
1152 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001153 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001154 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001155 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001156 goto failed;
1157 }
1158
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001159 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001160 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001161 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001162 goto failed;
1163 }
1164
1165 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001166 bool changed = false;
1167
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001168 /* Setting limited discoverable when powered off is
1169 * not a valid operation since it requires a timeout
1170 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1171 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001172 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1173 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1174 changed = true;
1175 }
1176
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001177 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001178 if (err < 0)
1179 goto failed;
1180
1181 if (changed)
1182 err = new_settings(hdev, sk);
1183
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001184 goto failed;
1185 }
1186
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001187 /* If the current mode is the same, then just update the timeout
1188 * value with the new value. And if only the timeout gets updated,
1189 * then no need for any HCI transactions.
1190 */
1191 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1192 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1193 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001194 cancel_delayed_work(&hdev->discov_off);
1195 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001196
Marcel Holtmann36261542013-10-15 08:28:51 -07001197 if (cp->val && hdev->discov_timeout > 0) {
1198 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001199 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001200 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001201 }
1202
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001203 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001204 goto failed;
1205 }
1206
1207 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1208 if (!cmd) {
1209 err = -ENOMEM;
1210 goto failed;
1211 }
1212
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001213 /* Cancel any potential discoverable timeout that might be
1214 * still active and store new timeout value. The arming of
1215 * the timeout happens in the complete handler.
1216 */
1217 cancel_delayed_work(&hdev->discov_off);
1218 hdev->discov_timeout = timeout;
1219
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001220 hci_req_init(&req, hdev);
1221
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001222 scan = SCAN_PAGE;
1223
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001224 if (cp->val) {
1225 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001226
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001227 if (cp->val == 0x02) {
1228 /* Limited discoverable mode */
1229 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1230
1231 hci_cp.num_iac = 2;
1232 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1233 hci_cp.iac_lap[1] = 0x8b;
1234 hci_cp.iac_lap[2] = 0x9e;
1235 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1236 hci_cp.iac_lap[4] = 0x8b;
1237 hci_cp.iac_lap[5] = 0x9e;
1238 } else {
1239 /* General discoverable mode */
1240 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1241
1242 hci_cp.num_iac = 1;
1243 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1244 hci_cp.iac_lap[1] = 0x8b;
1245 hci_cp.iac_lap[2] = 0x9e;
1246 }
1247
1248 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1249 (hci_cp.num_iac * 3) + 1, &hci_cp);
1250
1251 scan |= SCAN_INQUIRY;
1252 } else {
1253 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1254 }
1255
1256 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001257
1258 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001259 if (err < 0)
1260 mgmt_pending_remove(cmd);
1261
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001262failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001263 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001264 return err;
1265}
1266
Johan Hedberg406d7802013-03-15 17:07:09 -05001267static void write_fast_connectable(struct hci_request *req, bool enable)
1268{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001269 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001270 struct hci_cp_write_page_scan_activity acp;
1271 u8 type;
1272
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001273 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1274 return;
1275
Johan Hedberg406d7802013-03-15 17:07:09 -05001276 if (enable) {
1277 type = PAGE_SCAN_TYPE_INTERLACED;
1278
1279 /* 160 msec page scan interval */
1280 acp.interval = __constant_cpu_to_le16(0x0100);
1281 } else {
1282 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1283
1284 /* default 1.28 sec page scan */
1285 acp.interval = __constant_cpu_to_le16(0x0800);
1286 }
1287
1288 acp.window = __constant_cpu_to_le16(0x0012);
1289
Johan Hedbergbd98b992013-03-15 17:07:13 -05001290 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1291 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1292 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1293 sizeof(acp), &acp);
1294
1295 if (hdev->page_scan_type != type)
1296 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001297}
1298
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001299static u8 get_adv_type(struct hci_dev *hdev)
1300{
1301 struct pending_cmd *cmd;
1302 bool connectable;
1303
1304 /* If there's a pending mgmt command the flag will not yet have
1305 * it's final value, so check for this first.
1306 */
1307 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1308 if (cmd) {
1309 struct mgmt_mode *cp = cmd->param;
1310 connectable = !!cp->val;
1311 } else {
1312 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1313 }
1314
1315 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1316}
1317
Johan Hedberg95c66e72013-10-14 16:20:06 +03001318static void enable_advertising(struct hci_request *req)
1319{
1320 struct hci_dev *hdev = req->hdev;
1321 struct hci_cp_le_set_adv_param cp;
1322 u8 enable = 0x01;
1323
1324 memset(&cp, 0, sizeof(cp));
1325 cp.min_interval = __constant_cpu_to_le16(0x0800);
1326 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001327 cp.type = get_adv_type(hdev);
Johan Hedberg95c66e72013-10-14 16:20:06 +03001328 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1329 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1330 else
1331 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1332 cp.channel_map = 0x07;
1333
1334 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1335
1336 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1337}
1338
1339static void disable_advertising(struct hci_request *req)
1340{
1341 u8 enable = 0x00;
1342
1343 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1344}
1345
Johan Hedberg2b76f452013-03-15 17:07:04 -05001346static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1347{
1348 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001349 struct mgmt_mode *cp;
1350 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001351
1352 BT_DBG("status 0x%02x", status);
1353
1354 hci_dev_lock(hdev);
1355
1356 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1357 if (!cmd)
1358 goto unlock;
1359
Johan Hedberg37438c12013-10-14 16:20:05 +03001360 if (status) {
1361 u8 mgmt_err = mgmt_status(status);
1362 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1363 goto remove_cmd;
1364 }
1365
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001366 cp = cmd->param;
1367 if (cp->val)
1368 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1369 else
1370 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1371
Johan Hedberg2b76f452013-03-15 17:07:04 -05001372 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1373
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001374 if (changed)
1375 new_settings(hdev, cmd->sk);
1376
Johan Hedberg37438c12013-10-14 16:20:05 +03001377remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001378 mgmt_pending_remove(cmd);
1379
1380unlock:
1381 hci_dev_unlock(hdev);
1382}
1383
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001384static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001385 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001386{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001387 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001388 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001389 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001390 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001391 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001392
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001393 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001394
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001395 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1396 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001397 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001398 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001399
Johan Hedberga7e80f22013-01-09 16:05:19 +02001400 if (cp->val != 0x00 && cp->val != 0x01)
1401 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1402 MGMT_STATUS_INVALID_PARAMS);
1403
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001404 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001405
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001406 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001407 bool changed = false;
1408
1409 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1410 changed = true;
1411
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001412 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001413 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001414 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001415 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1416 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1417 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001418
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001419 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001420 if (err < 0)
1421 goto failed;
1422
1423 if (changed)
1424 err = new_settings(hdev, sk);
1425
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001426 goto failed;
1427 }
1428
1429 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001430 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001431 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001432 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001433 goto failed;
1434 }
1435
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001436 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1437 if (!cmd) {
1438 err = -ENOMEM;
1439 goto failed;
1440 }
1441
Johan Hedberg2b76f452013-03-15 17:07:04 -05001442 hci_req_init(&req, hdev);
1443
Johan Hedberg9b742462013-10-14 16:20:03 +03001444 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1445 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001446 if (cp->val) {
1447 scan = SCAN_PAGE;
1448 } else {
1449 scan = 0;
1450
1451 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001452 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001453 cancel_delayed_work(&hdev->discov_off);
1454 }
1455
1456 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1457 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001458
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001459 /* If we're going from non-connectable to connectable or
1460 * vice-versa when fast connectable is enabled ensure that fast
1461 * connectable gets disabled. write_fast_connectable won't do
1462 * anything if the page scan parameters are already what they
1463 * should be.
1464 */
1465 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001466 write_fast_connectable(&req, false);
1467
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001468 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1469 hci_conn_num(hdev, LE_LINK) == 0) {
1470 disable_advertising(&req);
1471 enable_advertising(&req);
1472 }
1473
Johan Hedberg2b76f452013-03-15 17:07:04 -05001474 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001475 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001476 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001477 if (err == -ENODATA)
1478 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1479 hdev);
1480 goto failed;
1481 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001482
1483failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001484 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001485 return err;
1486}
1487
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001488static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001489 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001490{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001491 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001492 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001493 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001494
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001495 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001496
Johan Hedberga7e80f22013-01-09 16:05:19 +02001497 if (cp->val != 0x00 && cp->val != 0x01)
1498 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1499 MGMT_STATUS_INVALID_PARAMS);
1500
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001501 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001502
1503 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001504 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001505 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001506 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001507
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001508 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001509 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001510 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001511
Marcel Holtmann55594352013-10-06 16:11:57 -07001512 if (changed)
1513 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001514
Marcel Holtmann55594352013-10-06 16:11:57 -07001515unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001516 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001517 return err;
1518}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001519
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001520static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1521 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001522{
1523 struct mgmt_mode *cp = data;
1524 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001525 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001526 int err;
1527
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001528 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001529
Johan Hedberge6fe7982013-10-02 15:45:22 +03001530 status = mgmt_bredr_support(hdev);
1531 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001532 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001533 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001534
Johan Hedberga7e80f22013-01-09 16:05:19 +02001535 if (cp->val != 0x00 && cp->val != 0x01)
1536 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1537 MGMT_STATUS_INVALID_PARAMS);
1538
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001539 hci_dev_lock(hdev);
1540
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001541 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001542 bool changed = false;
1543
1544 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001545 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001546 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1547 changed = true;
1548 }
1549
1550 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1551 if (err < 0)
1552 goto failed;
1553
1554 if (changed)
1555 err = new_settings(hdev, sk);
1556
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001557 goto failed;
1558 }
1559
1560 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001561 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001562 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001563 goto failed;
1564 }
1565
1566 val = !!cp->val;
1567
1568 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1569 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1570 goto failed;
1571 }
1572
1573 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1574 if (!cmd) {
1575 err = -ENOMEM;
1576 goto failed;
1577 }
1578
1579 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1580 if (err < 0) {
1581 mgmt_pending_remove(cmd);
1582 goto failed;
1583 }
1584
1585failed:
1586 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001587 return err;
1588}
1589
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001590static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001591{
1592 struct mgmt_mode *cp = data;
1593 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001594 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001595 int err;
1596
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001597 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001598
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001599 status = mgmt_bredr_support(hdev);
1600 if (status)
1601 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1602
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001603 if (!lmp_ssp_capable(hdev))
1604 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1605 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001606
Johan Hedberga7e80f22013-01-09 16:05:19 +02001607 if (cp->val != 0x00 && cp->val != 0x01)
1608 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1609 MGMT_STATUS_INVALID_PARAMS);
1610
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001611 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001612
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001613 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001614 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001615
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001616 if (cp->val) {
1617 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1618 &hdev->dev_flags);
1619 } else {
1620 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1621 &hdev->dev_flags);
1622 if (!changed)
1623 changed = test_and_clear_bit(HCI_HS_ENABLED,
1624 &hdev->dev_flags);
1625 else
1626 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001627 }
1628
1629 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1630 if (err < 0)
1631 goto failed;
1632
1633 if (changed)
1634 err = new_settings(hdev, sk);
1635
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001636 goto failed;
1637 }
1638
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001639 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1640 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001641 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1642 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001643 goto failed;
1644 }
1645
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001646 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001647 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1648 goto failed;
1649 }
1650
1651 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1652 if (!cmd) {
1653 err = -ENOMEM;
1654 goto failed;
1655 }
1656
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001657 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001658 if (err < 0) {
1659 mgmt_pending_remove(cmd);
1660 goto failed;
1661 }
1662
1663failed:
1664 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001665 return err;
1666}
1667
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001668static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001669{
1670 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001671 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001672 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001673 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001674
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001675 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001676
Johan Hedberge6fe7982013-10-02 15:45:22 +03001677 status = mgmt_bredr_support(hdev);
1678 if (status)
1679 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001680
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001681 if (!lmp_ssp_capable(hdev))
1682 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1683 MGMT_STATUS_NOT_SUPPORTED);
1684
1685 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1686 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1687 MGMT_STATUS_REJECTED);
1688
Johan Hedberga7e80f22013-01-09 16:05:19 +02001689 if (cp->val != 0x00 && cp->val != 0x01)
1690 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1691 MGMT_STATUS_INVALID_PARAMS);
1692
Marcel Holtmannee392692013-10-01 22:59:23 -07001693 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001694
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001695 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001696 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001697 } else {
1698 if (hdev_is_powered(hdev)) {
1699 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1700 MGMT_STATUS_REJECTED);
1701 goto unlock;
1702 }
1703
Marcel Holtmannee392692013-10-01 22:59:23 -07001704 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001705 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001706
1707 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1708 if (err < 0)
1709 goto unlock;
1710
1711 if (changed)
1712 err = new_settings(hdev, sk);
1713
1714unlock:
1715 hci_dev_unlock(hdev);
1716 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001717}
1718
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001719static void le_enable_complete(struct hci_dev *hdev, u8 status)
1720{
1721 struct cmd_lookup match = { NULL, hdev };
1722
1723 if (status) {
1724 u8 mgmt_err = mgmt_status(status);
1725
1726 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1727 &mgmt_err);
1728 return;
1729 }
1730
1731 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1732
1733 new_settings(hdev, match.sk);
1734
1735 if (match.sk)
1736 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001737
1738 /* Make sure the controller has a good default for
1739 * advertising data. Restrict the update to when LE
1740 * has actually been enabled. During power on, the
1741 * update in powered_update_hci will take care of it.
1742 */
1743 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1744 struct hci_request req;
1745
1746 hci_dev_lock(hdev);
1747
1748 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001749 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001750 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001751 hci_req_run(&req, NULL);
1752
1753 hci_dev_unlock(hdev);
1754 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001755}
1756
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001757static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001758{
1759 struct mgmt_mode *cp = data;
1760 struct hci_cp_write_le_host_supported hci_cp;
1761 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001762 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001763 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001764 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001765
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001766 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001767
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001768 if (!lmp_le_capable(hdev))
1769 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1770 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001771
Johan Hedberga7e80f22013-01-09 16:05:19 +02001772 if (cp->val != 0x00 && cp->val != 0x01)
1773 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1774 MGMT_STATUS_INVALID_PARAMS);
1775
Johan Hedbergc73eee92013-04-19 18:35:21 +03001776 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001777 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001778 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1779 MGMT_STATUS_REJECTED);
1780
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001781 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001782
1783 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001784 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001785
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001786 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001787 bool changed = false;
1788
1789 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1790 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1791 changed = true;
1792 }
1793
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001794 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1795 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001796 changed = true;
1797 }
1798
Johan Hedberg06199cf2012-02-22 16:37:11 +02001799 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1800 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001801 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001802
1803 if (changed)
1804 err = new_settings(hdev, sk);
1805
Johan Hedberg1de028c2012-02-29 19:55:35 -08001806 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001807 }
1808
Johan Hedberg4375f102013-09-25 13:26:10 +03001809 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1810 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001811 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001812 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001813 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001814 }
1815
1816 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1817 if (!cmd) {
1818 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001819 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001820 }
1821
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001822 hci_req_init(&req, hdev);
1823
Johan Hedberg06199cf2012-02-22 16:37:11 +02001824 memset(&hci_cp, 0, sizeof(hci_cp));
1825
1826 if (val) {
1827 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001828 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001829 } else {
1830 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1831 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001832 }
1833
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001834 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1835 &hci_cp);
1836
1837 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301838 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001839 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001840
Johan Hedberg1de028c2012-02-29 19:55:35 -08001841unlock:
1842 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001843 return err;
1844}
1845
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001846/* This is a helper function to test for pending mgmt commands that can
1847 * cause CoD or EIR HCI commands. We can only allow one such pending
1848 * mgmt command at a time since otherwise we cannot easily track what
1849 * the current values are, will be, and based on that calculate if a new
1850 * HCI command needs to be sent and if yes with what value.
1851 */
1852static bool pending_eir_or_class(struct hci_dev *hdev)
1853{
1854 struct pending_cmd *cmd;
1855
1856 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1857 switch (cmd->opcode) {
1858 case MGMT_OP_ADD_UUID:
1859 case MGMT_OP_REMOVE_UUID:
1860 case MGMT_OP_SET_DEV_CLASS:
1861 case MGMT_OP_SET_POWERED:
1862 return true;
1863 }
1864 }
1865
1866 return false;
1867}
1868
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001869static const u8 bluetooth_base_uuid[] = {
1870 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1871 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1872};
1873
1874static u8 get_uuid_size(const u8 *uuid)
1875{
1876 u32 val;
1877
1878 if (memcmp(uuid, bluetooth_base_uuid, 12))
1879 return 128;
1880
1881 val = get_unaligned_le32(&uuid[12]);
1882 if (val > 0xffff)
1883 return 32;
1884
1885 return 16;
1886}
1887
Johan Hedberg92da6092013-03-15 17:06:55 -05001888static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1889{
1890 struct pending_cmd *cmd;
1891
1892 hci_dev_lock(hdev);
1893
1894 cmd = mgmt_pending_find(mgmt_op, hdev);
1895 if (!cmd)
1896 goto unlock;
1897
1898 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1899 hdev->dev_class, 3);
1900
1901 mgmt_pending_remove(cmd);
1902
1903unlock:
1904 hci_dev_unlock(hdev);
1905}
1906
1907static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1908{
1909 BT_DBG("status 0x%02x", status);
1910
1911 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1912}
1913
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001914static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001915{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001916 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001917 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001918 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001919 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001920 int err;
1921
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001922 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001923
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001924 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001925
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001926 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001927 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001928 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001929 goto failed;
1930 }
1931
Andre Guedes92c4c202012-06-07 19:05:44 -03001932 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001933 if (!uuid) {
1934 err = -ENOMEM;
1935 goto failed;
1936 }
1937
1938 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001939 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001940 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001941
Johan Hedbergde66aa62013-01-27 00:31:27 +02001942 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001943
Johan Hedberg890ea892013-03-15 17:06:52 -05001944 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001945
Johan Hedberg890ea892013-03-15 17:06:52 -05001946 update_class(&req);
1947 update_eir(&req);
1948
Johan Hedberg92da6092013-03-15 17:06:55 -05001949 err = hci_req_run(&req, add_uuid_complete);
1950 if (err < 0) {
1951 if (err != -ENODATA)
1952 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001953
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001954 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001955 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001956 goto failed;
1957 }
1958
1959 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001960 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001961 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001962 goto failed;
1963 }
1964
1965 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001966
1967failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001968 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001969 return err;
1970}
1971
Johan Hedberg24b78d02012-02-23 23:24:30 +02001972static bool enable_service_cache(struct hci_dev *hdev)
1973{
1974 if (!hdev_is_powered(hdev))
1975 return false;
1976
1977 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001978 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1979 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001980 return true;
1981 }
1982
1983 return false;
1984}
1985
Johan Hedberg92da6092013-03-15 17:06:55 -05001986static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1987{
1988 BT_DBG("status 0x%02x", status);
1989
1990 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1991}
1992
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001993static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001994 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001995{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001996 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001997 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001998 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001999 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 -05002000 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002001 int err, found;
2002
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002003 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002004
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002005 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002006
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002007 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002008 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002009 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002010 goto unlock;
2011 }
2012
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002013 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
2014 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002015
Johan Hedberg24b78d02012-02-23 23:24:30 +02002016 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002017 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002018 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002019 goto unlock;
2020 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002021
Johan Hedberg9246a862012-02-23 21:33:16 +02002022 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002023 }
2024
2025 found = 0;
2026
Johan Hedberg056341c2013-01-27 00:31:30 +02002027 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002028 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2029 continue;
2030
2031 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002032 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002033 found++;
2034 }
2035
2036 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002037 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002038 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002039 goto unlock;
2040 }
2041
Johan Hedberg9246a862012-02-23 21:33:16 +02002042update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002043 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002044
Johan Hedberg890ea892013-03-15 17:06:52 -05002045 update_class(&req);
2046 update_eir(&req);
2047
Johan Hedberg92da6092013-03-15 17:06:55 -05002048 err = hci_req_run(&req, remove_uuid_complete);
2049 if (err < 0) {
2050 if (err != -ENODATA)
2051 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002052
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002053 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002054 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002055 goto unlock;
2056 }
2057
2058 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002059 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002060 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002061 goto unlock;
2062 }
2063
2064 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002065
2066unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002067 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002068 return err;
2069}
2070
Johan Hedberg92da6092013-03-15 17:06:55 -05002071static void set_class_complete(struct hci_dev *hdev, u8 status)
2072{
2073 BT_DBG("status 0x%02x", status);
2074
2075 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2076}
2077
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002078static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002079 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002080{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002081 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002082 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002083 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002084 int err;
2085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002086 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002087
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002088 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002089 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2090 MGMT_STATUS_NOT_SUPPORTED);
2091
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002092 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002093
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002094 if (pending_eir_or_class(hdev)) {
2095 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2096 MGMT_STATUS_BUSY);
2097 goto unlock;
2098 }
2099
2100 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2101 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2102 MGMT_STATUS_INVALID_PARAMS);
2103 goto unlock;
2104 }
2105
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002106 hdev->major_class = cp->major;
2107 hdev->minor_class = cp->minor;
2108
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002109 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002110 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002111 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002112 goto unlock;
2113 }
2114
Johan Hedberg890ea892013-03-15 17:06:52 -05002115 hci_req_init(&req, hdev);
2116
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002117 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002118 hci_dev_unlock(hdev);
2119 cancel_delayed_work_sync(&hdev->service_cache);
2120 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002121 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002122 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002123
Johan Hedberg890ea892013-03-15 17:06:52 -05002124 update_class(&req);
2125
Johan Hedberg92da6092013-03-15 17:06:55 -05002126 err = hci_req_run(&req, set_class_complete);
2127 if (err < 0) {
2128 if (err != -ENODATA)
2129 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002130
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002131 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002132 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002133 goto unlock;
2134 }
2135
2136 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002137 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002138 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002139 goto unlock;
2140 }
2141
2142 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002143
Johan Hedbergb5235a62012-02-21 14:32:24 +02002144unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002145 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002146 return err;
2147}
2148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002149static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002150 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002151{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002152 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002153 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002154 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002155
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002156 BT_DBG("request for %s", hdev->name);
2157
2158 if (!lmp_bredr_capable(hdev))
2159 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2160 MGMT_STATUS_NOT_SUPPORTED);
2161
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002162 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002163
Johan Hedberg86742e12011-11-07 23:13:38 +02002164 expected_len = sizeof(*cp) + key_count *
2165 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002166 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002167 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002168 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002169 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002170 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002171 }
2172
Johan Hedberg4ae14302013-01-20 14:27:13 +02002173 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2174 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2175 MGMT_STATUS_INVALID_PARAMS);
2176
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002177 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002178 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002179
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002180 for (i = 0; i < key_count; i++) {
2181 struct mgmt_link_key_info *key = &cp->keys[i];
2182
2183 if (key->addr.type != BDADDR_BREDR)
2184 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2185 MGMT_STATUS_INVALID_PARAMS);
2186 }
2187
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002188 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002189
2190 hci_link_keys_clear(hdev);
2191
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002192 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002193 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002194 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002195 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002196
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002197 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002198 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002199
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002200 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002201 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002202 }
2203
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002204 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002205
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002206 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002207
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002208 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002209}
2210
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002211static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002212 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002213{
2214 struct mgmt_ev_device_unpaired ev;
2215
2216 bacpy(&ev.addr.bdaddr, bdaddr);
2217 ev.addr.type = addr_type;
2218
2219 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002220 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002221}
2222
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002223static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002224 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002225{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002226 struct mgmt_cp_unpair_device *cp = data;
2227 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002228 struct hci_cp_disconnect dc;
2229 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002230 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002231 int err;
2232
Johan Hedberga8a1d192011-11-10 15:54:38 +02002233 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002234 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2235 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002236
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002237 if (!bdaddr_type_is_valid(cp->addr.type))
2238 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2239 MGMT_STATUS_INVALID_PARAMS,
2240 &rp, sizeof(rp));
2241
Johan Hedberg118da702013-01-20 14:27:20 +02002242 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2243 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2244 MGMT_STATUS_INVALID_PARAMS,
2245 &rp, sizeof(rp));
2246
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002247 hci_dev_lock(hdev);
2248
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002249 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002250 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002251 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002252 goto unlock;
2253 }
2254
Andre Guedes591f47f2012-04-24 21:02:49 -03002255 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002256 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2257 else
2258 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002259
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002260 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002261 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002262 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002263 goto unlock;
2264 }
2265
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002266 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002267 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002268 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002269 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002270 else
2271 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002272 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002273 } else {
2274 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002275 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002276
Johan Hedberga8a1d192011-11-10 15:54:38 +02002277 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002278 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002279 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002280 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002281 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002282 }
2283
Johan Hedberg124f6e32012-02-09 13:50:12 +02002284 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002285 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002286 if (!cmd) {
2287 err = -ENOMEM;
2288 goto unlock;
2289 }
2290
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002291 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002292 dc.reason = 0x13; /* Remote User Terminated Connection */
2293 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2294 if (err < 0)
2295 mgmt_pending_remove(cmd);
2296
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002297unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002298 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002299 return err;
2300}
2301
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002302static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002303 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002304{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002305 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002306 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002307 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002308 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002309 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002310 int err;
2311
2312 BT_DBG("");
2313
Johan Hedberg06a63b12013-01-20 14:27:21 +02002314 memset(&rp, 0, sizeof(rp));
2315 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2316 rp.addr.type = cp->addr.type;
2317
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002318 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002319 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2320 MGMT_STATUS_INVALID_PARAMS,
2321 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002322
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002323 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002324
2325 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002326 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2327 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002328 goto failed;
2329 }
2330
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002331 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002332 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2333 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002334 goto failed;
2335 }
2336
Andre Guedes591f47f2012-04-24 21:02:49 -03002337 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002338 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2339 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002340 else
2341 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002342
Vishal Agarwalf9607272012-06-13 05:32:43 +05302343 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002344 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2345 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002346 goto failed;
2347 }
2348
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002349 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002350 if (!cmd) {
2351 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002352 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002353 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002354
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002355 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002356 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002357
2358 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2359 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002360 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002361
2362failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002363 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002364 return err;
2365}
2366
Andre Guedes57c14772012-04-24 21:02:50 -03002367static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002368{
2369 switch (link_type) {
2370 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002371 switch (addr_type) {
2372 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002373 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002374
Johan Hedberg48264f02011-11-09 13:58:58 +02002375 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002376 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002377 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002378 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002379
Johan Hedberg4c659c32011-11-07 23:13:39 +02002380 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002381 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002382 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002383 }
2384}
2385
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002386static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2387 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002388{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002389 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002390 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002391 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002392 int err;
2393 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002394
2395 BT_DBG("");
2396
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002397 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002398
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002399 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002400 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002401 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002402 goto unlock;
2403 }
2404
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002405 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002406 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2407 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002408 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002409 }
2410
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002411 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002412 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002413 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002414 err = -ENOMEM;
2415 goto unlock;
2416 }
2417
Johan Hedberg2784eb42011-01-21 13:56:35 +02002418 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002419 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002420 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2421 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002422 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002423 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002424 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002425 continue;
2426 i++;
2427 }
2428
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002429 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002430
Johan Hedberg4c659c32011-11-07 23:13:39 +02002431 /* Recalculate length in case of filtered SCO connections, etc */
2432 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002433
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002434 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002435 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002436
Johan Hedberga38528f2011-01-22 06:46:43 +02002437 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002438
2439unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002440 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002441 return err;
2442}
2443
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002444static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002445 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002446{
2447 struct pending_cmd *cmd;
2448 int err;
2449
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002450 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002451 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002452 if (!cmd)
2453 return -ENOMEM;
2454
Johan Hedbergd8457692012-02-17 14:24:57 +02002455 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002456 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002457 if (err < 0)
2458 mgmt_pending_remove(cmd);
2459
2460 return err;
2461}
2462
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002463static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002464 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002465{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002466 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002467 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002468 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002469 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002470 int err;
2471
2472 BT_DBG("");
2473
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002474 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002475
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002476 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002477 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002478 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002479 goto failed;
2480 }
2481
Johan Hedbergd8457692012-02-17 14:24:57 +02002482 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002483 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002484 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002485 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002486 goto failed;
2487 }
2488
2489 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002490 struct mgmt_cp_pin_code_neg_reply ncp;
2491
2492 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002493
2494 BT_ERR("PIN code is not 16 bytes long");
2495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002496 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002497 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002498 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002499 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002500
2501 goto failed;
2502 }
2503
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002504 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002505 if (!cmd) {
2506 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002507 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002508 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002509
Johan Hedbergd8457692012-02-17 14:24:57 +02002510 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002511 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002512 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002513
2514 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2515 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002516 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002517
2518failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002519 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002520 return err;
2521}
2522
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002523static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2524 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002525{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002526 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002527
2528 BT_DBG("");
2529
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002530 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002531
2532 hdev->io_capability = cp->io_capability;
2533
2534 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002535 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002536
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002537 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002538
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002539 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2540 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002541}
2542
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002543static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002544{
2545 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002546 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002547
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002548 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002549 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2550 continue;
2551
Johan Hedberge9a416b2011-02-19 12:05:56 -03002552 if (cmd->user_data != conn)
2553 continue;
2554
2555 return cmd;
2556 }
2557
2558 return NULL;
2559}
2560
2561static void pairing_complete(struct pending_cmd *cmd, u8 status)
2562{
2563 struct mgmt_rp_pair_device rp;
2564 struct hci_conn *conn = cmd->user_data;
2565
Johan Hedbergba4e5642011-11-11 00:07:34 +02002566 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002567 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002568
Johan Hedbergaee9b212012-02-18 15:07:59 +02002569 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002570 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002571
2572 /* So we don't get further callbacks for this connection */
2573 conn->connect_cfm_cb = NULL;
2574 conn->security_cfm_cb = NULL;
2575 conn->disconn_cfm_cb = NULL;
2576
David Herrmann76a68ba2013-04-06 20:28:37 +02002577 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002578
Johan Hedberga664b5b2011-02-19 12:06:02 -03002579 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002580}
2581
2582static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2583{
2584 struct pending_cmd *cmd;
2585
2586 BT_DBG("status %u", status);
2587
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002588 cmd = find_pairing(conn);
2589 if (!cmd)
2590 BT_DBG("Unable to find a pending command");
2591 else
Johan Hedberge2113262012-02-18 15:20:03 +02002592 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002593}
2594
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302595static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2596{
2597 struct pending_cmd *cmd;
2598
2599 BT_DBG("status %u", status);
2600
2601 if (!status)
2602 return;
2603
2604 cmd = find_pairing(conn);
2605 if (!cmd)
2606 BT_DBG("Unable to find a pending command");
2607 else
2608 pairing_complete(cmd, mgmt_status(status));
2609}
2610
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002611static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002612 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002613{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002614 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002615 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002616 struct pending_cmd *cmd;
2617 u8 sec_level, auth_type;
2618 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002619 int err;
2620
2621 BT_DBG("");
2622
Szymon Jancf950a30e2013-01-18 12:48:07 +01002623 memset(&rp, 0, sizeof(rp));
2624 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2625 rp.addr.type = cp->addr.type;
2626
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002627 if (!bdaddr_type_is_valid(cp->addr.type))
2628 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2629 MGMT_STATUS_INVALID_PARAMS,
2630 &rp, sizeof(rp));
2631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002632 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002633
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002634 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002635 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2636 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002637 goto unlock;
2638 }
2639
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002640 sec_level = BT_SECURITY_MEDIUM;
2641 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002642 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002643 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002644 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002645
Andre Guedes591f47f2012-04-24 21:02:49 -03002646 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002647 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2648 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002649 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002650 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2651 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002652
Ville Tervo30e76272011-02-22 16:10:53 -03002653 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002654 int status;
2655
2656 if (PTR_ERR(conn) == -EBUSY)
2657 status = MGMT_STATUS_BUSY;
2658 else
2659 status = MGMT_STATUS_CONNECT_FAILED;
2660
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002661 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002662 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002663 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002664 goto unlock;
2665 }
2666
2667 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002668 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002669 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002670 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002671 goto unlock;
2672 }
2673
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002674 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002675 if (!cmd) {
2676 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002677 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002678 goto unlock;
2679 }
2680
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002681 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002682 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002683 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302684 else
2685 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002686
Johan Hedberge9a416b2011-02-19 12:05:56 -03002687 conn->security_cfm_cb = pairing_complete_cb;
2688 conn->disconn_cfm_cb = pairing_complete_cb;
2689 conn->io_capability = cp->io_cap;
2690 cmd->user_data = conn;
2691
2692 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002693 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002694 pairing_complete(cmd, 0);
2695
2696 err = 0;
2697
2698unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002699 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002700 return err;
2701}
2702
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002703static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2704 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002705{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002706 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002707 struct pending_cmd *cmd;
2708 struct hci_conn *conn;
2709 int err;
2710
2711 BT_DBG("");
2712
Johan Hedberg28424702012-02-02 04:02:29 +02002713 hci_dev_lock(hdev);
2714
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002715 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002716 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002717 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002718 goto unlock;
2719 }
2720
Johan Hedberg28424702012-02-02 04:02:29 +02002721 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2722 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002723 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002724 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002725 goto unlock;
2726 }
2727
2728 conn = cmd->user_data;
2729
2730 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002731 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002732 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002733 goto unlock;
2734 }
2735
2736 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002738 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002739 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002740unlock:
2741 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002742 return err;
2743}
2744
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002745static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002746 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002747 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002748{
Johan Hedberga5c29682011-02-19 12:05:57 -03002749 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002750 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002751 int err;
2752
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002753 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002754
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002755 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002756 err = cmd_complete(sk, hdev->id, mgmt_op,
2757 MGMT_STATUS_NOT_POWERED, addr,
2758 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002759 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002760 }
2761
Johan Hedberg1707c602013-03-15 17:07:15 -05002762 if (addr->type == BDADDR_BREDR)
2763 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002764 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002765 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002766
Johan Hedberg272d90d2012-02-09 15:26:12 +02002767 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002768 err = cmd_complete(sk, hdev->id, mgmt_op,
2769 MGMT_STATUS_NOT_CONNECTED, addr,
2770 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002771 goto done;
2772 }
2773
Johan Hedberg1707c602013-03-15 17:07:15 -05002774 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002775 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002776 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002777
Brian Gix5fe57d92011-12-21 16:12:13 -08002778 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002779 err = cmd_complete(sk, hdev->id, mgmt_op,
2780 MGMT_STATUS_SUCCESS, addr,
2781 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002782 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002783 err = cmd_complete(sk, hdev->id, mgmt_op,
2784 MGMT_STATUS_FAILED, addr,
2785 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002786
Brian Gix47c15e22011-11-16 13:53:14 -08002787 goto done;
2788 }
2789
Johan Hedberg1707c602013-03-15 17:07:15 -05002790 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002791 if (!cmd) {
2792 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002793 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002794 }
2795
Brian Gix0df4c182011-11-16 13:53:13 -08002796 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002797 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2798 struct hci_cp_user_passkey_reply cp;
2799
Johan Hedberg1707c602013-03-15 17:07:15 -05002800 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002801 cp.passkey = passkey;
2802 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2803 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002804 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2805 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002806
Johan Hedberga664b5b2011-02-19 12:06:02 -03002807 if (err < 0)
2808 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002809
Brian Gix0df4c182011-11-16 13:53:13 -08002810done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002811 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002812 return err;
2813}
2814
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302815static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2816 void *data, u16 len)
2817{
2818 struct mgmt_cp_pin_code_neg_reply *cp = data;
2819
2820 BT_DBG("");
2821
Johan Hedberg1707c602013-03-15 17:07:15 -05002822 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302823 MGMT_OP_PIN_CODE_NEG_REPLY,
2824 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2825}
2826
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002827static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2828 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002829{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002830 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002831
2832 BT_DBG("");
2833
2834 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002835 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002836 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002837
Johan Hedberg1707c602013-03-15 17:07:15 -05002838 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002839 MGMT_OP_USER_CONFIRM_REPLY,
2840 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002841}
2842
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002843static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002844 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002845{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002846 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002847
2848 BT_DBG("");
2849
Johan Hedberg1707c602013-03-15 17:07:15 -05002850 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002851 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2852 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002853}
2854
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002855static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2856 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002857{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002858 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002859
2860 BT_DBG("");
2861
Johan Hedberg1707c602013-03-15 17:07:15 -05002862 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002863 MGMT_OP_USER_PASSKEY_REPLY,
2864 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002865}
2866
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002867static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002868 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002869{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002870 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002871
2872 BT_DBG("");
2873
Johan Hedberg1707c602013-03-15 17:07:15 -05002874 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002875 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2876 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002877}
2878
Johan Hedberg13928972013-03-15 17:07:00 -05002879static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002880{
Johan Hedberg13928972013-03-15 17:07:00 -05002881 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002882 struct hci_cp_write_local_name cp;
2883
Johan Hedberg13928972013-03-15 17:07:00 -05002884 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002885
Johan Hedberg890ea892013-03-15 17:06:52 -05002886 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002887}
2888
Johan Hedberg13928972013-03-15 17:07:00 -05002889static void set_name_complete(struct hci_dev *hdev, u8 status)
2890{
2891 struct mgmt_cp_set_local_name *cp;
2892 struct pending_cmd *cmd;
2893
2894 BT_DBG("status 0x%02x", status);
2895
2896 hci_dev_lock(hdev);
2897
2898 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2899 if (!cmd)
2900 goto unlock;
2901
2902 cp = cmd->param;
2903
2904 if (status)
2905 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2906 mgmt_status(status));
2907 else
2908 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2909 cp, sizeof(*cp));
2910
2911 mgmt_pending_remove(cmd);
2912
2913unlock:
2914 hci_dev_unlock(hdev);
2915}
2916
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002917static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002918 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002919{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002920 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002921 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002922 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002923 int err;
2924
2925 BT_DBG("");
2926
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002927 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002928
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002929 /* If the old values are the same as the new ones just return a
2930 * direct command complete event.
2931 */
2932 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2933 !memcmp(hdev->short_name, cp->short_name,
2934 sizeof(hdev->short_name))) {
2935 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2936 data, len);
2937 goto failed;
2938 }
2939
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002940 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002941
Johan Hedbergb5235a62012-02-21 14:32:24 +02002942 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002943 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002944
2945 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002946 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002947 if (err < 0)
2948 goto failed;
2949
2950 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002951 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002952
Johan Hedbergb5235a62012-02-21 14:32:24 +02002953 goto failed;
2954 }
2955
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002956 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002957 if (!cmd) {
2958 err = -ENOMEM;
2959 goto failed;
2960 }
2961
Johan Hedberg13928972013-03-15 17:07:00 -05002962 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2963
Johan Hedberg890ea892013-03-15 17:06:52 -05002964 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002965
2966 if (lmp_bredr_capable(hdev)) {
2967 update_name(&req);
2968 update_eir(&req);
2969 }
2970
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07002971 /* The name is stored in the scan response data and so
2972 * no need to udpate the advertising data here.
2973 */
Johan Hedberg3f985052013-03-15 17:07:02 -05002974 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07002975 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05002976
Johan Hedberg13928972013-03-15 17:07:00 -05002977 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002978 if (err < 0)
2979 mgmt_pending_remove(cmd);
2980
2981failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002982 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002983 return err;
2984}
2985
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002986static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002987 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002988{
Szymon Jancc35938b2011-03-22 13:12:21 +01002989 struct pending_cmd *cmd;
2990 int err;
2991
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002992 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002993
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002994 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002995
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002996 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002997 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002998 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002999 goto unlock;
3000 }
3001
Andre Guedes9a1a1992012-07-24 15:03:48 -03003002 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003003 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003004 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003005 goto unlock;
3006 }
3007
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003008 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003009 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003010 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003011 goto unlock;
3012 }
3013
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003014 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003015 if (!cmd) {
3016 err = -ENOMEM;
3017 goto unlock;
3018 }
3019
3020 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3021 if (err < 0)
3022 mgmt_pending_remove(cmd);
3023
3024unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003025 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003026 return err;
3027}
3028
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003029static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003030 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003031{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003032 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003033 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003034 int err;
3035
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003036 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003037
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003038 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003039
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003040 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003041 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01003042 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003043 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01003044 else
Szymon Janca6785be2012-12-13 15:11:21 +01003045 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003046
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003047 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003048 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003049
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003050 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003051 return err;
3052}
3053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003054static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003055 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003056{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003057 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003058 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003059 int err;
3060
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003061 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003062
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003063 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003064
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003065 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003066 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003067 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003068 else
Szymon Janca6785be2012-12-13 15:11:21 +01003069 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003070
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003071 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003072 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003073
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003074 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003075 return err;
3076}
3077
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003078static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3079{
3080 struct pending_cmd *cmd;
3081 u8 type;
3082 int err;
3083
3084 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3085
3086 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3087 if (!cmd)
3088 return -ENOENT;
3089
3090 type = hdev->discovery.type;
3091
3092 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3093 &type, sizeof(type));
3094 mgmt_pending_remove(cmd);
3095
3096 return err;
3097}
3098
Andre Guedes7c307722013-04-30 15:29:28 -03003099static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3100{
3101 BT_DBG("status %d", status);
3102
3103 if (status) {
3104 hci_dev_lock(hdev);
3105 mgmt_start_discovery_failed(hdev, status);
3106 hci_dev_unlock(hdev);
3107 return;
3108 }
3109
3110 hci_dev_lock(hdev);
3111 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3112 hci_dev_unlock(hdev);
3113
3114 switch (hdev->discovery.type) {
3115 case DISCOV_TYPE_LE:
3116 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003117 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003118 break;
3119
3120 case DISCOV_TYPE_INTERLEAVED:
3121 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003122 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003123 break;
3124
3125 case DISCOV_TYPE_BREDR:
3126 break;
3127
3128 default:
3129 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3130 }
3131}
3132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003133static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003134 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003135{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003136 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003137 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003138 struct hci_cp_le_set_scan_param param_cp;
3139 struct hci_cp_le_set_scan_enable enable_cp;
3140 struct hci_cp_inquiry inq_cp;
3141 struct hci_request req;
3142 /* General inquiry access code (GIAC) */
3143 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003144 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003145 int err;
3146
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003147 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003148
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003149 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003150
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003151 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003152 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003153 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003154 goto failed;
3155 }
3156
Andre Guedes642be6c2012-03-21 00:03:37 -03003157 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3158 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3159 MGMT_STATUS_BUSY);
3160 goto failed;
3161 }
3162
Johan Hedbergff9ef572012-01-04 14:23:45 +02003163 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003164 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003165 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003166 goto failed;
3167 }
3168
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003169 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003170 if (!cmd) {
3171 err = -ENOMEM;
3172 goto failed;
3173 }
3174
Andre Guedes4aab14e2012-02-17 20:39:36 -03003175 hdev->discovery.type = cp->type;
3176
Andre Guedes7c307722013-04-30 15:29:28 -03003177 hci_req_init(&req, hdev);
3178
Andre Guedes4aab14e2012-02-17 20:39:36 -03003179 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003180 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003181 status = mgmt_bredr_support(hdev);
3182 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003183 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003184 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003185 mgmt_pending_remove(cmd);
3186 goto failed;
3187 }
3188
Andre Guedes7c307722013-04-30 15:29:28 -03003189 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3190 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3191 MGMT_STATUS_BUSY);
3192 mgmt_pending_remove(cmd);
3193 goto failed;
3194 }
3195
3196 hci_inquiry_cache_flush(hdev);
3197
3198 memset(&inq_cp, 0, sizeof(inq_cp));
3199 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003200 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003201 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003202 break;
3203
3204 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003205 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003206 status = mgmt_le_support(hdev);
3207 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003208 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003209 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003210 mgmt_pending_remove(cmd);
3211 goto failed;
3212 }
3213
Andre Guedes7c307722013-04-30 15:29:28 -03003214 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003215 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003216 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3217 MGMT_STATUS_NOT_SUPPORTED);
3218 mgmt_pending_remove(cmd);
3219 goto failed;
3220 }
3221
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003222 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003223 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3224 MGMT_STATUS_REJECTED);
3225 mgmt_pending_remove(cmd);
3226 goto failed;
3227 }
3228
3229 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3230 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3231 MGMT_STATUS_BUSY);
3232 mgmt_pending_remove(cmd);
3233 goto failed;
3234 }
3235
3236 memset(&param_cp, 0, sizeof(param_cp));
3237 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003238 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3239 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07003240 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
3241 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
3242 else
3243 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03003244 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3245 &param_cp);
3246
3247 memset(&enable_cp, 0, sizeof(enable_cp));
3248 enable_cp.enable = LE_SCAN_ENABLE;
3249 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3250 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3251 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003252 break;
3253
Andre Guedesf39799f2012-02-17 20:39:35 -03003254 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003255 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3256 MGMT_STATUS_INVALID_PARAMS);
3257 mgmt_pending_remove(cmd);
3258 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003259 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003260
Andre Guedes7c307722013-04-30 15:29:28 -03003261 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003262 if (err < 0)
3263 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003264 else
3265 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003266
3267failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003268 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003269 return err;
3270}
3271
Andre Guedes1183fdc2013-04-30 15:29:35 -03003272static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3273{
3274 struct pending_cmd *cmd;
3275 int err;
3276
3277 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3278 if (!cmd)
3279 return -ENOENT;
3280
3281 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3282 &hdev->discovery.type, sizeof(hdev->discovery.type));
3283 mgmt_pending_remove(cmd);
3284
3285 return err;
3286}
3287
Andre Guedes0e05bba2013-04-30 15:29:33 -03003288static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3289{
3290 BT_DBG("status %d", status);
3291
3292 hci_dev_lock(hdev);
3293
3294 if (status) {
3295 mgmt_stop_discovery_failed(hdev, status);
3296 goto unlock;
3297 }
3298
3299 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3300
3301unlock:
3302 hci_dev_unlock(hdev);
3303}
3304
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003305static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003306 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003307{
Johan Hedbergd9306502012-02-20 23:25:18 +02003308 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003309 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003310 struct hci_cp_remote_name_req_cancel cp;
3311 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003312 struct hci_request req;
3313 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003314 int err;
3315
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003316 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003317
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003318 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003319
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003320 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003321 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003322 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3323 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003324 goto unlock;
3325 }
3326
3327 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003328 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003329 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3330 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003331 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003332 }
3333
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003334 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003335 if (!cmd) {
3336 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003337 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003338 }
3339
Andre Guedes0e05bba2013-04-30 15:29:33 -03003340 hci_req_init(&req, hdev);
3341
Andre Guedese0d9727e2012-03-20 15:15:36 -03003342 switch (hdev->discovery.state) {
3343 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003344 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3345 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3346 } else {
3347 cancel_delayed_work(&hdev->le_scan_disable);
3348
3349 memset(&enable_cp, 0, sizeof(enable_cp));
3350 enable_cp.enable = LE_SCAN_DISABLE;
3351 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3352 sizeof(enable_cp), &enable_cp);
3353 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003354
Andre Guedese0d9727e2012-03-20 15:15:36 -03003355 break;
3356
3357 case DISCOVERY_RESOLVING:
3358 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003359 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003360 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003361 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003362 err = cmd_complete(sk, hdev->id,
3363 MGMT_OP_STOP_DISCOVERY, 0,
3364 &mgmt_cp->type,
3365 sizeof(mgmt_cp->type));
3366 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3367 goto unlock;
3368 }
3369
3370 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003371 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3372 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003373
3374 break;
3375
3376 default:
3377 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003378
3379 mgmt_pending_remove(cmd);
3380 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3381 MGMT_STATUS_FAILED, &mgmt_cp->type,
3382 sizeof(mgmt_cp->type));
3383 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003384 }
3385
Andre Guedes0e05bba2013-04-30 15:29:33 -03003386 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003387 if (err < 0)
3388 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003389 else
3390 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003391
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003392unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003393 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003394 return err;
3395}
3396
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003397static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003398 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003399{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003400 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003401 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003402 int err;
3403
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003404 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003405
Johan Hedberg561aafb2012-01-04 13:31:59 +02003406 hci_dev_lock(hdev);
3407
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003408 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003409 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003410 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003411 goto failed;
3412 }
3413
Johan Hedberga198e7b2012-02-17 14:27:06 +02003414 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003415 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003416 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003417 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003418 goto failed;
3419 }
3420
3421 if (cp->name_known) {
3422 e->name_state = NAME_KNOWN;
3423 list_del(&e->list);
3424 } else {
3425 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003426 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003427 }
3428
Johan Hedberge3846622013-01-09 15:29:33 +02003429 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3430 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003431
3432failed:
3433 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003434 return err;
3435}
3436
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003437static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003438 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003439{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003440 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003441 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003442 int err;
3443
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003444 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003445
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003446 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003447 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3448 MGMT_STATUS_INVALID_PARAMS,
3449 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003450
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003451 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003452
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003453 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003454 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003455 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003456 else
Szymon Janca6785be2012-12-13 15:11:21 +01003457 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003458
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003459 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003460 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003461
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003462 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003463
3464 return err;
3465}
3466
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003467static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003468 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003469{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003470 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003471 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003472 int err;
3473
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003474 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003475
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003476 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003477 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3478 MGMT_STATUS_INVALID_PARAMS,
3479 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003480
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003481 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003482
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003483 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003484 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003485 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003486 else
Szymon Janca6785be2012-12-13 15:11:21 +01003487 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003488
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003489 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003490 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003491
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003492 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003493
3494 return err;
3495}
3496
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003497static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3498 u16 len)
3499{
3500 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003501 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003502 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003503 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003504
3505 BT_DBG("%s", hdev->name);
3506
Szymon Jancc72d4b82012-03-16 16:02:57 +01003507 source = __le16_to_cpu(cp->source);
3508
3509 if (source > 0x0002)
3510 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3511 MGMT_STATUS_INVALID_PARAMS);
3512
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003513 hci_dev_lock(hdev);
3514
Szymon Jancc72d4b82012-03-16 16:02:57 +01003515 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003516 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3517 hdev->devid_product = __le16_to_cpu(cp->product);
3518 hdev->devid_version = __le16_to_cpu(cp->version);
3519
3520 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3521
Johan Hedberg890ea892013-03-15 17:06:52 -05003522 hci_req_init(&req, hdev);
3523 update_eir(&req);
3524 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003525
3526 hci_dev_unlock(hdev);
3527
3528 return err;
3529}
3530
Johan Hedberg4375f102013-09-25 13:26:10 +03003531static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3532{
3533 struct cmd_lookup match = { NULL, hdev };
3534
3535 if (status) {
3536 u8 mgmt_err = mgmt_status(status);
3537
3538 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3539 cmd_status_rsp, &mgmt_err);
3540 return;
3541 }
3542
3543 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3544 &match);
3545
3546 new_settings(hdev, match.sk);
3547
3548 if (match.sk)
3549 sock_put(match.sk);
3550}
3551
Marcel Holtmann21b51872013-10-10 09:47:53 -07003552static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3553 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003554{
3555 struct mgmt_mode *cp = data;
3556 struct pending_cmd *cmd;
3557 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003558 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003559 int err;
3560
3561 BT_DBG("request for %s", hdev->name);
3562
Johan Hedberge6fe7982013-10-02 15:45:22 +03003563 status = mgmt_le_support(hdev);
3564 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003565 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003566 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003567
3568 if (cp->val != 0x00 && cp->val != 0x01)
3569 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3570 MGMT_STATUS_INVALID_PARAMS);
3571
3572 hci_dev_lock(hdev);
3573
3574 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003575 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003576
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003577 /* The following conditions are ones which mean that we should
3578 * not do any HCI communication but directly send a mgmt
3579 * response to user space (after toggling the flag if
3580 * necessary).
3581 */
3582 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003583 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003584 bool changed = false;
3585
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003586 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3587 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003588 changed = true;
3589 }
3590
3591 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3592 if (err < 0)
3593 goto unlock;
3594
3595 if (changed)
3596 err = new_settings(hdev, sk);
3597
3598 goto unlock;
3599 }
3600
3601 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3602 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3603 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3604 MGMT_STATUS_BUSY);
3605 goto unlock;
3606 }
3607
3608 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3609 if (!cmd) {
3610 err = -ENOMEM;
3611 goto unlock;
3612 }
3613
3614 hci_req_init(&req, hdev);
3615
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003616 if (val)
3617 enable_advertising(&req);
3618 else
3619 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003620
3621 err = hci_req_run(&req, set_advertising_complete);
3622 if (err < 0)
3623 mgmt_pending_remove(cmd);
3624
3625unlock:
3626 hci_dev_unlock(hdev);
3627 return err;
3628}
3629
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003630static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3631 void *data, u16 len)
3632{
3633 struct mgmt_cp_set_static_address *cp = data;
3634 int err;
3635
3636 BT_DBG("%s", hdev->name);
3637
Marcel Holtmann62af4442013-10-02 22:10:32 -07003638 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003639 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003640 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003641
3642 if (hdev_is_powered(hdev))
3643 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3644 MGMT_STATUS_REJECTED);
3645
3646 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3647 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3648 return cmd_status(sk, hdev->id,
3649 MGMT_OP_SET_STATIC_ADDRESS,
3650 MGMT_STATUS_INVALID_PARAMS);
3651
3652 /* Two most significant bits shall be set */
3653 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3654 return cmd_status(sk, hdev->id,
3655 MGMT_OP_SET_STATIC_ADDRESS,
3656 MGMT_STATUS_INVALID_PARAMS);
3657 }
3658
3659 hci_dev_lock(hdev);
3660
3661 bacpy(&hdev->static_addr, &cp->bdaddr);
3662
3663 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3664
3665 hci_dev_unlock(hdev);
3666
3667 return err;
3668}
3669
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003670static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3671 void *data, u16 len)
3672{
3673 struct mgmt_cp_set_scan_params *cp = data;
3674 __u16 interval, window;
3675 int err;
3676
3677 BT_DBG("%s", hdev->name);
3678
3679 if (!lmp_le_capable(hdev))
3680 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3681 MGMT_STATUS_NOT_SUPPORTED);
3682
3683 interval = __le16_to_cpu(cp->interval);
3684
3685 if (interval < 0x0004 || interval > 0x4000)
3686 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3687 MGMT_STATUS_INVALID_PARAMS);
3688
3689 window = __le16_to_cpu(cp->window);
3690
3691 if (window < 0x0004 || window > 0x4000)
3692 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3693 MGMT_STATUS_INVALID_PARAMS);
3694
Marcel Holtmann899e1072013-10-14 09:55:32 -07003695 if (window > interval)
3696 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3697 MGMT_STATUS_INVALID_PARAMS);
3698
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003699 hci_dev_lock(hdev);
3700
3701 hdev->le_scan_interval = interval;
3702 hdev->le_scan_window = window;
3703
3704 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3705
3706 hci_dev_unlock(hdev);
3707
3708 return err;
3709}
3710
Johan Hedberg33e38b32013-03-15 17:07:05 -05003711static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3712{
3713 struct pending_cmd *cmd;
3714
3715 BT_DBG("status 0x%02x", status);
3716
3717 hci_dev_lock(hdev);
3718
3719 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3720 if (!cmd)
3721 goto unlock;
3722
3723 if (status) {
3724 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3725 mgmt_status(status));
3726 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003727 struct mgmt_mode *cp = cmd->param;
3728
3729 if (cp->val)
3730 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3731 else
3732 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3733
Johan Hedberg33e38b32013-03-15 17:07:05 -05003734 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3735 new_settings(hdev, cmd->sk);
3736 }
3737
3738 mgmt_pending_remove(cmd);
3739
3740unlock:
3741 hci_dev_unlock(hdev);
3742}
3743
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003744static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003745 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003746{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003747 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003748 struct pending_cmd *cmd;
3749 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003750 int err;
3751
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003752 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003753
Johan Hedberg56f87902013-10-02 13:43:13 +03003754 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3755 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003756 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3757 MGMT_STATUS_NOT_SUPPORTED);
3758
Johan Hedberga7e80f22013-01-09 16:05:19 +02003759 if (cp->val != 0x00 && cp->val != 0x01)
3760 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3761 MGMT_STATUS_INVALID_PARAMS);
3762
Johan Hedberg5400c042012-02-21 16:40:33 +02003763 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003764 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003765 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003766
3767 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003768 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003769 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003770
3771 hci_dev_lock(hdev);
3772
Johan Hedberg05cbf292013-03-15 17:07:07 -05003773 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3774 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3775 MGMT_STATUS_BUSY);
3776 goto unlock;
3777 }
3778
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003779 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3780 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3781 hdev);
3782 goto unlock;
3783 }
3784
Johan Hedberg33e38b32013-03-15 17:07:05 -05003785 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3786 data, len);
3787 if (!cmd) {
3788 err = -ENOMEM;
3789 goto unlock;
3790 }
3791
3792 hci_req_init(&req, hdev);
3793
Johan Hedberg406d7802013-03-15 17:07:09 -05003794 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003795
3796 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003797 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003798 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003799 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003800 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003801 }
3802
Johan Hedberg33e38b32013-03-15 17:07:05 -05003803unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003804 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003805
Antti Julkuf6422ec2011-06-22 13:11:56 +03003806 return err;
3807}
3808
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003809static void set_bredr_scan(struct hci_request *req)
3810{
3811 struct hci_dev *hdev = req->hdev;
3812 u8 scan = 0;
3813
3814 /* Ensure that fast connectable is disabled. This function will
3815 * not do anything if the page scan parameters are already what
3816 * they should be.
3817 */
3818 write_fast_connectable(req, false);
3819
3820 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3821 scan |= SCAN_PAGE;
3822 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3823 scan |= SCAN_INQUIRY;
3824
3825 if (scan)
3826 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3827}
3828
Johan Hedberg0663ca22013-10-02 13:43:14 +03003829static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3830{
3831 struct pending_cmd *cmd;
3832
3833 BT_DBG("status 0x%02x", status);
3834
3835 hci_dev_lock(hdev);
3836
3837 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3838 if (!cmd)
3839 goto unlock;
3840
3841 if (status) {
3842 u8 mgmt_err = mgmt_status(status);
3843
3844 /* We need to restore the flag if related HCI commands
3845 * failed.
3846 */
3847 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3848
3849 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3850 } else {
3851 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3852 new_settings(hdev, cmd->sk);
3853 }
3854
3855 mgmt_pending_remove(cmd);
3856
3857unlock:
3858 hci_dev_unlock(hdev);
3859}
3860
3861static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3862{
3863 struct mgmt_mode *cp = data;
3864 struct pending_cmd *cmd;
3865 struct hci_request req;
3866 int err;
3867
3868 BT_DBG("request for %s", hdev->name);
3869
3870 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3871 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3872 MGMT_STATUS_NOT_SUPPORTED);
3873
3874 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3875 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3876 MGMT_STATUS_REJECTED);
3877
3878 if (cp->val != 0x00 && cp->val != 0x01)
3879 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3880 MGMT_STATUS_INVALID_PARAMS);
3881
3882 hci_dev_lock(hdev);
3883
3884 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3885 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3886 goto unlock;
3887 }
3888
3889 if (!hdev_is_powered(hdev)) {
3890 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003891 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3892 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3893 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3894 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3895 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3896 }
3897
3898 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3899
3900 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3901 if (err < 0)
3902 goto unlock;
3903
3904 err = new_settings(hdev, sk);
3905 goto unlock;
3906 }
3907
3908 /* Reject disabling when powered on */
3909 if (!cp->val) {
3910 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3911 MGMT_STATUS_REJECTED);
3912 goto unlock;
3913 }
3914
3915 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3916 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3917 MGMT_STATUS_BUSY);
3918 goto unlock;
3919 }
3920
3921 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3922 if (!cmd) {
3923 err = -ENOMEM;
3924 goto unlock;
3925 }
3926
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003927 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03003928 * generates the correct flags.
3929 */
3930 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3931
3932 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003933
3934 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3935 set_bredr_scan(&req);
3936
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07003937 /* Since only the advertising data flags will change, there
3938 * is no need to update the scan response data.
3939 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003940 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003941
Johan Hedberg0663ca22013-10-02 13:43:14 +03003942 err = hci_req_run(&req, set_bredr_complete);
3943 if (err < 0)
3944 mgmt_pending_remove(cmd);
3945
3946unlock:
3947 hci_dev_unlock(hdev);
3948 return err;
3949}
3950
Johan Hedberg3f706b72013-01-20 14:27:16 +02003951static bool ltk_is_valid(struct mgmt_ltk_info *key)
3952{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003953 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3954 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003955 if (key->master != 0x00 && key->master != 0x01)
3956 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003957 if (!bdaddr_type_is_le(key->addr.type))
3958 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003959 return true;
3960}
3961
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003962static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003963 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003964{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003965 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3966 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003967 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003968
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003969 BT_DBG("request for %s", hdev->name);
3970
3971 if (!lmp_le_capable(hdev))
3972 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3973 MGMT_STATUS_NOT_SUPPORTED);
3974
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003975 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003976
3977 expected_len = sizeof(*cp) + key_count *
3978 sizeof(struct mgmt_ltk_info);
3979 if (expected_len != len) {
3980 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003981 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003982 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003983 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003984 }
3985
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003986 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003987
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003988 for (i = 0; i < key_count; i++) {
3989 struct mgmt_ltk_info *key = &cp->keys[i];
3990
Johan Hedberg3f706b72013-01-20 14:27:16 +02003991 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003992 return cmd_status(sk, hdev->id,
3993 MGMT_OP_LOAD_LONG_TERM_KEYS,
3994 MGMT_STATUS_INVALID_PARAMS);
3995 }
3996
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003997 hci_dev_lock(hdev);
3998
3999 hci_smp_ltks_clear(hdev);
4000
4001 for (i = 0; i < key_count; i++) {
4002 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004003 u8 type, addr_type;
4004
4005 if (key->addr.type == BDADDR_LE_PUBLIC)
4006 addr_type = ADDR_LE_DEV_PUBLIC;
4007 else
4008 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004009
4010 if (key->master)
4011 type = HCI_SMP_LTK;
4012 else
4013 type = HCI_SMP_LTK_SLAVE;
4014
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004015 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004016 type, 0, key->authenticated, key->val,
4017 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004018 }
4019
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004020 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4021 NULL, 0);
4022
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004023 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004024
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004025 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004026}
4027
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004028static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004029 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4030 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004031 bool var_len;
4032 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004033} mgmt_handlers[] = {
4034 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004035 { read_version, false, MGMT_READ_VERSION_SIZE },
4036 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4037 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4038 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4039 { set_powered, false, MGMT_SETTING_SIZE },
4040 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4041 { set_connectable, false, MGMT_SETTING_SIZE },
4042 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4043 { set_pairable, false, MGMT_SETTING_SIZE },
4044 { set_link_security, false, MGMT_SETTING_SIZE },
4045 { set_ssp, false, MGMT_SETTING_SIZE },
4046 { set_hs, false, MGMT_SETTING_SIZE },
4047 { set_le, false, MGMT_SETTING_SIZE },
4048 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4049 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4050 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4051 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4052 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4053 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4054 { disconnect, false, MGMT_DISCONNECT_SIZE },
4055 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4056 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4057 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4058 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4059 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4060 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4061 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4062 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4063 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4064 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4065 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4066 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
4067 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
4068 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4069 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4070 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4071 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4072 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4073 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004074 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004075 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004076 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004077 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004078 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004079};
4080
4081
Johan Hedberg03811012010-12-08 00:21:06 +02004082int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4083{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004084 void *buf;
4085 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004086 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004087 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004088 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004089 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004090 int err;
4091
4092 BT_DBG("got %zu bytes", msglen);
4093
4094 if (msglen < sizeof(*hdr))
4095 return -EINVAL;
4096
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004097 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004098 if (!buf)
4099 return -ENOMEM;
4100
4101 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4102 err = -EFAULT;
4103 goto done;
4104 }
4105
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004106 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004107 opcode = __le16_to_cpu(hdr->opcode);
4108 index = __le16_to_cpu(hdr->index);
4109 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004110
4111 if (len != msglen - sizeof(*hdr)) {
4112 err = -EINVAL;
4113 goto done;
4114 }
4115
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004116 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004117 hdev = hci_dev_get(index);
4118 if (!hdev) {
4119 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004120 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004121 goto done;
4122 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004123
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004124 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4125 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004126 err = cmd_status(sk, index, opcode,
4127 MGMT_STATUS_INVALID_INDEX);
4128 goto done;
4129 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004130 }
4131
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004132 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004133 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004134 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004135 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004136 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004137 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004138 }
4139
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004140 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004141 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004142 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004143 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004144 goto done;
4145 }
4146
Johan Hedbergbe22b542012-03-01 22:24:41 +02004147 handler = &mgmt_handlers[opcode];
4148
4149 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004150 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004151 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004152 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004153 goto done;
4154 }
4155
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004156 if (hdev)
4157 mgmt_init_hdev(sk, hdev);
4158
4159 cp = buf + sizeof(*hdr);
4160
Johan Hedbergbe22b542012-03-01 22:24:41 +02004161 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004162 if (err < 0)
4163 goto done;
4164
Johan Hedberg03811012010-12-08 00:21:06 +02004165 err = msglen;
4166
4167done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004168 if (hdev)
4169 hci_dev_put(hdev);
4170
Johan Hedberg03811012010-12-08 00:21:06 +02004171 kfree(buf);
4172 return err;
4173}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004174
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004175void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004176{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004177 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004178 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004179
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004180 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004181}
4182
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004183void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004184{
Johan Hedberg5f159032012-03-02 03:13:19 +02004185 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004186
Marcel Holtmann1514b892013-10-06 08:25:01 -07004187 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004188 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004189
Johan Hedberg744cf192011-11-08 20:40:14 +02004190 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004191
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004192 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004193}
4194
Johan Hedberg229ab392013-03-15 17:06:53 -05004195static void powered_complete(struct hci_dev *hdev, u8 status)
4196{
4197 struct cmd_lookup match = { NULL, hdev };
4198
4199 BT_DBG("status 0x%02x", status);
4200
4201 hci_dev_lock(hdev);
4202
4203 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4204
4205 new_settings(hdev, match.sk);
4206
4207 hci_dev_unlock(hdev);
4208
4209 if (match.sk)
4210 sock_put(match.sk);
4211}
4212
Johan Hedberg70da6242013-03-15 17:06:51 -05004213static int powered_update_hci(struct hci_dev *hdev)
4214{
Johan Hedberg890ea892013-03-15 17:06:52 -05004215 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004216 u8 link_sec;
4217
Johan Hedberg890ea892013-03-15 17:06:52 -05004218 hci_req_init(&req, hdev);
4219
Johan Hedberg70da6242013-03-15 17:06:51 -05004220 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4221 !lmp_host_ssp_capable(hdev)) {
4222 u8 ssp = 1;
4223
Johan Hedberg890ea892013-03-15 17:06:52 -05004224 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004225 }
4226
Johan Hedbergc73eee92013-04-19 18:35:21 +03004227 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4228 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004229 struct hci_cp_write_le_host_supported cp;
4230
4231 cp.le = 1;
4232 cp.simul = lmp_le_br_capable(hdev);
4233
4234 /* Check first if we already have the right
4235 * host state (host features set)
4236 */
4237 if (cp.le != lmp_host_le_capable(hdev) ||
4238 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004239 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4240 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004241 }
4242
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004243 if (lmp_le_capable(hdev)) {
4244 /* Set random address to static address if configured */
4245 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4246 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4247 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004248
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004249 /* Make sure the controller has a good default for
4250 * advertising data. This also applies to the case
4251 * where BR/EDR was toggled during the AUTO_OFF phase.
4252 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004253 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004254 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004255 update_scan_rsp_data(&req);
4256 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004257
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004258 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4259 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004260 }
4261
Johan Hedberg70da6242013-03-15 17:06:51 -05004262 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4263 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004264 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4265 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004266
4267 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004268 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4269 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004270 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004271 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004272 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004273 }
4274
Johan Hedberg229ab392013-03-15 17:06:53 -05004275 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004276}
4277
Johan Hedberg744cf192011-11-08 20:40:14 +02004278int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004279{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004280 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004281 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4282 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004283 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004284
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004285 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4286 return 0;
4287
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004288 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004289 if (powered_update_hci(hdev) == 0)
4290 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004291
Johan Hedberg229ab392013-03-15 17:06:53 -05004292 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4293 &match);
4294 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004295 }
4296
Johan Hedberg229ab392013-03-15 17:06:53 -05004297 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4298 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4299
4300 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4301 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4302 zero_cod, sizeof(zero_cod), NULL);
4303
4304new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004305 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004306
4307 if (match.sk)
4308 sock_put(match.sk);
4309
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004310 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004311}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004312
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004313void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004314{
4315 struct pending_cmd *cmd;
4316 u8 status;
4317
4318 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4319 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004320 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004321
4322 if (err == -ERFKILL)
4323 status = MGMT_STATUS_RFKILLED;
4324 else
4325 status = MGMT_STATUS_FAILED;
4326
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004327 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004328
4329 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004330}
4331
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004332void mgmt_discoverable_timeout(struct hci_dev *hdev)
4333{
4334 struct hci_request req;
4335 u8 scan = SCAN_PAGE;
4336
4337 hci_dev_lock(hdev);
4338
4339 /* When discoverable timeout triggers, then just make sure
4340 * the limited discoverable flag is cleared. Even in the case
4341 * of a timeout triggered from general discoverable, it is
4342 * safe to unconditionally clear the flag.
4343 */
4344 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
4345
4346 hci_req_init(&req, hdev);
4347 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
4348 update_class(&req);
4349 hci_req_run(&req, NULL);
4350
4351 hdev->discov_timeout = 0;
4352
4353 hci_dev_unlock(hdev);
4354}
4355
Marcel Holtmann86a75642013-10-15 06:33:54 -07004356void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004357{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004358 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004359
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004360 /* Nothing needed here if there's a pending command since that
4361 * commands request completion callback takes care of everything
4362 * necessary.
4363 */
4364 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004365 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004366
Marcel Holtmann86a75642013-10-15 06:33:54 -07004367 if (discoverable)
4368 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4369 else
4370 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004371
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004372 if (changed)
Marcel Holtmann86a75642013-10-15 06:33:54 -07004373 new_settings(hdev, NULL);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004374}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004375
Marcel Holtmanna3309162013-10-15 06:33:55 -07004376void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004377{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004378 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004379
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004380 /* Nothing needed here if there's a pending command since that
4381 * commands request completion callback takes care of everything
4382 * necessary.
4383 */
4384 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004385 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004386
Marcel Holtmanna3309162013-10-15 06:33:55 -07004387 if (connectable)
4388 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4389 else
4390 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004391
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004392 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004393 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004394}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004395
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004396void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004397{
Johan Hedbergca69b792011-11-11 18:10:00 +02004398 u8 mgmt_err = mgmt_status(status);
4399
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004400 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004401 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004402 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004403
4404 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004405 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004406 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004407}
4408
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004409void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4410 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004411{
Johan Hedberg86742e12011-11-07 23:13:38 +02004412 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004413
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004414 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004415
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004416 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004417 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004418 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004419 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004420 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004421 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004422
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004423 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004424}
Johan Hedbergf7520542011-01-20 12:34:39 +02004425
Marcel Holtmann083368f2013-10-15 14:26:29 -07004426void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004427{
4428 struct mgmt_ev_new_long_term_key ev;
4429
4430 memset(&ev, 0, sizeof(ev));
4431
4432 ev.store_hint = persistent;
4433 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004434 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004435 ev.key.authenticated = key->authenticated;
4436 ev.key.enc_size = key->enc_size;
4437 ev.key.ediv = key->ediv;
4438
4439 if (key->type == HCI_SMP_LTK)
4440 ev.key.master = 1;
4441
4442 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4443 memcpy(ev.key.val, key->val, sizeof(key->val));
4444
Marcel Holtmann083368f2013-10-15 14:26:29 -07004445 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004446}
4447
Marcel Holtmann94933992013-10-15 10:26:39 -07004448static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4449 u8 data_len)
4450{
4451 eir[eir_len++] = sizeof(type) + data_len;
4452 eir[eir_len++] = type;
4453 memcpy(&eir[eir_len], data, data_len);
4454 eir_len += data_len;
4455
4456 return eir_len;
4457}
4458
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004459void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4460 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4461 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004462{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004463 char buf[512];
4464 struct mgmt_ev_device_connected *ev = (void *) buf;
4465 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004466
Johan Hedbergb644ba32012-01-17 21:48:47 +02004467 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004468 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004469
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004470 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004471
Johan Hedbergb644ba32012-01-17 21:48:47 +02004472 if (name_len > 0)
4473 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004474 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004475
4476 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004477 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004478 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004479
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004480 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004481
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004482 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4483 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004484}
4485
Johan Hedberg8962ee72011-01-20 12:40:27 +02004486static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4487{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004488 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004489 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004490 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004491
Johan Hedberg88c3df12012-02-09 14:27:38 +02004492 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4493 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004494
Johan Hedbergaee9b212012-02-18 15:07:59 +02004495 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004496 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004497
4498 *sk = cmd->sk;
4499 sock_hold(*sk);
4500
Johan Hedberga664b5b2011-02-19 12:06:02 -03004501 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004502}
4503
Johan Hedberg124f6e32012-02-09 13:50:12 +02004504static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004505{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004506 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004507 struct mgmt_cp_unpair_device *cp = cmd->param;
4508 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004509
4510 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004511 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4512 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004513
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004514 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4515
Johan Hedbergaee9b212012-02-18 15:07:59 +02004516 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004517
4518 mgmt_pending_remove(cmd);
4519}
4520
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004521void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4522 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004523{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004524 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004525 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004526
Johan Hedberg744cf192011-11-08 20:40:14 +02004527 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004528
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004529 bacpy(&ev.addr.bdaddr, bdaddr);
4530 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4531 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004532
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004533 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004534
4535 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004536 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004537
Johan Hedberg124f6e32012-02-09 13:50:12 +02004538 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004539 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004540}
4541
Marcel Holtmann78929242013-10-06 23:55:47 -07004542void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4543 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004544{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004545 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004546 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004547
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004548 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4549 hdev);
4550
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004551 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004552 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004553 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004554
Johan Hedberg88c3df12012-02-09 14:27:38 +02004555 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004556 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004557
Marcel Holtmann78929242013-10-06 23:55:47 -07004558 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4559 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004560
Johan Hedberga664b5b2011-02-19 12:06:02 -03004561 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004562}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004563
Marcel Holtmann445608d2013-10-06 23:55:48 -07004564void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4565 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004566{
4567 struct mgmt_ev_connect_failed ev;
4568
Johan Hedberg4c659c32011-11-07 23:13:39 +02004569 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004570 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004571 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004572
Marcel Holtmann445608d2013-10-06 23:55:48 -07004573 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004574}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004575
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004576void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004577{
4578 struct mgmt_ev_pin_code_request ev;
4579
Johan Hedbergd8457692012-02-17 14:24:57 +02004580 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004581 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004582 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004583
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004584 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004585}
4586
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004587void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4588 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004589{
4590 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004591 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004592
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004593 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004594 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004595 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004596
Johan Hedbergd8457692012-02-17 14:24:57 +02004597 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004598 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004599
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004600 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4601 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004602
Johan Hedberga664b5b2011-02-19 12:06:02 -03004603 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004604}
4605
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004606void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4607 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004608{
4609 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004610 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004611
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004612 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004613 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004614 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004615
Johan Hedbergd8457692012-02-17 14:24:57 +02004616 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004617 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004618
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004619 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4620 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004621
Johan Hedberga664b5b2011-02-19 12:06:02 -03004622 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004623}
Johan Hedberga5c29682011-02-19 12:05:57 -03004624
Johan Hedberg744cf192011-11-08 20:40:14 +02004625int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004626 u8 link_type, u8 addr_type, __le32 value,
4627 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004628{
4629 struct mgmt_ev_user_confirm_request ev;
4630
Johan Hedberg744cf192011-11-08 20:40:14 +02004631 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004632
Johan Hedberg272d90d2012-02-09 15:26:12 +02004633 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004634 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004635 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004636 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004637
Johan Hedberg744cf192011-11-08 20:40:14 +02004638 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004639 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004640}
4641
Johan Hedberg272d90d2012-02-09 15:26:12 +02004642int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004643 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004644{
4645 struct mgmt_ev_user_passkey_request ev;
4646
4647 BT_DBG("%s", hdev->name);
4648
Johan Hedberg272d90d2012-02-09 15:26:12 +02004649 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004650 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004651
4652 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004653 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004654}
4655
Brian Gix0df4c182011-11-16 13:53:13 -08004656static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004657 u8 link_type, u8 addr_type, u8 status,
4658 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004659{
4660 struct pending_cmd *cmd;
4661 struct mgmt_rp_user_confirm_reply rp;
4662 int err;
4663
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004664 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004665 if (!cmd)
4666 return -ENOENT;
4667
Johan Hedberg272d90d2012-02-09 15:26:12 +02004668 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004669 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004670 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004671 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004672
Johan Hedberga664b5b2011-02-19 12:06:02 -03004673 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004674
4675 return err;
4676}
4677
Johan Hedberg744cf192011-11-08 20:40:14 +02004678int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004679 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004680{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004681 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004682 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004683}
4684
Johan Hedberg272d90d2012-02-09 15:26:12 +02004685int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004686 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004687{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004688 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004689 status,
4690 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004691}
Johan Hedberg2a611692011-02-19 12:06:00 -03004692
Brian Gix604086b2011-11-23 08:28:33 -08004693int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004694 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004695{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004696 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004697 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004698}
4699
Johan Hedberg272d90d2012-02-09 15:26:12 +02004700int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004701 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004702{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004703 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004704 status,
4705 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004706}
4707
Johan Hedberg92a25252012-09-06 18:39:26 +03004708int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4709 u8 link_type, u8 addr_type, u32 passkey,
4710 u8 entered)
4711{
4712 struct mgmt_ev_passkey_notify ev;
4713
4714 BT_DBG("%s", hdev->name);
4715
4716 bacpy(&ev.addr.bdaddr, bdaddr);
4717 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4718 ev.passkey = __cpu_to_le32(passkey);
4719 ev.entered = entered;
4720
4721 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4722}
4723
Marcel Holtmanne5460992013-10-15 14:26:23 -07004724void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4725 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004726{
4727 struct mgmt_ev_auth_failed ev;
4728
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004729 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004730 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004731 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004732
Marcel Holtmanne5460992013-10-15 14:26:23 -07004733 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004734}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004735
Marcel Holtmann464996a2013-10-15 14:26:24 -07004736void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004737{
4738 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004739 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004740
4741 if (status) {
4742 u8 mgmt_err = mgmt_status(status);
4743 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004744 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004745 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004746 }
4747
Marcel Holtmann464996a2013-10-15 14:26:24 -07004748 if (test_bit(HCI_AUTH, &hdev->flags))
4749 changed = !test_and_set_bit(HCI_LINK_SECURITY,
4750 &hdev->dev_flags);
4751 else
4752 changed = test_and_clear_bit(HCI_LINK_SECURITY,
4753 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02004754
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004755 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004756 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004757
Johan Hedberg47990ea2012-02-22 11:58:37 +02004758 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07004759 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004760
4761 if (match.sk)
4762 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004763}
4764
Johan Hedberg890ea892013-03-15 17:06:52 -05004765static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004766{
Johan Hedberg890ea892013-03-15 17:06:52 -05004767 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004768 struct hci_cp_write_eir cp;
4769
Johan Hedberg976eb202012-10-24 21:12:01 +03004770 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004771 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004772
Johan Hedbergc80da272012-02-22 15:38:48 +02004773 memset(hdev->eir, 0, sizeof(hdev->eir));
4774
Johan Hedbergcacaf522012-02-21 00:52:42 +02004775 memset(&cp, 0, sizeof(cp));
4776
Johan Hedberg890ea892013-03-15 17:06:52 -05004777 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004778}
4779
Marcel Holtmann3e248562013-10-15 14:26:25 -07004780void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004781{
4782 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004783 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004784 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004785
4786 if (status) {
4787 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004788
4789 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004790 &hdev->dev_flags)) {
4791 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004792 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004793 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004794
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004795 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4796 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004797 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004798 }
4799
4800 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004801 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004802 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004803 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4804 if (!changed)
4805 changed = test_and_clear_bit(HCI_HS_ENABLED,
4806 &hdev->dev_flags);
4807 else
4808 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004809 }
4810
4811 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4812
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004813 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07004814 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004815
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004816 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004817 sock_put(match.sk);
4818
Johan Hedberg890ea892013-03-15 17:06:52 -05004819 hci_req_init(&req, hdev);
4820
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004821 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004822 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004823 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004824 clear_eir(&req);
4825
4826 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004827}
4828
Johan Hedberg92da6092013-03-15 17:06:55 -05004829static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004830{
4831 struct cmd_lookup *match = data;
4832
Johan Hedberg90e70452012-02-23 23:09:40 +02004833 if (match->sk == NULL) {
4834 match->sk = cmd->sk;
4835 sock_hold(match->sk);
4836 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004837}
4838
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004839void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
4840 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004841{
Johan Hedberg90e70452012-02-23 23:09:40 +02004842 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004843
Johan Hedberg92da6092013-03-15 17:06:55 -05004844 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4845 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4846 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004847
4848 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004849 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
4850 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004851
4852 if (match.sk)
4853 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004854}
4855
Marcel Holtmann7667da32013-10-15 14:26:27 -07004856void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004857{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004858 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004859 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004860
Johan Hedberg13928972013-03-15 17:07:00 -05004861 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07004862 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004863
4864 memset(&ev, 0, sizeof(ev));
4865 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004866 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004867
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004868 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004869 if (!cmd) {
4870 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004871
Johan Hedberg13928972013-03-15 17:07:00 -05004872 /* If this is a HCI command related to powering on the
4873 * HCI dev don't send any mgmt signals.
4874 */
4875 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07004876 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004877 }
4878
Marcel Holtmann7667da32013-10-15 14:26:27 -07004879 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4880 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004881}
Szymon Jancc35938b2011-03-22 13:12:21 +01004882
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004883void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
4884 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004885{
4886 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01004887
Johan Hedberg744cf192011-11-08 20:40:14 +02004888 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004889
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004890 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004891 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004892 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01004893
4894 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004895 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4896 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004897 } else {
4898 struct mgmt_rp_read_local_oob_data rp;
4899
4900 memcpy(rp.hash, hash, sizeof(rp.hash));
4901 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4902
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004903 cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4904 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004905 }
4906
4907 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01004908}
Johan Hedberge17acd42011-03-30 23:57:16 +03004909
Marcel Holtmann901801b2013-10-06 23:55:51 -07004910void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4911 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4912 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004913{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004914 char buf[512];
4915 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004916 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004917
Andre Guedes12602d02013-04-30 15:29:40 -03004918 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004919 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004920
Johan Hedberg1dc06092012-01-15 21:01:23 +02004921 /* Leave 5 bytes for a potential CoD field */
4922 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004923 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004924
Johan Hedberg1dc06092012-01-15 21:01:23 +02004925 memset(buf, 0, sizeof(buf));
4926
Johan Hedberge319d2e2012-01-15 19:51:59 +02004927 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004928 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004929 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004930 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304931 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004932 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304933 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004934
Johan Hedberg1dc06092012-01-15 21:01:23 +02004935 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004936 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004937
Johan Hedberg1dc06092012-01-15 21:01:23 +02004938 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4939 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004940 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004941
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004942 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004943 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004944
Marcel Holtmann901801b2013-10-06 23:55:51 -07004945 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004946}
Johan Hedberga88a9652011-03-30 13:18:12 +03004947
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004948void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4949 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004950{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004951 struct mgmt_ev_device_found *ev;
4952 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4953 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004954
Johan Hedbergb644ba32012-01-17 21:48:47 +02004955 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004956
Johan Hedbergb644ba32012-01-17 21:48:47 +02004957 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004958
Johan Hedbergb644ba32012-01-17 21:48:47 +02004959 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004960 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004961 ev->rssi = rssi;
4962
4963 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004964 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004965
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004966 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004967
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004968 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004969}
Johan Hedberg314b2382011-04-27 10:29:57 -04004970
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004971void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004972{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004973 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004974 struct pending_cmd *cmd;
4975
Andre Guedes343fb142011-11-22 17:14:19 -03004976 BT_DBG("%s discovering %u", hdev->name, discovering);
4977
Johan Hedberg164a6e72011-11-01 17:06:44 +02004978 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004979 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004980 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004981 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004982
4983 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004984 u8 type = hdev->discovery.type;
4985
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004986 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4987 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004988 mgmt_pending_remove(cmd);
4989 }
4990
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004991 memset(&ev, 0, sizeof(ev));
4992 ev.type = hdev->discovery.type;
4993 ev.discovering = discovering;
4994
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004995 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004996}
Antti Julku5e762442011-08-25 16:48:02 +03004997
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004998int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004999{
5000 struct pending_cmd *cmd;
5001 struct mgmt_ev_device_blocked ev;
5002
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005003 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005004
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005005 bacpy(&ev.addr.bdaddr, bdaddr);
5006 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005007
Johan Hedberg744cf192011-11-08 20:40:14 +02005008 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005009 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005010}
5011
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005012int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005013{
5014 struct pending_cmd *cmd;
5015 struct mgmt_ev_device_unblocked ev;
5016
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005017 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005018
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005019 bacpy(&ev.addr.bdaddr, bdaddr);
5020 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005021
Johan Hedberg744cf192011-11-08 20:40:14 +02005022 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005023 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005024}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005025
5026static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5027{
5028 BT_DBG("%s status %u", hdev->name, status);
5029
5030 /* Clear the advertising mgmt setting if we failed to re-enable it */
5031 if (status) {
5032 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005033 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005034 }
5035}
5036
5037void mgmt_reenable_advertising(struct hci_dev *hdev)
5038{
5039 struct hci_request req;
5040
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005041 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005042 return;
5043
5044 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5045 return;
5046
5047 hci_req_init(&req, hdev);
5048 enable_advertising(&req);
5049
5050 /* If this fails we have no option but to let user space know
5051 * that we've disabled advertising.
5052 */
5053 if (hci_req_run(&req, adv_enable_complete) < 0) {
5054 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005055 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005056 }
5057}