blob: 59bbf434ba9a638dbe3d948d3427a237c99ad9b1 [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{
541 return 0;
542}
543
544static void update_scan_rsp_data(struct hci_request *req)
545{
546 struct hci_dev *hdev = req->hdev;
547 struct hci_cp_le_set_scan_rsp_data cp;
548 u8 len;
549
550 if (!lmp_le_capable(hdev))
551 return;
552
553 memset(&cp, 0, sizeof(cp));
554
555 len = create_scan_rsp_data(hdev, cp.data);
556
557 if (hdev->adv_data_len == len &&
558 memcmp(cp.data, hdev->adv_data, len) == 0)
559 return;
560
561 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
562 hdev->adv_data_len = len;
563
564 cp.length = len;
565
566 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
567}
568
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700569static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700570{
571 u8 ad_len = 0, flags = 0;
572 size_t name_len;
573
574 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
575 flags |= LE_AD_GENERAL;
576
577 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
578 if (lmp_le_br_capable(hdev))
579 flags |= LE_AD_SIM_LE_BREDR_CTRL;
580 if (lmp_host_le_br_capable(hdev))
581 flags |= LE_AD_SIM_LE_BREDR_HOST;
582 } else {
583 flags |= LE_AD_NO_BREDR;
584 }
585
586 if (flags) {
587 BT_DBG("adv flags 0x%02x", flags);
588
589 ptr[0] = 2;
590 ptr[1] = EIR_FLAGS;
591 ptr[2] = flags;
592
593 ad_len += 3;
594 ptr += 3;
595 }
596
597 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
598 ptr[0] = 2;
599 ptr[1] = EIR_TX_POWER;
600 ptr[2] = (u8) hdev->adv_tx_power;
601
602 ad_len += 3;
603 ptr += 3;
604 }
605
606 name_len = strlen(hdev->dev_name);
607 if (name_len > 0) {
608 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
609
610 if (name_len > max_len) {
611 name_len = max_len;
612 ptr[1] = EIR_NAME_SHORT;
613 } else
614 ptr[1] = EIR_NAME_COMPLETE;
615
616 ptr[0] = name_len + 1;
617
618 memcpy(ptr + 2, hdev->dev_name, name_len);
619
620 ad_len += (name_len + 2);
621 ptr += (name_len + 2);
622 }
623
624 return ad_len;
625}
626
627static void update_ad(struct hci_request *req)
628{
629 struct hci_dev *hdev = req->hdev;
630 struct hci_cp_le_set_adv_data cp;
631 u8 len;
632
633 if (!lmp_le_capable(hdev))
634 return;
635
636 memset(&cp, 0, sizeof(cp));
637
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700638 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700639
640 if (hdev->adv_data_len == len &&
641 memcmp(cp.data, hdev->adv_data, len) == 0)
642 return;
643
644 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
645 hdev->adv_data_len = len;
646
647 cp.length = len;
648
649 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
650}
651
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300652static void create_eir(struct hci_dev *hdev, u8 *data)
653{
654 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300655 size_t name_len;
656
657 name_len = strlen(hdev->dev_name);
658
659 if (name_len > 0) {
660 /* EIR Data type */
661 if (name_len > 48) {
662 name_len = 48;
663 ptr[1] = EIR_NAME_SHORT;
664 } else
665 ptr[1] = EIR_NAME_COMPLETE;
666
667 /* EIR Data length */
668 ptr[0] = name_len + 1;
669
670 memcpy(ptr + 2, hdev->dev_name, name_len);
671
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300672 ptr += (name_len + 2);
673 }
674
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100675 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700676 ptr[0] = 2;
677 ptr[1] = EIR_TX_POWER;
678 ptr[2] = (u8) hdev->inq_tx_power;
679
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700680 ptr += 3;
681 }
682
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700683 if (hdev->devid_source > 0) {
684 ptr[0] = 9;
685 ptr[1] = EIR_DEVICE_ID;
686
687 put_unaligned_le16(hdev->devid_source, ptr + 2);
688 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
689 put_unaligned_le16(hdev->devid_product, ptr + 6);
690 put_unaligned_le16(hdev->devid_version, ptr + 8);
691
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700692 ptr += 10;
693 }
694
Johan Hedberg213202e2013-01-27 00:31:33 +0200695 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200696 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200697 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300698}
699
Johan Hedberg890ea892013-03-15 17:06:52 -0500700static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300701{
Johan Hedberg890ea892013-03-15 17:06:52 -0500702 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300703 struct hci_cp_write_eir cp;
704
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200705 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500706 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200707
Johan Hedberg976eb202012-10-24 21:12:01 +0300708 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500709 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300710
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200711 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500712 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300713
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200714 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500715 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300716
717 memset(&cp, 0, sizeof(cp));
718
719 create_eir(hdev, cp.data);
720
721 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500722 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300723
724 memcpy(hdev->eir, cp.data, sizeof(cp.data));
725
Johan Hedberg890ea892013-03-15 17:06:52 -0500726 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300727}
728
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200729static u8 get_service_classes(struct hci_dev *hdev)
730{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300731 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200732 u8 val = 0;
733
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300734 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200735 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200736
737 return val;
738}
739
Johan Hedberg890ea892013-03-15 17:06:52 -0500740static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200741{
Johan Hedberg890ea892013-03-15 17:06:52 -0500742 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200743 u8 cod[3];
744
745 BT_DBG("%s", hdev->name);
746
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200747 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500748 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200749
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200750 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500751 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200752
753 cod[0] = hdev->minor_class;
754 cod[1] = hdev->major_class;
755 cod[2] = get_service_classes(hdev);
756
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700757 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
758 cod[1] |= 0x20;
759
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200760 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500761 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200762
Johan Hedberg890ea892013-03-15 17:06:52 -0500763 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200764}
765
Johan Hedberg7d785252011-12-15 00:47:39 +0200766static void service_cache_off(struct work_struct *work)
767{
768 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300769 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500770 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200771
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200772 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200773 return;
774
Johan Hedberg890ea892013-03-15 17:06:52 -0500775 hci_req_init(&req, hdev);
776
Johan Hedberg7d785252011-12-15 00:47:39 +0200777 hci_dev_lock(hdev);
778
Johan Hedberg890ea892013-03-15 17:06:52 -0500779 update_eir(&req);
780 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200781
782 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500783
784 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200785}
786
Johan Hedberg6a919082012-02-28 06:17:26 +0200787static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200788{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200789 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200790 return;
791
Johan Hedberg4f87da82012-03-02 19:55:56 +0200792 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200793
Johan Hedberg4f87da82012-03-02 19:55:56 +0200794 /* Non-mgmt controlled devices get this bit set
795 * implicitly so that pairing works for them, however
796 * for mgmt we require user-space to explicitly enable
797 * it
798 */
799 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200800}
801
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200802static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300803 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200804{
805 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200806
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200807 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200808
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300809 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200810
Johan Hedberg03811012010-12-08 00:21:06 +0200811 memset(&rp, 0, sizeof(rp));
812
Johan Hedberg03811012010-12-08 00:21:06 +0200813 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200814
815 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200816 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200817
818 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
819 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
820
821 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200822
823 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200824 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200825
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300826 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200827
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200828 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300829 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200830}
831
832static void mgmt_pending_free(struct pending_cmd *cmd)
833{
834 sock_put(cmd->sk);
835 kfree(cmd->param);
836 kfree(cmd);
837}
838
839static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300840 struct hci_dev *hdev, void *data,
841 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200842{
843 struct pending_cmd *cmd;
844
Andre Guedes12b94562012-06-07 19:05:45 -0300845 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200846 if (!cmd)
847 return NULL;
848
849 cmd->opcode = opcode;
850 cmd->index = hdev->id;
851
Andre Guedes12b94562012-06-07 19:05:45 -0300852 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200853 if (!cmd->param) {
854 kfree(cmd);
855 return NULL;
856 }
857
858 if (data)
859 memcpy(cmd->param, data, len);
860
861 cmd->sk = sk;
862 sock_hold(sk);
863
864 list_add(&cmd->list, &hdev->mgmt_pending);
865
866 return cmd;
867}
868
869static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300870 void (*cb)(struct pending_cmd *cmd,
871 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300872 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200873{
Andre Guedesa3d09352013-02-01 11:21:30 -0300874 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200875
Andre Guedesa3d09352013-02-01 11:21:30 -0300876 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200877 if (opcode > 0 && cmd->opcode != opcode)
878 continue;
879
880 cb(cmd, data);
881 }
882}
883
884static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
885{
886 struct pending_cmd *cmd;
887
888 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
889 if (cmd->opcode == opcode)
890 return cmd;
891 }
892
893 return NULL;
894}
895
896static void mgmt_pending_remove(struct pending_cmd *cmd)
897{
898 list_del(&cmd->list);
899 mgmt_pending_free(cmd);
900}
901
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200902static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200903{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200904 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200905
Johan Hedbergaee9b212012-02-18 15:07:59 +0200906 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300907 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200908}
909
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200910static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300911 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200912{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300913 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200914 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200915 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200916
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200917 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200918
Johan Hedberga7e80f22013-01-09 16:05:19 +0200919 if (cp->val != 0x00 && cp->val != 0x01)
920 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
921 MGMT_STATUS_INVALID_PARAMS);
922
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300923 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200924
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300925 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
926 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
927 MGMT_STATUS_BUSY);
928 goto failed;
929 }
930
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100931 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
932 cancel_delayed_work(&hdev->power_off);
933
934 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200935 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
936 data, len);
937 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100938 goto failed;
939 }
940 }
941
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200942 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200943 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200944 goto failed;
945 }
946
Johan Hedberg03811012010-12-08 00:21:06 +0200947 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
948 if (!cmd) {
949 err = -ENOMEM;
950 goto failed;
951 }
952
953 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200954 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200955 else
Johan Hedberg19202572013-01-14 22:33:51 +0200956 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200957
958 err = 0;
959
960failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300961 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200962 return err;
963}
964
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300965static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
966 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200967{
968 struct sk_buff *skb;
969 struct mgmt_hdr *hdr;
970
Andre Guedes790eff42012-06-07 19:05:46 -0300971 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200972 if (!skb)
973 return -ENOMEM;
974
975 hdr = (void *) skb_put(skb, sizeof(*hdr));
976 hdr->opcode = cpu_to_le16(event);
977 if (hdev)
978 hdr->index = cpu_to_le16(hdev->id);
979 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530980 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200981 hdr->len = cpu_to_le16(data_len);
982
983 if (data)
984 memcpy(skb_put(skb, data_len), data, data_len);
985
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100986 /* Time stamp */
987 __net_timestamp(skb);
988
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200989 hci_send_to_control(skb, skip_sk);
990 kfree_skb(skb);
991
992 return 0;
993}
994
995static int new_settings(struct hci_dev *hdev, struct sock *skip)
996{
997 __le32 ev;
998
999 ev = cpu_to_le32(get_current_settings(hdev));
1000
1001 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1002}
1003
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001004struct cmd_lookup {
1005 struct sock *sk;
1006 struct hci_dev *hdev;
1007 u8 mgmt_status;
1008};
1009
1010static void settings_rsp(struct pending_cmd *cmd, void *data)
1011{
1012 struct cmd_lookup *match = data;
1013
1014 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1015
1016 list_del(&cmd->list);
1017
1018 if (match->sk == NULL) {
1019 match->sk = cmd->sk;
1020 sock_hold(match->sk);
1021 }
1022
1023 mgmt_pending_free(cmd);
1024}
1025
1026static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1027{
1028 u8 *status = data;
1029
1030 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1031 mgmt_pending_remove(cmd);
1032}
1033
Johan Hedberge6fe7982013-10-02 15:45:22 +03001034static u8 mgmt_bredr_support(struct hci_dev *hdev)
1035{
1036 if (!lmp_bredr_capable(hdev))
1037 return MGMT_STATUS_NOT_SUPPORTED;
1038 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1039 return MGMT_STATUS_REJECTED;
1040 else
1041 return MGMT_STATUS_SUCCESS;
1042}
1043
1044static u8 mgmt_le_support(struct hci_dev *hdev)
1045{
1046 if (!lmp_le_capable(hdev))
1047 return MGMT_STATUS_NOT_SUPPORTED;
1048 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1049 return MGMT_STATUS_REJECTED;
1050 else
1051 return MGMT_STATUS_SUCCESS;
1052}
1053
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001054static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1055{
1056 struct pending_cmd *cmd;
1057 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001058 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001059 bool changed;
1060
1061 BT_DBG("status 0x%02x", status);
1062
1063 hci_dev_lock(hdev);
1064
1065 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1066 if (!cmd)
1067 goto unlock;
1068
1069 if (status) {
1070 u8 mgmt_err = mgmt_status(status);
1071 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001072 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001073 goto remove_cmd;
1074 }
1075
1076 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001077 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001078 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1079 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001080
1081 if (hdev->discov_timeout > 0) {
1082 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1083 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1084 to);
1085 }
1086 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001087 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1088 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001089 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001090
1091 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1092
1093 if (changed)
1094 new_settings(hdev, cmd->sk);
1095
Marcel Holtmann970ba522013-10-15 06:33:57 -07001096 /* When the discoverable mode gets changed, make sure
1097 * that class of device has the limited discoverable
1098 * bit correctly set.
1099 */
1100 hci_req_init(&req, hdev);
1101 update_class(&req);
1102 hci_req_run(&req, NULL);
1103
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001104remove_cmd:
1105 mgmt_pending_remove(cmd);
1106
1107unlock:
1108 hci_dev_unlock(hdev);
1109}
1110
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001111static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001112 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001113{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001114 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001115 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001116 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001117 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001118 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001119 int err;
1120
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001121 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001122
Johan Hedberge6fe7982013-10-02 15:45:22 +03001123 status = mgmt_bredr_support(hdev);
1124 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001125 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001126 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001127
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001128 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001129 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1130 MGMT_STATUS_INVALID_PARAMS);
1131
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001132 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001133
1134 /* Disabling discoverable requires that no timeout is set,
1135 * and enabling limited discoverable requires a timeout.
1136 */
1137 if ((cp->val == 0x00 && timeout > 0) ||
1138 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001139 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001140 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001141
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001142 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001143
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001144 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001145 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001146 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001147 goto failed;
1148 }
1149
1150 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001151 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001152 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001153 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001154 goto failed;
1155 }
1156
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001157 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001158 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001159 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001160 goto failed;
1161 }
1162
1163 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001164 bool changed = false;
1165
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001166 /* Setting limited discoverable when powered off is
1167 * not a valid operation since it requires a timeout
1168 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1169 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001170 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1171 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1172 changed = true;
1173 }
1174
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001175 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001176 if (err < 0)
1177 goto failed;
1178
1179 if (changed)
1180 err = new_settings(hdev, sk);
1181
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001182 goto failed;
1183 }
1184
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001185 /* If the current mode is the same, then just update the timeout
1186 * value with the new value. And if only the timeout gets updated,
1187 * then no need for any HCI transactions.
1188 */
1189 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1190 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1191 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001192 cancel_delayed_work(&hdev->discov_off);
1193 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001194
Marcel Holtmann36261542013-10-15 08:28:51 -07001195 if (cp->val && hdev->discov_timeout > 0) {
1196 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001197 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001198 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001199 }
1200
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001201 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001202 goto failed;
1203 }
1204
1205 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1206 if (!cmd) {
1207 err = -ENOMEM;
1208 goto failed;
1209 }
1210
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001211 /* Cancel any potential discoverable timeout that might be
1212 * still active and store new timeout value. The arming of
1213 * the timeout happens in the complete handler.
1214 */
1215 cancel_delayed_work(&hdev->discov_off);
1216 hdev->discov_timeout = timeout;
1217
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001218 hci_req_init(&req, hdev);
1219
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001220 scan = SCAN_PAGE;
1221
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001222 if (cp->val) {
1223 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001224
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001225 if (cp->val == 0x02) {
1226 /* Limited discoverable mode */
1227 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1228
1229 hci_cp.num_iac = 2;
1230 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1231 hci_cp.iac_lap[1] = 0x8b;
1232 hci_cp.iac_lap[2] = 0x9e;
1233 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1234 hci_cp.iac_lap[4] = 0x8b;
1235 hci_cp.iac_lap[5] = 0x9e;
1236 } else {
1237 /* General discoverable mode */
1238 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1239
1240 hci_cp.num_iac = 1;
1241 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1242 hci_cp.iac_lap[1] = 0x8b;
1243 hci_cp.iac_lap[2] = 0x9e;
1244 }
1245
1246 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1247 (hci_cp.num_iac * 3) + 1, &hci_cp);
1248
1249 scan |= SCAN_INQUIRY;
1250 } else {
1251 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1252 }
1253
1254 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001255
1256 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001257 if (err < 0)
1258 mgmt_pending_remove(cmd);
1259
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001260failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001261 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001262 return err;
1263}
1264
Johan Hedberg406d7802013-03-15 17:07:09 -05001265static void write_fast_connectable(struct hci_request *req, bool enable)
1266{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001267 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001268 struct hci_cp_write_page_scan_activity acp;
1269 u8 type;
1270
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001271 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1272 return;
1273
Johan Hedberg406d7802013-03-15 17:07:09 -05001274 if (enable) {
1275 type = PAGE_SCAN_TYPE_INTERLACED;
1276
1277 /* 160 msec page scan interval */
1278 acp.interval = __constant_cpu_to_le16(0x0100);
1279 } else {
1280 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1281
1282 /* default 1.28 sec page scan */
1283 acp.interval = __constant_cpu_to_le16(0x0800);
1284 }
1285
1286 acp.window = __constant_cpu_to_le16(0x0012);
1287
Johan Hedbergbd98b992013-03-15 17:07:13 -05001288 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1289 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1290 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1291 sizeof(acp), &acp);
1292
1293 if (hdev->page_scan_type != type)
1294 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001295}
1296
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001297static u8 get_adv_type(struct hci_dev *hdev)
1298{
1299 struct pending_cmd *cmd;
1300 bool connectable;
1301
1302 /* If there's a pending mgmt command the flag will not yet have
1303 * it's final value, so check for this first.
1304 */
1305 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1306 if (cmd) {
1307 struct mgmt_mode *cp = cmd->param;
1308 connectable = !!cp->val;
1309 } else {
1310 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1311 }
1312
1313 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1314}
1315
Johan Hedberg95c66e72013-10-14 16:20:06 +03001316static void enable_advertising(struct hci_request *req)
1317{
1318 struct hci_dev *hdev = req->hdev;
1319 struct hci_cp_le_set_adv_param cp;
1320 u8 enable = 0x01;
1321
1322 memset(&cp, 0, sizeof(cp));
1323 cp.min_interval = __constant_cpu_to_le16(0x0800);
1324 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001325 cp.type = get_adv_type(hdev);
Johan Hedberg95c66e72013-10-14 16:20:06 +03001326 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1327 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1328 else
1329 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1330 cp.channel_map = 0x07;
1331
1332 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1333
1334 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1335}
1336
1337static void disable_advertising(struct hci_request *req)
1338{
1339 u8 enable = 0x00;
1340
1341 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1342}
1343
Johan Hedberg2b76f452013-03-15 17:07:04 -05001344static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1345{
1346 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001347 struct mgmt_mode *cp;
1348 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001349
1350 BT_DBG("status 0x%02x", status);
1351
1352 hci_dev_lock(hdev);
1353
1354 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1355 if (!cmd)
1356 goto unlock;
1357
Johan Hedberg37438c12013-10-14 16:20:05 +03001358 if (status) {
1359 u8 mgmt_err = mgmt_status(status);
1360 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1361 goto remove_cmd;
1362 }
1363
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001364 cp = cmd->param;
1365 if (cp->val)
1366 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1367 else
1368 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1369
Johan Hedberg2b76f452013-03-15 17:07:04 -05001370 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1371
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001372 if (changed)
1373 new_settings(hdev, cmd->sk);
1374
Johan Hedberg37438c12013-10-14 16:20:05 +03001375remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001376 mgmt_pending_remove(cmd);
1377
1378unlock:
1379 hci_dev_unlock(hdev);
1380}
1381
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001382static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001383 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001384{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001385 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001386 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001387 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001388 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001389 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001391 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001392
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001393 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1394 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001395 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001396 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001397
Johan Hedberga7e80f22013-01-09 16:05:19 +02001398 if (cp->val != 0x00 && cp->val != 0x01)
1399 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1400 MGMT_STATUS_INVALID_PARAMS);
1401
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001402 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001403
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001404 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001405 bool changed = false;
1406
1407 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1408 changed = true;
1409
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001410 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001411 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001412 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001413 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1414 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1415 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001416
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001417 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001418 if (err < 0)
1419 goto failed;
1420
1421 if (changed)
1422 err = new_settings(hdev, sk);
1423
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001424 goto failed;
1425 }
1426
1427 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001428 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001429 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001430 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001431 goto failed;
1432 }
1433
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001434 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1435 if (!cmd) {
1436 err = -ENOMEM;
1437 goto failed;
1438 }
1439
Johan Hedberg2b76f452013-03-15 17:07:04 -05001440 hci_req_init(&req, hdev);
1441
Johan Hedberg9b742462013-10-14 16:20:03 +03001442 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1443 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001444 if (cp->val) {
1445 scan = SCAN_PAGE;
1446 } else {
1447 scan = 0;
1448
1449 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001450 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001451 cancel_delayed_work(&hdev->discov_off);
1452 }
1453
1454 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1455 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001456
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001457 /* If we're going from non-connectable to connectable or
1458 * vice-versa when fast connectable is enabled ensure that fast
1459 * connectable gets disabled. write_fast_connectable won't do
1460 * anything if the page scan parameters are already what they
1461 * should be.
1462 */
1463 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001464 write_fast_connectable(&req, false);
1465
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001466 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1467 hci_conn_num(hdev, LE_LINK) == 0) {
1468 disable_advertising(&req);
1469 enable_advertising(&req);
1470 }
1471
Johan Hedberg2b76f452013-03-15 17:07:04 -05001472 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001473 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001474 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001475 if (err == -ENODATA)
1476 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1477 hdev);
1478 goto failed;
1479 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001480
1481failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001482 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001483 return err;
1484}
1485
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001486static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001487 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001488{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001489 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001490 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001491 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001492
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001493 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001494
Johan Hedberga7e80f22013-01-09 16:05:19 +02001495 if (cp->val != 0x00 && cp->val != 0x01)
1496 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1497 MGMT_STATUS_INVALID_PARAMS);
1498
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001499 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001500
1501 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001502 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001503 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001504 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001505
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001506 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001507 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001508 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001509
Marcel Holtmann55594352013-10-06 16:11:57 -07001510 if (changed)
1511 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001512
Marcel Holtmann55594352013-10-06 16:11:57 -07001513unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001514 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001515 return err;
1516}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001517
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001518static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1519 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001520{
1521 struct mgmt_mode *cp = data;
1522 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001523 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001524 int err;
1525
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001526 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001527
Johan Hedberge6fe7982013-10-02 15:45:22 +03001528 status = mgmt_bredr_support(hdev);
1529 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001530 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001531 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001532
Johan Hedberga7e80f22013-01-09 16:05:19 +02001533 if (cp->val != 0x00 && cp->val != 0x01)
1534 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1535 MGMT_STATUS_INVALID_PARAMS);
1536
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001537 hci_dev_lock(hdev);
1538
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001539 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001540 bool changed = false;
1541
1542 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001543 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001544 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1545 changed = true;
1546 }
1547
1548 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1549 if (err < 0)
1550 goto failed;
1551
1552 if (changed)
1553 err = new_settings(hdev, sk);
1554
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001555 goto failed;
1556 }
1557
1558 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001559 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001560 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001561 goto failed;
1562 }
1563
1564 val = !!cp->val;
1565
1566 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1567 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1568 goto failed;
1569 }
1570
1571 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1572 if (!cmd) {
1573 err = -ENOMEM;
1574 goto failed;
1575 }
1576
1577 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1578 if (err < 0) {
1579 mgmt_pending_remove(cmd);
1580 goto failed;
1581 }
1582
1583failed:
1584 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001585 return err;
1586}
1587
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001588static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001589{
1590 struct mgmt_mode *cp = data;
1591 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001592 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001593 int err;
1594
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001595 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001596
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001597 status = mgmt_bredr_support(hdev);
1598 if (status)
1599 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1600
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001601 if (!lmp_ssp_capable(hdev))
1602 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1603 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001604
Johan Hedberga7e80f22013-01-09 16:05:19 +02001605 if (cp->val != 0x00 && cp->val != 0x01)
1606 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1607 MGMT_STATUS_INVALID_PARAMS);
1608
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001609 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001610
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001611 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001612 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001613
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001614 if (cp->val) {
1615 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1616 &hdev->dev_flags);
1617 } else {
1618 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1619 &hdev->dev_flags);
1620 if (!changed)
1621 changed = test_and_clear_bit(HCI_HS_ENABLED,
1622 &hdev->dev_flags);
1623 else
1624 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001625 }
1626
1627 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1628 if (err < 0)
1629 goto failed;
1630
1631 if (changed)
1632 err = new_settings(hdev, sk);
1633
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001634 goto failed;
1635 }
1636
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001637 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1638 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001639 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1640 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001641 goto failed;
1642 }
1643
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001644 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001645 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1646 goto failed;
1647 }
1648
1649 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1650 if (!cmd) {
1651 err = -ENOMEM;
1652 goto failed;
1653 }
1654
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001655 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001656 if (err < 0) {
1657 mgmt_pending_remove(cmd);
1658 goto failed;
1659 }
1660
1661failed:
1662 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001663 return err;
1664}
1665
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001666static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001667{
1668 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001669 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001670 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001671 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001672
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001673 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001674
Johan Hedberge6fe7982013-10-02 15:45:22 +03001675 status = mgmt_bredr_support(hdev);
1676 if (status)
1677 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001678
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001679 if (!lmp_ssp_capable(hdev))
1680 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1681 MGMT_STATUS_NOT_SUPPORTED);
1682
1683 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1684 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1685 MGMT_STATUS_REJECTED);
1686
Johan Hedberga7e80f22013-01-09 16:05:19 +02001687 if (cp->val != 0x00 && cp->val != 0x01)
1688 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1689 MGMT_STATUS_INVALID_PARAMS);
1690
Marcel Holtmannee392692013-10-01 22:59:23 -07001691 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001692
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001693 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001694 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001695 } else {
1696 if (hdev_is_powered(hdev)) {
1697 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1698 MGMT_STATUS_REJECTED);
1699 goto unlock;
1700 }
1701
Marcel Holtmannee392692013-10-01 22:59:23 -07001702 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001703 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001704
1705 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1706 if (err < 0)
1707 goto unlock;
1708
1709 if (changed)
1710 err = new_settings(hdev, sk);
1711
1712unlock:
1713 hci_dev_unlock(hdev);
1714 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001715}
1716
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001717static void le_enable_complete(struct hci_dev *hdev, u8 status)
1718{
1719 struct cmd_lookup match = { NULL, hdev };
1720
1721 if (status) {
1722 u8 mgmt_err = mgmt_status(status);
1723
1724 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1725 &mgmt_err);
1726 return;
1727 }
1728
1729 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1730
1731 new_settings(hdev, match.sk);
1732
1733 if (match.sk)
1734 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001735
1736 /* Make sure the controller has a good default for
1737 * advertising data. Restrict the update to when LE
1738 * has actually been enabled. During power on, the
1739 * update in powered_update_hci will take care of it.
1740 */
1741 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1742 struct hci_request req;
1743
1744 hci_dev_lock(hdev);
1745
1746 hci_req_init(&req, hdev);
1747 update_ad(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001748 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001749 hci_req_run(&req, NULL);
1750
1751 hci_dev_unlock(hdev);
1752 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001753}
1754
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001755static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001756{
1757 struct mgmt_mode *cp = data;
1758 struct hci_cp_write_le_host_supported hci_cp;
1759 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001760 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001761 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001762 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001763
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001764 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001765
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001766 if (!lmp_le_capable(hdev))
1767 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1768 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001769
Johan Hedberga7e80f22013-01-09 16:05:19 +02001770 if (cp->val != 0x00 && cp->val != 0x01)
1771 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1772 MGMT_STATUS_INVALID_PARAMS);
1773
Johan Hedbergc73eee92013-04-19 18:35:21 +03001774 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001775 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001776 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1777 MGMT_STATUS_REJECTED);
1778
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001779 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001780
1781 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001782 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001783
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001784 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001785 bool changed = false;
1786
1787 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1788 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1789 changed = true;
1790 }
1791
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001792 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1793 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001794 changed = true;
1795 }
1796
Johan Hedberg06199cf2012-02-22 16:37:11 +02001797 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1798 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001799 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001800
1801 if (changed)
1802 err = new_settings(hdev, sk);
1803
Johan Hedberg1de028c2012-02-29 19:55:35 -08001804 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001805 }
1806
Johan Hedberg4375f102013-09-25 13:26:10 +03001807 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1808 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001809 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001810 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001811 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001812 }
1813
1814 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1815 if (!cmd) {
1816 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001817 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001818 }
1819
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001820 hci_req_init(&req, hdev);
1821
Johan Hedberg06199cf2012-02-22 16:37:11 +02001822 memset(&hci_cp, 0, sizeof(hci_cp));
1823
1824 if (val) {
1825 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001826 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001827 } else {
1828 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1829 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001830 }
1831
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001832 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1833 &hci_cp);
1834
1835 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301836 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001837 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001838
Johan Hedberg1de028c2012-02-29 19:55:35 -08001839unlock:
1840 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001841 return err;
1842}
1843
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001844/* This is a helper function to test for pending mgmt commands that can
1845 * cause CoD or EIR HCI commands. We can only allow one such pending
1846 * mgmt command at a time since otherwise we cannot easily track what
1847 * the current values are, will be, and based on that calculate if a new
1848 * HCI command needs to be sent and if yes with what value.
1849 */
1850static bool pending_eir_or_class(struct hci_dev *hdev)
1851{
1852 struct pending_cmd *cmd;
1853
1854 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1855 switch (cmd->opcode) {
1856 case MGMT_OP_ADD_UUID:
1857 case MGMT_OP_REMOVE_UUID:
1858 case MGMT_OP_SET_DEV_CLASS:
1859 case MGMT_OP_SET_POWERED:
1860 return true;
1861 }
1862 }
1863
1864 return false;
1865}
1866
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001867static const u8 bluetooth_base_uuid[] = {
1868 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1869 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1870};
1871
1872static u8 get_uuid_size(const u8 *uuid)
1873{
1874 u32 val;
1875
1876 if (memcmp(uuid, bluetooth_base_uuid, 12))
1877 return 128;
1878
1879 val = get_unaligned_le32(&uuid[12]);
1880 if (val > 0xffff)
1881 return 32;
1882
1883 return 16;
1884}
1885
Johan Hedberg92da6092013-03-15 17:06:55 -05001886static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1887{
1888 struct pending_cmd *cmd;
1889
1890 hci_dev_lock(hdev);
1891
1892 cmd = mgmt_pending_find(mgmt_op, hdev);
1893 if (!cmd)
1894 goto unlock;
1895
1896 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1897 hdev->dev_class, 3);
1898
1899 mgmt_pending_remove(cmd);
1900
1901unlock:
1902 hci_dev_unlock(hdev);
1903}
1904
1905static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1906{
1907 BT_DBG("status 0x%02x", status);
1908
1909 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1910}
1911
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001912static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001913{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001914 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001915 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001916 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001917 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001918 int err;
1919
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001920 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001921
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001922 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001923
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001924 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001925 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001926 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001927 goto failed;
1928 }
1929
Andre Guedes92c4c202012-06-07 19:05:44 -03001930 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001931 if (!uuid) {
1932 err = -ENOMEM;
1933 goto failed;
1934 }
1935
1936 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001937 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001938 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001939
Johan Hedbergde66aa62013-01-27 00:31:27 +02001940 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001941
Johan Hedberg890ea892013-03-15 17:06:52 -05001942 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001943
Johan Hedberg890ea892013-03-15 17:06:52 -05001944 update_class(&req);
1945 update_eir(&req);
1946
Johan Hedberg92da6092013-03-15 17:06:55 -05001947 err = hci_req_run(&req, add_uuid_complete);
1948 if (err < 0) {
1949 if (err != -ENODATA)
1950 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001951
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001952 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001953 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001954 goto failed;
1955 }
1956
1957 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001958 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001959 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001960 goto failed;
1961 }
1962
1963 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001964
1965failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001966 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001967 return err;
1968}
1969
Johan Hedberg24b78d02012-02-23 23:24:30 +02001970static bool enable_service_cache(struct hci_dev *hdev)
1971{
1972 if (!hdev_is_powered(hdev))
1973 return false;
1974
1975 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001976 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1977 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001978 return true;
1979 }
1980
1981 return false;
1982}
1983
Johan Hedberg92da6092013-03-15 17:06:55 -05001984static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1985{
1986 BT_DBG("status 0x%02x", status);
1987
1988 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1989}
1990
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001991static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001992 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001993{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001994 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001995 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001996 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001997 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 -05001998 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001999 int err, found;
2000
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002001 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002002
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002003 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002004
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002005 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002006 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002007 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002008 goto unlock;
2009 }
2010
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002011 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
2012 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002013
Johan Hedberg24b78d02012-02-23 23:24:30 +02002014 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002015 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002016 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002017 goto unlock;
2018 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002019
Johan Hedberg9246a862012-02-23 21:33:16 +02002020 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002021 }
2022
2023 found = 0;
2024
Johan Hedberg056341c2013-01-27 00:31:30 +02002025 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002026 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2027 continue;
2028
2029 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002030 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002031 found++;
2032 }
2033
2034 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002035 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002036 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002037 goto unlock;
2038 }
2039
Johan Hedberg9246a862012-02-23 21:33:16 +02002040update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002041 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002042
Johan Hedberg890ea892013-03-15 17:06:52 -05002043 update_class(&req);
2044 update_eir(&req);
2045
Johan Hedberg92da6092013-03-15 17:06:55 -05002046 err = hci_req_run(&req, remove_uuid_complete);
2047 if (err < 0) {
2048 if (err != -ENODATA)
2049 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002050
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002051 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002052 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002053 goto unlock;
2054 }
2055
2056 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002057 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002058 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002059 goto unlock;
2060 }
2061
2062 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002063
2064unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002065 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002066 return err;
2067}
2068
Johan Hedberg92da6092013-03-15 17:06:55 -05002069static void set_class_complete(struct hci_dev *hdev, u8 status)
2070{
2071 BT_DBG("status 0x%02x", status);
2072
2073 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2074}
2075
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002076static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002077 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002078{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002079 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002080 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002081 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002082 int err;
2083
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002084 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002085
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002086 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002087 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2088 MGMT_STATUS_NOT_SUPPORTED);
2089
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002090 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002091
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002092 if (pending_eir_or_class(hdev)) {
2093 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2094 MGMT_STATUS_BUSY);
2095 goto unlock;
2096 }
2097
2098 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2099 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2100 MGMT_STATUS_INVALID_PARAMS);
2101 goto unlock;
2102 }
2103
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002104 hdev->major_class = cp->major;
2105 hdev->minor_class = cp->minor;
2106
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002107 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002108 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002109 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002110 goto unlock;
2111 }
2112
Johan Hedberg890ea892013-03-15 17:06:52 -05002113 hci_req_init(&req, hdev);
2114
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002115 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002116 hci_dev_unlock(hdev);
2117 cancel_delayed_work_sync(&hdev->service_cache);
2118 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002119 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002120 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002121
Johan Hedberg890ea892013-03-15 17:06:52 -05002122 update_class(&req);
2123
Johan Hedberg92da6092013-03-15 17:06:55 -05002124 err = hci_req_run(&req, set_class_complete);
2125 if (err < 0) {
2126 if (err != -ENODATA)
2127 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002128
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002129 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002130 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002131 goto unlock;
2132 }
2133
2134 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002135 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002136 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002137 goto unlock;
2138 }
2139
2140 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002141
Johan Hedbergb5235a62012-02-21 14:32:24 +02002142unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002143 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002144 return err;
2145}
2146
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002147static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002148 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002149{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002150 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002151 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002152 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002153
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002154 BT_DBG("request for %s", hdev->name);
2155
2156 if (!lmp_bredr_capable(hdev))
2157 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2158 MGMT_STATUS_NOT_SUPPORTED);
2159
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002160 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002161
Johan Hedberg86742e12011-11-07 23:13:38 +02002162 expected_len = sizeof(*cp) + key_count *
2163 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002164 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002165 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002166 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002167 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002168 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002169 }
2170
Johan Hedberg4ae14302013-01-20 14:27:13 +02002171 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2172 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2173 MGMT_STATUS_INVALID_PARAMS);
2174
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002175 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002176 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002177
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002178 for (i = 0; i < key_count; i++) {
2179 struct mgmt_link_key_info *key = &cp->keys[i];
2180
2181 if (key->addr.type != BDADDR_BREDR)
2182 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2183 MGMT_STATUS_INVALID_PARAMS);
2184 }
2185
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002186 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002187
2188 hci_link_keys_clear(hdev);
2189
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002190 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002191 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002192 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002193 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002194
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002195 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002196 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002197
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002198 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002199 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002200 }
2201
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002202 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002203
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002204 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002205
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002206 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002207}
2208
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002209static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002210 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002211{
2212 struct mgmt_ev_device_unpaired ev;
2213
2214 bacpy(&ev.addr.bdaddr, bdaddr);
2215 ev.addr.type = addr_type;
2216
2217 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002218 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002219}
2220
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002221static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002222 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002223{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002224 struct mgmt_cp_unpair_device *cp = data;
2225 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002226 struct hci_cp_disconnect dc;
2227 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002228 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002229 int err;
2230
Johan Hedberga8a1d192011-11-10 15:54:38 +02002231 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002232 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2233 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002234
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002235 if (!bdaddr_type_is_valid(cp->addr.type))
2236 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2237 MGMT_STATUS_INVALID_PARAMS,
2238 &rp, sizeof(rp));
2239
Johan Hedberg118da702013-01-20 14:27:20 +02002240 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2241 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2242 MGMT_STATUS_INVALID_PARAMS,
2243 &rp, sizeof(rp));
2244
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002245 hci_dev_lock(hdev);
2246
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002247 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002248 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002249 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002250 goto unlock;
2251 }
2252
Andre Guedes591f47f2012-04-24 21:02:49 -03002253 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002254 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2255 else
2256 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002257
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002258 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002259 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002260 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002261 goto unlock;
2262 }
2263
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002264 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002265 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002266 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002267 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002268 else
2269 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002270 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002271 } else {
2272 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002273 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002274
Johan Hedberga8a1d192011-11-10 15:54:38 +02002275 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002276 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002277 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002278 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002279 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002280 }
2281
Johan Hedberg124f6e32012-02-09 13:50:12 +02002282 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002283 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002284 if (!cmd) {
2285 err = -ENOMEM;
2286 goto unlock;
2287 }
2288
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002289 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002290 dc.reason = 0x13; /* Remote User Terminated Connection */
2291 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2292 if (err < 0)
2293 mgmt_pending_remove(cmd);
2294
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002295unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002296 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002297 return err;
2298}
2299
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002300static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002301 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002302{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002303 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002304 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002305 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002306 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002307 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002308 int err;
2309
2310 BT_DBG("");
2311
Johan Hedberg06a63b12013-01-20 14:27:21 +02002312 memset(&rp, 0, sizeof(rp));
2313 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2314 rp.addr.type = cp->addr.type;
2315
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002316 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002317 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2318 MGMT_STATUS_INVALID_PARAMS,
2319 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002320
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002321 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002322
2323 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002324 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2325 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002326 goto failed;
2327 }
2328
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002329 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002330 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2331 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002332 goto failed;
2333 }
2334
Andre Guedes591f47f2012-04-24 21:02:49 -03002335 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002336 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2337 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002338 else
2339 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002340
Vishal Agarwalf9607272012-06-13 05:32:43 +05302341 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002342 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2343 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002344 goto failed;
2345 }
2346
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002347 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002348 if (!cmd) {
2349 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002350 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002351 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002352
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002353 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002354 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002355
2356 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2357 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002358 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002359
2360failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002361 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002362 return err;
2363}
2364
Andre Guedes57c14772012-04-24 21:02:50 -03002365static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002366{
2367 switch (link_type) {
2368 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002369 switch (addr_type) {
2370 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002371 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002372
Johan Hedberg48264f02011-11-09 13:58:58 +02002373 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002374 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002375 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002376 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002377
Johan Hedberg4c659c32011-11-07 23:13:39 +02002378 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002379 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002380 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002381 }
2382}
2383
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002384static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2385 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002386{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002387 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002388 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002389 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002390 int err;
2391 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002392
2393 BT_DBG("");
2394
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002395 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002396
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002397 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002398 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002399 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002400 goto unlock;
2401 }
2402
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002403 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002404 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2405 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002406 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002407 }
2408
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002409 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002410 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002411 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002412 err = -ENOMEM;
2413 goto unlock;
2414 }
2415
Johan Hedberg2784eb42011-01-21 13:56:35 +02002416 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002417 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002418 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2419 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002420 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002421 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002422 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002423 continue;
2424 i++;
2425 }
2426
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002427 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002428
Johan Hedberg4c659c32011-11-07 23:13:39 +02002429 /* Recalculate length in case of filtered SCO connections, etc */
2430 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002431
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002432 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002433 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002434
Johan Hedberga38528f2011-01-22 06:46:43 +02002435 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002436
2437unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002438 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002439 return err;
2440}
2441
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002442static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002443 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002444{
2445 struct pending_cmd *cmd;
2446 int err;
2447
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002448 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002449 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002450 if (!cmd)
2451 return -ENOMEM;
2452
Johan Hedbergd8457692012-02-17 14:24:57 +02002453 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002454 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002455 if (err < 0)
2456 mgmt_pending_remove(cmd);
2457
2458 return err;
2459}
2460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002461static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002462 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002463{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002464 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002465 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002466 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002467 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002468 int err;
2469
2470 BT_DBG("");
2471
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002472 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002473
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002474 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002475 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002476 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002477 goto failed;
2478 }
2479
Johan Hedbergd8457692012-02-17 14:24:57 +02002480 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002481 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002482 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002483 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002484 goto failed;
2485 }
2486
2487 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002488 struct mgmt_cp_pin_code_neg_reply ncp;
2489
2490 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002491
2492 BT_ERR("PIN code is not 16 bytes long");
2493
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002494 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002495 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002496 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002497 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002498
2499 goto failed;
2500 }
2501
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002502 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002503 if (!cmd) {
2504 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002505 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002506 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002507
Johan Hedbergd8457692012-02-17 14:24:57 +02002508 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002509 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002510 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002511
2512 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2513 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002514 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002515
2516failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002517 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002518 return err;
2519}
2520
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002521static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2522 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002523{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002524 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002525
2526 BT_DBG("");
2527
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002528 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002529
2530 hdev->io_capability = cp->io_capability;
2531
2532 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002533 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002534
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002535 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002536
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002537 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2538 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002539}
2540
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002541static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002542{
2543 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002544 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002545
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002546 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002547 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2548 continue;
2549
Johan Hedberge9a416b2011-02-19 12:05:56 -03002550 if (cmd->user_data != conn)
2551 continue;
2552
2553 return cmd;
2554 }
2555
2556 return NULL;
2557}
2558
2559static void pairing_complete(struct pending_cmd *cmd, u8 status)
2560{
2561 struct mgmt_rp_pair_device rp;
2562 struct hci_conn *conn = cmd->user_data;
2563
Johan Hedbergba4e5642011-11-11 00:07:34 +02002564 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002565 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002566
Johan Hedbergaee9b212012-02-18 15:07:59 +02002567 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002568 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002569
2570 /* So we don't get further callbacks for this connection */
2571 conn->connect_cfm_cb = NULL;
2572 conn->security_cfm_cb = NULL;
2573 conn->disconn_cfm_cb = NULL;
2574
David Herrmann76a68ba2013-04-06 20:28:37 +02002575 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002576
Johan Hedberga664b5b2011-02-19 12:06:02 -03002577 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002578}
2579
2580static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2581{
2582 struct pending_cmd *cmd;
2583
2584 BT_DBG("status %u", status);
2585
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002586 cmd = find_pairing(conn);
2587 if (!cmd)
2588 BT_DBG("Unable to find a pending command");
2589 else
Johan Hedberge2113262012-02-18 15:20:03 +02002590 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002591}
2592
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302593static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2594{
2595 struct pending_cmd *cmd;
2596
2597 BT_DBG("status %u", status);
2598
2599 if (!status)
2600 return;
2601
2602 cmd = find_pairing(conn);
2603 if (!cmd)
2604 BT_DBG("Unable to find a pending command");
2605 else
2606 pairing_complete(cmd, mgmt_status(status));
2607}
2608
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002609static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002610 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002611{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002612 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002613 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002614 struct pending_cmd *cmd;
2615 u8 sec_level, auth_type;
2616 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002617 int err;
2618
2619 BT_DBG("");
2620
Szymon Jancf950a30e2013-01-18 12:48:07 +01002621 memset(&rp, 0, sizeof(rp));
2622 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2623 rp.addr.type = cp->addr.type;
2624
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002625 if (!bdaddr_type_is_valid(cp->addr.type))
2626 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2627 MGMT_STATUS_INVALID_PARAMS,
2628 &rp, sizeof(rp));
2629
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002630 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002631
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002632 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002633 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2634 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002635 goto unlock;
2636 }
2637
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002638 sec_level = BT_SECURITY_MEDIUM;
2639 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002640 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002641 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002642 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002643
Andre Guedes591f47f2012-04-24 21:02:49 -03002644 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002645 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2646 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002647 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002648 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2649 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002650
Ville Tervo30e76272011-02-22 16:10:53 -03002651 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002652 int status;
2653
2654 if (PTR_ERR(conn) == -EBUSY)
2655 status = MGMT_STATUS_BUSY;
2656 else
2657 status = MGMT_STATUS_CONNECT_FAILED;
2658
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002659 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002660 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002661 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002662 goto unlock;
2663 }
2664
2665 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002666 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002667 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002668 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002669 goto unlock;
2670 }
2671
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002672 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002673 if (!cmd) {
2674 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002675 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002676 goto unlock;
2677 }
2678
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002679 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002680 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002681 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302682 else
2683 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002684
Johan Hedberge9a416b2011-02-19 12:05:56 -03002685 conn->security_cfm_cb = pairing_complete_cb;
2686 conn->disconn_cfm_cb = pairing_complete_cb;
2687 conn->io_capability = cp->io_cap;
2688 cmd->user_data = conn;
2689
2690 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002691 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002692 pairing_complete(cmd, 0);
2693
2694 err = 0;
2695
2696unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002697 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002698 return err;
2699}
2700
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002701static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2702 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002703{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002704 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002705 struct pending_cmd *cmd;
2706 struct hci_conn *conn;
2707 int err;
2708
2709 BT_DBG("");
2710
Johan Hedberg28424702012-02-02 04:02:29 +02002711 hci_dev_lock(hdev);
2712
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002713 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002714 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002715 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002716 goto unlock;
2717 }
2718
Johan Hedberg28424702012-02-02 04:02:29 +02002719 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2720 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002721 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002722 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002723 goto unlock;
2724 }
2725
2726 conn = cmd->user_data;
2727
2728 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002729 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002730 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002731 goto unlock;
2732 }
2733
2734 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2735
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002736 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002737 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002738unlock:
2739 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002740 return err;
2741}
2742
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002743static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002744 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002745 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002746{
Johan Hedberga5c29682011-02-19 12:05:57 -03002747 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002748 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002749 int err;
2750
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002751 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002752
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002753 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002754 err = cmd_complete(sk, hdev->id, mgmt_op,
2755 MGMT_STATUS_NOT_POWERED, addr,
2756 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002757 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002758 }
2759
Johan Hedberg1707c602013-03-15 17:07:15 -05002760 if (addr->type == BDADDR_BREDR)
2761 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002762 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002763 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002764
Johan Hedberg272d90d2012-02-09 15:26:12 +02002765 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002766 err = cmd_complete(sk, hdev->id, mgmt_op,
2767 MGMT_STATUS_NOT_CONNECTED, addr,
2768 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002769 goto done;
2770 }
2771
Johan Hedberg1707c602013-03-15 17:07:15 -05002772 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002773 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002774 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002775
Brian Gix5fe57d92011-12-21 16:12:13 -08002776 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002777 err = cmd_complete(sk, hdev->id, mgmt_op,
2778 MGMT_STATUS_SUCCESS, addr,
2779 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002780 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002781 err = cmd_complete(sk, hdev->id, mgmt_op,
2782 MGMT_STATUS_FAILED, addr,
2783 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002784
Brian Gix47c15e22011-11-16 13:53:14 -08002785 goto done;
2786 }
2787
Johan Hedberg1707c602013-03-15 17:07:15 -05002788 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002789 if (!cmd) {
2790 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002791 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002792 }
2793
Brian Gix0df4c182011-11-16 13:53:13 -08002794 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002795 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2796 struct hci_cp_user_passkey_reply cp;
2797
Johan Hedberg1707c602013-03-15 17:07:15 -05002798 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002799 cp.passkey = passkey;
2800 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2801 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002802 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2803 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002804
Johan Hedberga664b5b2011-02-19 12:06:02 -03002805 if (err < 0)
2806 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002807
Brian Gix0df4c182011-11-16 13:53:13 -08002808done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002809 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002810 return err;
2811}
2812
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302813static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2814 void *data, u16 len)
2815{
2816 struct mgmt_cp_pin_code_neg_reply *cp = data;
2817
2818 BT_DBG("");
2819
Johan Hedberg1707c602013-03-15 17:07:15 -05002820 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302821 MGMT_OP_PIN_CODE_NEG_REPLY,
2822 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2823}
2824
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002825static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2826 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002827{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002828 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002829
2830 BT_DBG("");
2831
2832 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002833 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002834 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002835
Johan Hedberg1707c602013-03-15 17:07:15 -05002836 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002837 MGMT_OP_USER_CONFIRM_REPLY,
2838 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002839}
2840
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002841static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002842 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002843{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002844 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002845
2846 BT_DBG("");
2847
Johan Hedberg1707c602013-03-15 17:07:15 -05002848 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002849 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2850 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002851}
2852
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002853static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2854 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002855{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002856 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002857
2858 BT_DBG("");
2859
Johan Hedberg1707c602013-03-15 17:07:15 -05002860 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002861 MGMT_OP_USER_PASSKEY_REPLY,
2862 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002863}
2864
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002865static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002866 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002867{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002868 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002869
2870 BT_DBG("");
2871
Johan Hedberg1707c602013-03-15 17:07:15 -05002872 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002873 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2874 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002875}
2876
Johan Hedberg13928972013-03-15 17:07:00 -05002877static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002878{
Johan Hedberg13928972013-03-15 17:07:00 -05002879 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002880 struct hci_cp_write_local_name cp;
2881
Johan Hedberg13928972013-03-15 17:07:00 -05002882 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002883
Johan Hedberg890ea892013-03-15 17:06:52 -05002884 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002885}
2886
Johan Hedberg13928972013-03-15 17:07:00 -05002887static void set_name_complete(struct hci_dev *hdev, u8 status)
2888{
2889 struct mgmt_cp_set_local_name *cp;
2890 struct pending_cmd *cmd;
2891
2892 BT_DBG("status 0x%02x", status);
2893
2894 hci_dev_lock(hdev);
2895
2896 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2897 if (!cmd)
2898 goto unlock;
2899
2900 cp = cmd->param;
2901
2902 if (status)
2903 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2904 mgmt_status(status));
2905 else
2906 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2907 cp, sizeof(*cp));
2908
2909 mgmt_pending_remove(cmd);
2910
2911unlock:
2912 hci_dev_unlock(hdev);
2913}
2914
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002915static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002916 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002917{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002918 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002919 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002920 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002921 int err;
2922
2923 BT_DBG("");
2924
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002925 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002926
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002927 /* If the old values are the same as the new ones just return a
2928 * direct command complete event.
2929 */
2930 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2931 !memcmp(hdev->short_name, cp->short_name,
2932 sizeof(hdev->short_name))) {
2933 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2934 data, len);
2935 goto failed;
2936 }
2937
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002938 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002939
Johan Hedbergb5235a62012-02-21 14:32:24 +02002940 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002941 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002942
2943 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002944 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002945 if (err < 0)
2946 goto failed;
2947
2948 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002949 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002950
Johan Hedbergb5235a62012-02-21 14:32:24 +02002951 goto failed;
2952 }
2953
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002954 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002955 if (!cmd) {
2956 err = -ENOMEM;
2957 goto failed;
2958 }
2959
Johan Hedberg13928972013-03-15 17:07:00 -05002960 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2961
Johan Hedberg890ea892013-03-15 17:06:52 -05002962 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002963
2964 if (lmp_bredr_capable(hdev)) {
2965 update_name(&req);
2966 update_eir(&req);
2967 }
2968
2969 if (lmp_le_capable(hdev))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002970 update_ad(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05002971
Johan Hedberg13928972013-03-15 17:07:00 -05002972 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002973 if (err < 0)
2974 mgmt_pending_remove(cmd);
2975
2976failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002977 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002978 return err;
2979}
2980
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002981static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002982 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002983{
Szymon Jancc35938b2011-03-22 13:12:21 +01002984 struct pending_cmd *cmd;
2985 int err;
2986
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002987 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002988
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002989 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002990
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002991 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002992 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002993 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002994 goto unlock;
2995 }
2996
Andre Guedes9a1a1992012-07-24 15:03:48 -03002997 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002998 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002999 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003000 goto unlock;
3001 }
3002
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003003 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003004 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003005 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003006 goto unlock;
3007 }
3008
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003009 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003010 if (!cmd) {
3011 err = -ENOMEM;
3012 goto unlock;
3013 }
3014
3015 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3016 if (err < 0)
3017 mgmt_pending_remove(cmd);
3018
3019unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003020 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003021 return err;
3022}
3023
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003024static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003025 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003026{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003027 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003028 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003029 int err;
3030
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003031 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003032
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003033 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003034
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003035 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01003037 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003038 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01003039 else
Szymon Janca6785be2012-12-13 15:11:21 +01003040 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003041
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003042 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003043 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003044
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003045 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003046 return err;
3047}
3048
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003049static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003050 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003051{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003052 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003053 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003054 int err;
3055
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003056 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003057
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003058 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003059
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003060 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003061 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003062 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003063 else
Szymon Janca6785be2012-12-13 15:11:21 +01003064 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003065
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003066 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003067 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003068
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003069 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003070 return err;
3071}
3072
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003073static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3074{
3075 struct pending_cmd *cmd;
3076 u8 type;
3077 int err;
3078
3079 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3080
3081 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3082 if (!cmd)
3083 return -ENOENT;
3084
3085 type = hdev->discovery.type;
3086
3087 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3088 &type, sizeof(type));
3089 mgmt_pending_remove(cmd);
3090
3091 return err;
3092}
3093
Andre Guedes7c307722013-04-30 15:29:28 -03003094static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3095{
3096 BT_DBG("status %d", status);
3097
3098 if (status) {
3099 hci_dev_lock(hdev);
3100 mgmt_start_discovery_failed(hdev, status);
3101 hci_dev_unlock(hdev);
3102 return;
3103 }
3104
3105 hci_dev_lock(hdev);
3106 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3107 hci_dev_unlock(hdev);
3108
3109 switch (hdev->discovery.type) {
3110 case DISCOV_TYPE_LE:
3111 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003112 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003113 break;
3114
3115 case DISCOV_TYPE_INTERLEAVED:
3116 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003117 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003118 break;
3119
3120 case DISCOV_TYPE_BREDR:
3121 break;
3122
3123 default:
3124 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3125 }
3126}
3127
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003128static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003129 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003130{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003131 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003132 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003133 struct hci_cp_le_set_scan_param param_cp;
3134 struct hci_cp_le_set_scan_enable enable_cp;
3135 struct hci_cp_inquiry inq_cp;
3136 struct hci_request req;
3137 /* General inquiry access code (GIAC) */
3138 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003139 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003140 int err;
3141
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003142 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003143
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003144 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003145
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003146 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003147 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003148 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003149 goto failed;
3150 }
3151
Andre Guedes642be6c2012-03-21 00:03:37 -03003152 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3153 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3154 MGMT_STATUS_BUSY);
3155 goto failed;
3156 }
3157
Johan Hedbergff9ef572012-01-04 14:23:45 +02003158 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003159 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003160 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003161 goto failed;
3162 }
3163
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003164 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003165 if (!cmd) {
3166 err = -ENOMEM;
3167 goto failed;
3168 }
3169
Andre Guedes4aab14e2012-02-17 20:39:36 -03003170 hdev->discovery.type = cp->type;
3171
Andre Guedes7c307722013-04-30 15:29:28 -03003172 hci_req_init(&req, hdev);
3173
Andre Guedes4aab14e2012-02-17 20:39:36 -03003174 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003175 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003176 status = mgmt_bredr_support(hdev);
3177 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003178 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003179 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003180 mgmt_pending_remove(cmd);
3181 goto failed;
3182 }
3183
Andre Guedes7c307722013-04-30 15:29:28 -03003184 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3185 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3186 MGMT_STATUS_BUSY);
3187 mgmt_pending_remove(cmd);
3188 goto failed;
3189 }
3190
3191 hci_inquiry_cache_flush(hdev);
3192
3193 memset(&inq_cp, 0, sizeof(inq_cp));
3194 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003195 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003196 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003197 break;
3198
3199 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003200 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003201 status = mgmt_le_support(hdev);
3202 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003203 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003204 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003205 mgmt_pending_remove(cmd);
3206 goto failed;
3207 }
3208
Andre Guedes7c307722013-04-30 15:29:28 -03003209 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003210 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003211 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3212 MGMT_STATUS_NOT_SUPPORTED);
3213 mgmt_pending_remove(cmd);
3214 goto failed;
3215 }
3216
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003217 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003218 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3219 MGMT_STATUS_REJECTED);
3220 mgmt_pending_remove(cmd);
3221 goto failed;
3222 }
3223
3224 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3225 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3226 MGMT_STATUS_BUSY);
3227 mgmt_pending_remove(cmd);
3228 goto failed;
3229 }
3230
3231 memset(&param_cp, 0, sizeof(param_cp));
3232 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003233 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3234 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07003235 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
3236 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
3237 else
3238 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03003239 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3240 &param_cp);
3241
3242 memset(&enable_cp, 0, sizeof(enable_cp));
3243 enable_cp.enable = LE_SCAN_ENABLE;
3244 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3245 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3246 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003247 break;
3248
Andre Guedesf39799f2012-02-17 20:39:35 -03003249 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003250 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3251 MGMT_STATUS_INVALID_PARAMS);
3252 mgmt_pending_remove(cmd);
3253 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003254 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003255
Andre Guedes7c307722013-04-30 15:29:28 -03003256 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003257 if (err < 0)
3258 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003259 else
3260 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003261
3262failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003263 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003264 return err;
3265}
3266
Andre Guedes1183fdc2013-04-30 15:29:35 -03003267static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3268{
3269 struct pending_cmd *cmd;
3270 int err;
3271
3272 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3273 if (!cmd)
3274 return -ENOENT;
3275
3276 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3277 &hdev->discovery.type, sizeof(hdev->discovery.type));
3278 mgmt_pending_remove(cmd);
3279
3280 return err;
3281}
3282
Andre Guedes0e05bba2013-04-30 15:29:33 -03003283static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3284{
3285 BT_DBG("status %d", status);
3286
3287 hci_dev_lock(hdev);
3288
3289 if (status) {
3290 mgmt_stop_discovery_failed(hdev, status);
3291 goto unlock;
3292 }
3293
3294 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3295
3296unlock:
3297 hci_dev_unlock(hdev);
3298}
3299
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003300static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003301 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003302{
Johan Hedbergd9306502012-02-20 23:25:18 +02003303 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003304 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003305 struct hci_cp_remote_name_req_cancel cp;
3306 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003307 struct hci_request req;
3308 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003309 int err;
3310
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003311 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003312
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003313 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003314
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003315 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003316 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003317 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3318 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003319 goto unlock;
3320 }
3321
3322 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003323 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003324 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3325 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003326 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003327 }
3328
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003329 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003330 if (!cmd) {
3331 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003332 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003333 }
3334
Andre Guedes0e05bba2013-04-30 15:29:33 -03003335 hci_req_init(&req, hdev);
3336
Andre Guedese0d9727e2012-03-20 15:15:36 -03003337 switch (hdev->discovery.state) {
3338 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003339 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3340 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3341 } else {
3342 cancel_delayed_work(&hdev->le_scan_disable);
3343
3344 memset(&enable_cp, 0, sizeof(enable_cp));
3345 enable_cp.enable = LE_SCAN_DISABLE;
3346 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3347 sizeof(enable_cp), &enable_cp);
3348 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003349
Andre Guedese0d9727e2012-03-20 15:15:36 -03003350 break;
3351
3352 case DISCOVERY_RESOLVING:
3353 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003354 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003355 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003356 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003357 err = cmd_complete(sk, hdev->id,
3358 MGMT_OP_STOP_DISCOVERY, 0,
3359 &mgmt_cp->type,
3360 sizeof(mgmt_cp->type));
3361 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3362 goto unlock;
3363 }
3364
3365 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003366 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3367 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003368
3369 break;
3370
3371 default:
3372 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003373
3374 mgmt_pending_remove(cmd);
3375 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3376 MGMT_STATUS_FAILED, &mgmt_cp->type,
3377 sizeof(mgmt_cp->type));
3378 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003379 }
3380
Andre Guedes0e05bba2013-04-30 15:29:33 -03003381 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003382 if (err < 0)
3383 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003384 else
3385 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003386
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003387unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003388 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003389 return err;
3390}
3391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003392static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003393 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003394{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003395 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003396 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003397 int err;
3398
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003399 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003400
Johan Hedberg561aafb2012-01-04 13:31:59 +02003401 hci_dev_lock(hdev);
3402
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003403 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003404 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003405 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003406 goto failed;
3407 }
3408
Johan Hedberga198e7b2012-02-17 14:27:06 +02003409 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003410 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003411 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003412 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003413 goto failed;
3414 }
3415
3416 if (cp->name_known) {
3417 e->name_state = NAME_KNOWN;
3418 list_del(&e->list);
3419 } else {
3420 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003421 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003422 }
3423
Johan Hedberge3846622013-01-09 15:29:33 +02003424 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3425 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003426
3427failed:
3428 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003429 return err;
3430}
3431
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003432static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003433 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003434{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003435 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003436 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003437 int err;
3438
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003439 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003440
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003441 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003442 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3443 MGMT_STATUS_INVALID_PARAMS,
3444 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003445
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003446 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003447
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003448 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003449 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003450 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003451 else
Szymon Janca6785be2012-12-13 15:11:21 +01003452 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003453
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003454 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003455 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003456
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003457 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003458
3459 return err;
3460}
3461
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003462static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003463 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003464{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003465 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003466 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003467 int err;
3468
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003469 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003470
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003471 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003472 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3473 MGMT_STATUS_INVALID_PARAMS,
3474 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003475
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003476 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003477
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003478 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003479 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003480 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003481 else
Szymon Janca6785be2012-12-13 15:11:21 +01003482 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003483
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003484 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003485 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003486
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003487 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003488
3489 return err;
3490}
3491
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003492static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3493 u16 len)
3494{
3495 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003496 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003497 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003498 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003499
3500 BT_DBG("%s", hdev->name);
3501
Szymon Jancc72d4b82012-03-16 16:02:57 +01003502 source = __le16_to_cpu(cp->source);
3503
3504 if (source > 0x0002)
3505 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3506 MGMT_STATUS_INVALID_PARAMS);
3507
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003508 hci_dev_lock(hdev);
3509
Szymon Jancc72d4b82012-03-16 16:02:57 +01003510 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003511 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3512 hdev->devid_product = __le16_to_cpu(cp->product);
3513 hdev->devid_version = __le16_to_cpu(cp->version);
3514
3515 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3516
Johan Hedberg890ea892013-03-15 17:06:52 -05003517 hci_req_init(&req, hdev);
3518 update_eir(&req);
3519 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003520
3521 hci_dev_unlock(hdev);
3522
3523 return err;
3524}
3525
Johan Hedberg4375f102013-09-25 13:26:10 +03003526static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3527{
3528 struct cmd_lookup match = { NULL, hdev };
3529
3530 if (status) {
3531 u8 mgmt_err = mgmt_status(status);
3532
3533 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3534 cmd_status_rsp, &mgmt_err);
3535 return;
3536 }
3537
3538 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3539 &match);
3540
3541 new_settings(hdev, match.sk);
3542
3543 if (match.sk)
3544 sock_put(match.sk);
3545}
3546
Marcel Holtmann21b51872013-10-10 09:47:53 -07003547static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3548 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003549{
3550 struct mgmt_mode *cp = data;
3551 struct pending_cmd *cmd;
3552 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003553 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003554 int err;
3555
3556 BT_DBG("request for %s", hdev->name);
3557
Johan Hedberge6fe7982013-10-02 15:45:22 +03003558 status = mgmt_le_support(hdev);
3559 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003560 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003561 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003562
3563 if (cp->val != 0x00 && cp->val != 0x01)
3564 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3565 MGMT_STATUS_INVALID_PARAMS);
3566
3567 hci_dev_lock(hdev);
3568
3569 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003570 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003571
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003572 /* The following conditions are ones which mean that we should
3573 * not do any HCI communication but directly send a mgmt
3574 * response to user space (after toggling the flag if
3575 * necessary).
3576 */
3577 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003578 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003579 bool changed = false;
3580
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003581 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3582 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003583 changed = true;
3584 }
3585
3586 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3587 if (err < 0)
3588 goto unlock;
3589
3590 if (changed)
3591 err = new_settings(hdev, sk);
3592
3593 goto unlock;
3594 }
3595
3596 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3597 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3598 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3599 MGMT_STATUS_BUSY);
3600 goto unlock;
3601 }
3602
3603 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3604 if (!cmd) {
3605 err = -ENOMEM;
3606 goto unlock;
3607 }
3608
3609 hci_req_init(&req, hdev);
3610
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003611 if (val)
3612 enable_advertising(&req);
3613 else
3614 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003615
3616 err = hci_req_run(&req, set_advertising_complete);
3617 if (err < 0)
3618 mgmt_pending_remove(cmd);
3619
3620unlock:
3621 hci_dev_unlock(hdev);
3622 return err;
3623}
3624
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003625static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3626 void *data, u16 len)
3627{
3628 struct mgmt_cp_set_static_address *cp = data;
3629 int err;
3630
3631 BT_DBG("%s", hdev->name);
3632
Marcel Holtmann62af4442013-10-02 22:10:32 -07003633 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003634 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003635 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003636
3637 if (hdev_is_powered(hdev))
3638 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3639 MGMT_STATUS_REJECTED);
3640
3641 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3642 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3643 return cmd_status(sk, hdev->id,
3644 MGMT_OP_SET_STATIC_ADDRESS,
3645 MGMT_STATUS_INVALID_PARAMS);
3646
3647 /* Two most significant bits shall be set */
3648 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3649 return cmd_status(sk, hdev->id,
3650 MGMT_OP_SET_STATIC_ADDRESS,
3651 MGMT_STATUS_INVALID_PARAMS);
3652 }
3653
3654 hci_dev_lock(hdev);
3655
3656 bacpy(&hdev->static_addr, &cp->bdaddr);
3657
3658 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3659
3660 hci_dev_unlock(hdev);
3661
3662 return err;
3663}
3664
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003665static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3666 void *data, u16 len)
3667{
3668 struct mgmt_cp_set_scan_params *cp = data;
3669 __u16 interval, window;
3670 int err;
3671
3672 BT_DBG("%s", hdev->name);
3673
3674 if (!lmp_le_capable(hdev))
3675 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3676 MGMT_STATUS_NOT_SUPPORTED);
3677
3678 interval = __le16_to_cpu(cp->interval);
3679
3680 if (interval < 0x0004 || interval > 0x4000)
3681 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3682 MGMT_STATUS_INVALID_PARAMS);
3683
3684 window = __le16_to_cpu(cp->window);
3685
3686 if (window < 0x0004 || window > 0x4000)
3687 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3688 MGMT_STATUS_INVALID_PARAMS);
3689
Marcel Holtmann899e1072013-10-14 09:55:32 -07003690 if (window > interval)
3691 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3692 MGMT_STATUS_INVALID_PARAMS);
3693
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003694 hci_dev_lock(hdev);
3695
3696 hdev->le_scan_interval = interval;
3697 hdev->le_scan_window = window;
3698
3699 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3700
3701 hci_dev_unlock(hdev);
3702
3703 return err;
3704}
3705
Johan Hedberg33e38b32013-03-15 17:07:05 -05003706static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3707{
3708 struct pending_cmd *cmd;
3709
3710 BT_DBG("status 0x%02x", status);
3711
3712 hci_dev_lock(hdev);
3713
3714 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3715 if (!cmd)
3716 goto unlock;
3717
3718 if (status) {
3719 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3720 mgmt_status(status));
3721 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003722 struct mgmt_mode *cp = cmd->param;
3723
3724 if (cp->val)
3725 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3726 else
3727 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3728
Johan Hedberg33e38b32013-03-15 17:07:05 -05003729 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3730 new_settings(hdev, cmd->sk);
3731 }
3732
3733 mgmt_pending_remove(cmd);
3734
3735unlock:
3736 hci_dev_unlock(hdev);
3737}
3738
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003739static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003740 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003741{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003742 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003743 struct pending_cmd *cmd;
3744 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003745 int err;
3746
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003747 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003748
Johan Hedberg56f87902013-10-02 13:43:13 +03003749 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3750 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003751 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3752 MGMT_STATUS_NOT_SUPPORTED);
3753
Johan Hedberga7e80f22013-01-09 16:05:19 +02003754 if (cp->val != 0x00 && cp->val != 0x01)
3755 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3756 MGMT_STATUS_INVALID_PARAMS);
3757
Johan Hedberg5400c042012-02-21 16:40:33 +02003758 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003759 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003760 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003761
3762 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003763 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003764 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003765
3766 hci_dev_lock(hdev);
3767
Johan Hedberg05cbf292013-03-15 17:07:07 -05003768 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3769 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3770 MGMT_STATUS_BUSY);
3771 goto unlock;
3772 }
3773
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003774 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3775 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3776 hdev);
3777 goto unlock;
3778 }
3779
Johan Hedberg33e38b32013-03-15 17:07:05 -05003780 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3781 data, len);
3782 if (!cmd) {
3783 err = -ENOMEM;
3784 goto unlock;
3785 }
3786
3787 hci_req_init(&req, hdev);
3788
Johan Hedberg406d7802013-03-15 17:07:09 -05003789 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003790
3791 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003792 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003793 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003794 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003795 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003796 }
3797
Johan Hedberg33e38b32013-03-15 17:07:05 -05003798unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003799 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003800
Antti Julkuf6422ec2011-06-22 13:11:56 +03003801 return err;
3802}
3803
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003804static void set_bredr_scan(struct hci_request *req)
3805{
3806 struct hci_dev *hdev = req->hdev;
3807 u8 scan = 0;
3808
3809 /* Ensure that fast connectable is disabled. This function will
3810 * not do anything if the page scan parameters are already what
3811 * they should be.
3812 */
3813 write_fast_connectable(req, false);
3814
3815 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3816 scan |= SCAN_PAGE;
3817 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3818 scan |= SCAN_INQUIRY;
3819
3820 if (scan)
3821 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3822}
3823
Johan Hedberg0663ca22013-10-02 13:43:14 +03003824static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3825{
3826 struct pending_cmd *cmd;
3827
3828 BT_DBG("status 0x%02x", status);
3829
3830 hci_dev_lock(hdev);
3831
3832 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3833 if (!cmd)
3834 goto unlock;
3835
3836 if (status) {
3837 u8 mgmt_err = mgmt_status(status);
3838
3839 /* We need to restore the flag if related HCI commands
3840 * failed.
3841 */
3842 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3843
3844 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3845 } else {
3846 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3847 new_settings(hdev, cmd->sk);
3848 }
3849
3850 mgmt_pending_remove(cmd);
3851
3852unlock:
3853 hci_dev_unlock(hdev);
3854}
3855
3856static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3857{
3858 struct mgmt_mode *cp = data;
3859 struct pending_cmd *cmd;
3860 struct hci_request req;
3861 int err;
3862
3863 BT_DBG("request for %s", hdev->name);
3864
3865 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3866 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3867 MGMT_STATUS_NOT_SUPPORTED);
3868
3869 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3870 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3871 MGMT_STATUS_REJECTED);
3872
3873 if (cp->val != 0x00 && cp->val != 0x01)
3874 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3875 MGMT_STATUS_INVALID_PARAMS);
3876
3877 hci_dev_lock(hdev);
3878
3879 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3880 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3881 goto unlock;
3882 }
3883
3884 if (!hdev_is_powered(hdev)) {
3885 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003886 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3887 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3888 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3889 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3890 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3891 }
3892
3893 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3894
3895 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3896 if (err < 0)
3897 goto unlock;
3898
3899 err = new_settings(hdev, sk);
3900 goto unlock;
3901 }
3902
3903 /* Reject disabling when powered on */
3904 if (!cp->val) {
3905 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3906 MGMT_STATUS_REJECTED);
3907 goto unlock;
3908 }
3909
3910 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3911 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3912 MGMT_STATUS_BUSY);
3913 goto unlock;
3914 }
3915
3916 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3917 if (!cmd) {
3918 err = -ENOMEM;
3919 goto unlock;
3920 }
3921
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07003922 /* We need to flip the bit already here so that update_ad
Johan Hedberg0663ca22013-10-02 13:43:14 +03003923 * generates the correct flags.
3924 */
3925 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3926
3927 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003928
3929 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3930 set_bredr_scan(&req);
3931
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07003932 /* Since only the advertising data flags will change, there
3933 * is no need to update the scan response data.
3934 */
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07003935 update_ad(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003936
Johan Hedberg0663ca22013-10-02 13:43:14 +03003937 err = hci_req_run(&req, set_bredr_complete);
3938 if (err < 0)
3939 mgmt_pending_remove(cmd);
3940
3941unlock:
3942 hci_dev_unlock(hdev);
3943 return err;
3944}
3945
Johan Hedberg3f706b72013-01-20 14:27:16 +02003946static bool ltk_is_valid(struct mgmt_ltk_info *key)
3947{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003948 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3949 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003950 if (key->master != 0x00 && key->master != 0x01)
3951 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003952 if (!bdaddr_type_is_le(key->addr.type))
3953 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003954 return true;
3955}
3956
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003957static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003958 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003959{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003960 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3961 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003962 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003963
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003964 BT_DBG("request for %s", hdev->name);
3965
3966 if (!lmp_le_capable(hdev))
3967 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3968 MGMT_STATUS_NOT_SUPPORTED);
3969
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003970 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003971
3972 expected_len = sizeof(*cp) + key_count *
3973 sizeof(struct mgmt_ltk_info);
3974 if (expected_len != len) {
3975 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003976 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003977 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003978 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003979 }
3980
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003981 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003982
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003983 for (i = 0; i < key_count; i++) {
3984 struct mgmt_ltk_info *key = &cp->keys[i];
3985
Johan Hedberg3f706b72013-01-20 14:27:16 +02003986 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003987 return cmd_status(sk, hdev->id,
3988 MGMT_OP_LOAD_LONG_TERM_KEYS,
3989 MGMT_STATUS_INVALID_PARAMS);
3990 }
3991
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003992 hci_dev_lock(hdev);
3993
3994 hci_smp_ltks_clear(hdev);
3995
3996 for (i = 0; i < key_count; i++) {
3997 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003998 u8 type, addr_type;
3999
4000 if (key->addr.type == BDADDR_LE_PUBLIC)
4001 addr_type = ADDR_LE_DEV_PUBLIC;
4002 else
4003 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004004
4005 if (key->master)
4006 type = HCI_SMP_LTK;
4007 else
4008 type = HCI_SMP_LTK_SLAVE;
4009
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004010 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004011 type, 0, key->authenticated, key->val,
4012 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004013 }
4014
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004015 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4016 NULL, 0);
4017
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004018 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004019
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004020 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004021}
4022
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004023static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004024 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4025 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004026 bool var_len;
4027 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004028} mgmt_handlers[] = {
4029 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004030 { read_version, false, MGMT_READ_VERSION_SIZE },
4031 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4032 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4033 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4034 { set_powered, false, MGMT_SETTING_SIZE },
4035 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4036 { set_connectable, false, MGMT_SETTING_SIZE },
4037 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4038 { set_pairable, false, MGMT_SETTING_SIZE },
4039 { set_link_security, false, MGMT_SETTING_SIZE },
4040 { set_ssp, false, MGMT_SETTING_SIZE },
4041 { set_hs, false, MGMT_SETTING_SIZE },
4042 { set_le, false, MGMT_SETTING_SIZE },
4043 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4044 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4045 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4046 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4047 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4048 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4049 { disconnect, false, MGMT_DISCONNECT_SIZE },
4050 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4051 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4052 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4053 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4054 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4055 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4056 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4057 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4058 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4059 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4060 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4061 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
4062 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
4063 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4064 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4065 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4066 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4067 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4068 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004069 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004070 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004071 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004072 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004073 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004074};
4075
4076
Johan Hedberg03811012010-12-08 00:21:06 +02004077int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4078{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004079 void *buf;
4080 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004081 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004082 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004083 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004084 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004085 int err;
4086
4087 BT_DBG("got %zu bytes", msglen);
4088
4089 if (msglen < sizeof(*hdr))
4090 return -EINVAL;
4091
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004092 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004093 if (!buf)
4094 return -ENOMEM;
4095
4096 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4097 err = -EFAULT;
4098 goto done;
4099 }
4100
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004101 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004102 opcode = __le16_to_cpu(hdr->opcode);
4103 index = __le16_to_cpu(hdr->index);
4104 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004105
4106 if (len != msglen - sizeof(*hdr)) {
4107 err = -EINVAL;
4108 goto done;
4109 }
4110
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004111 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004112 hdev = hci_dev_get(index);
4113 if (!hdev) {
4114 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004115 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004116 goto done;
4117 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004118
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004119 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4120 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004121 err = cmd_status(sk, index, opcode,
4122 MGMT_STATUS_INVALID_INDEX);
4123 goto done;
4124 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004125 }
4126
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004127 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004128 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004129 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004130 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004131 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004132 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004133 }
4134
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004135 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004136 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004137 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004138 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004139 goto done;
4140 }
4141
Johan Hedbergbe22b542012-03-01 22:24:41 +02004142 handler = &mgmt_handlers[opcode];
4143
4144 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004145 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004146 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004147 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004148 goto done;
4149 }
4150
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004151 if (hdev)
4152 mgmt_init_hdev(sk, hdev);
4153
4154 cp = buf + sizeof(*hdr);
4155
Johan Hedbergbe22b542012-03-01 22:24:41 +02004156 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004157 if (err < 0)
4158 goto done;
4159
Johan Hedberg03811012010-12-08 00:21:06 +02004160 err = msglen;
4161
4162done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004163 if (hdev)
4164 hci_dev_put(hdev);
4165
Johan Hedberg03811012010-12-08 00:21:06 +02004166 kfree(buf);
4167 return err;
4168}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004169
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004170void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004171{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004172 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004173 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004174
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004175 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004176}
4177
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004178void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004179{
Johan Hedberg5f159032012-03-02 03:13:19 +02004180 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004181
Marcel Holtmann1514b892013-10-06 08:25:01 -07004182 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004183 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004184
Johan Hedberg744cf192011-11-08 20:40:14 +02004185 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004186
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004187 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004188}
4189
Johan Hedberg229ab392013-03-15 17:06:53 -05004190static void powered_complete(struct hci_dev *hdev, u8 status)
4191{
4192 struct cmd_lookup match = { NULL, hdev };
4193
4194 BT_DBG("status 0x%02x", status);
4195
4196 hci_dev_lock(hdev);
4197
4198 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4199
4200 new_settings(hdev, match.sk);
4201
4202 hci_dev_unlock(hdev);
4203
4204 if (match.sk)
4205 sock_put(match.sk);
4206}
4207
Johan Hedberg70da6242013-03-15 17:06:51 -05004208static int powered_update_hci(struct hci_dev *hdev)
4209{
Johan Hedberg890ea892013-03-15 17:06:52 -05004210 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004211 u8 link_sec;
4212
Johan Hedberg890ea892013-03-15 17:06:52 -05004213 hci_req_init(&req, hdev);
4214
Johan Hedberg70da6242013-03-15 17:06:51 -05004215 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4216 !lmp_host_ssp_capable(hdev)) {
4217 u8 ssp = 1;
4218
Johan Hedberg890ea892013-03-15 17:06:52 -05004219 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004220 }
4221
Johan Hedbergc73eee92013-04-19 18:35:21 +03004222 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4223 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004224 struct hci_cp_write_le_host_supported cp;
4225
4226 cp.le = 1;
4227 cp.simul = lmp_le_br_capable(hdev);
4228
4229 /* Check first if we already have the right
4230 * host state (host features set)
4231 */
4232 if (cp.le != lmp_host_le_capable(hdev) ||
4233 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004234 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4235 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004236 }
4237
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004238 if (lmp_le_capable(hdev)) {
4239 /* Set random address to static address if configured */
4240 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4241 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4242 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004243
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004244 /* Make sure the controller has a good default for
4245 * advertising data. This also applies to the case
4246 * where BR/EDR was toggled during the AUTO_OFF phase.
4247 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004248 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004249 update_ad(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004250 update_scan_rsp_data(&req);
4251 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004252
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004253 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4254 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004255 }
4256
Johan Hedberg70da6242013-03-15 17:06:51 -05004257 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4258 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004259 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4260 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004261
4262 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004263 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4264 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004265 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004266 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004267 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004268 }
4269
Johan Hedberg229ab392013-03-15 17:06:53 -05004270 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004271}
4272
Johan Hedberg744cf192011-11-08 20:40:14 +02004273int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004274{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004275 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004276 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4277 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004278 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004279
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004280 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4281 return 0;
4282
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004283 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004284 if (powered_update_hci(hdev) == 0)
4285 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004286
Johan Hedberg229ab392013-03-15 17:06:53 -05004287 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4288 &match);
4289 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004290 }
4291
Johan Hedberg229ab392013-03-15 17:06:53 -05004292 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4293 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4294
4295 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4296 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4297 zero_cod, sizeof(zero_cod), NULL);
4298
4299new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004300 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004301
4302 if (match.sk)
4303 sock_put(match.sk);
4304
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004305 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004306}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004307
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004308void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004309{
4310 struct pending_cmd *cmd;
4311 u8 status;
4312
4313 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4314 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004315 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004316
4317 if (err == -ERFKILL)
4318 status = MGMT_STATUS_RFKILLED;
4319 else
4320 status = MGMT_STATUS_FAILED;
4321
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004322 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004323
4324 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004325}
4326
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004327void mgmt_discoverable_timeout(struct hci_dev *hdev)
4328{
4329 struct hci_request req;
4330 u8 scan = SCAN_PAGE;
4331
4332 hci_dev_lock(hdev);
4333
4334 /* When discoverable timeout triggers, then just make sure
4335 * the limited discoverable flag is cleared. Even in the case
4336 * of a timeout triggered from general discoverable, it is
4337 * safe to unconditionally clear the flag.
4338 */
4339 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
4340
4341 hci_req_init(&req, hdev);
4342 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
4343 update_class(&req);
4344 hci_req_run(&req, NULL);
4345
4346 hdev->discov_timeout = 0;
4347
4348 hci_dev_unlock(hdev);
4349}
4350
Marcel Holtmann86a75642013-10-15 06:33:54 -07004351void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004352{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004353 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004354
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004355 /* Nothing needed here if there's a pending command since that
4356 * commands request completion callback takes care of everything
4357 * necessary.
4358 */
4359 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004360 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004361
Marcel Holtmann86a75642013-10-15 06:33:54 -07004362 if (discoverable)
4363 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4364 else
4365 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004366
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004367 if (changed)
Marcel Holtmann86a75642013-10-15 06:33:54 -07004368 new_settings(hdev, NULL);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004369}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004370
Marcel Holtmanna3309162013-10-15 06:33:55 -07004371void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004372{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004373 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004374
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004375 /* Nothing needed here if there's a pending command since that
4376 * commands request completion callback takes care of everything
4377 * necessary.
4378 */
4379 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004380 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004381
Marcel Holtmanna3309162013-10-15 06:33:55 -07004382 if (connectable)
4383 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4384 else
4385 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004386
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004387 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004388 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004389}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004390
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004391void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004392{
Johan Hedbergca69b792011-11-11 18:10:00 +02004393 u8 mgmt_err = mgmt_status(status);
4394
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004395 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004396 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004397 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004398
4399 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004400 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004401 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004402}
4403
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004404void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4405 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004406{
Johan Hedberg86742e12011-11-07 23:13:38 +02004407 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004408
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004409 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004410
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004411 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004412 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004413 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004414 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004415 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004416 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004417
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004418 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004419}
Johan Hedbergf7520542011-01-20 12:34:39 +02004420
Marcel Holtmann083368f2013-10-15 14:26:29 -07004421void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004422{
4423 struct mgmt_ev_new_long_term_key ev;
4424
4425 memset(&ev, 0, sizeof(ev));
4426
4427 ev.store_hint = persistent;
4428 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004429 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004430 ev.key.authenticated = key->authenticated;
4431 ev.key.enc_size = key->enc_size;
4432 ev.key.ediv = key->ediv;
4433
4434 if (key->type == HCI_SMP_LTK)
4435 ev.key.master = 1;
4436
4437 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4438 memcpy(ev.key.val, key->val, sizeof(key->val));
4439
Marcel Holtmann083368f2013-10-15 14:26:29 -07004440 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004441}
4442
Marcel Holtmann94933992013-10-15 10:26:39 -07004443static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4444 u8 data_len)
4445{
4446 eir[eir_len++] = sizeof(type) + data_len;
4447 eir[eir_len++] = type;
4448 memcpy(&eir[eir_len], data, data_len);
4449 eir_len += data_len;
4450
4451 return eir_len;
4452}
4453
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004454void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4455 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4456 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004457{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004458 char buf[512];
4459 struct mgmt_ev_device_connected *ev = (void *) buf;
4460 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004461
Johan Hedbergb644ba32012-01-17 21:48:47 +02004462 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004463 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004464
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004465 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004466
Johan Hedbergb644ba32012-01-17 21:48:47 +02004467 if (name_len > 0)
4468 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004469 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004470
4471 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004472 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004473 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004474
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004475 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004476
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004477 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4478 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004479}
4480
Johan Hedberg8962ee72011-01-20 12:40:27 +02004481static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4482{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004483 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004484 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004485 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004486
Johan Hedberg88c3df12012-02-09 14:27:38 +02004487 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4488 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004489
Johan Hedbergaee9b212012-02-18 15:07:59 +02004490 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004491 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004492
4493 *sk = cmd->sk;
4494 sock_hold(*sk);
4495
Johan Hedberga664b5b2011-02-19 12:06:02 -03004496 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004497}
4498
Johan Hedberg124f6e32012-02-09 13:50:12 +02004499static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004500{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004501 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004502 struct mgmt_cp_unpair_device *cp = cmd->param;
4503 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004504
4505 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004506 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4507 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004508
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004509 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4510
Johan Hedbergaee9b212012-02-18 15:07:59 +02004511 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004512
4513 mgmt_pending_remove(cmd);
4514}
4515
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004516void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4517 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004518{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004519 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004520 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004521
Johan Hedberg744cf192011-11-08 20:40:14 +02004522 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004523
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004524 bacpy(&ev.addr.bdaddr, bdaddr);
4525 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4526 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004527
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004528 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004529
4530 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004531 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004532
Johan Hedberg124f6e32012-02-09 13:50:12 +02004533 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004534 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004535}
4536
Marcel Holtmann78929242013-10-06 23:55:47 -07004537void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4538 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004539{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004540 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004541 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004542
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004543 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4544 hdev);
4545
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004546 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004547 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004548 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004549
Johan Hedberg88c3df12012-02-09 14:27:38 +02004550 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004551 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004552
Marcel Holtmann78929242013-10-06 23:55:47 -07004553 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4554 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004555
Johan Hedberga664b5b2011-02-19 12:06:02 -03004556 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004557}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004558
Marcel Holtmann445608d2013-10-06 23:55:48 -07004559void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4560 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004561{
4562 struct mgmt_ev_connect_failed ev;
4563
Johan Hedberg4c659c32011-11-07 23:13:39 +02004564 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004565 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004566 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004567
Marcel Holtmann445608d2013-10-06 23:55:48 -07004568 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004569}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004570
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004571void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004572{
4573 struct mgmt_ev_pin_code_request ev;
4574
Johan Hedbergd8457692012-02-17 14:24:57 +02004575 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004576 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004577 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004578
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004579 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004580}
4581
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004582void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4583 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004584{
4585 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004586 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004587
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004588 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004589 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004590 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004591
Johan Hedbergd8457692012-02-17 14:24:57 +02004592 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004593 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004594
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004595 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4596 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004597
Johan Hedberga664b5b2011-02-19 12:06:02 -03004598 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004599}
4600
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004601void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4602 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004603{
4604 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004605 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004606
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004607 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004608 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004609 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004610
Johan Hedbergd8457692012-02-17 14:24:57 +02004611 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004612 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004613
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004614 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4615 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004616
Johan Hedberga664b5b2011-02-19 12:06:02 -03004617 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004618}
Johan Hedberga5c29682011-02-19 12:05:57 -03004619
Johan Hedberg744cf192011-11-08 20:40:14 +02004620int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004621 u8 link_type, u8 addr_type, __le32 value,
4622 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004623{
4624 struct mgmt_ev_user_confirm_request ev;
4625
Johan Hedberg744cf192011-11-08 20:40:14 +02004626 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004627
Johan Hedberg272d90d2012-02-09 15:26:12 +02004628 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004629 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004630 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004631 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004632
Johan Hedberg744cf192011-11-08 20:40:14 +02004633 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004634 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004635}
4636
Johan Hedberg272d90d2012-02-09 15:26:12 +02004637int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004638 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004639{
4640 struct mgmt_ev_user_passkey_request ev;
4641
4642 BT_DBG("%s", hdev->name);
4643
Johan Hedberg272d90d2012-02-09 15:26:12 +02004644 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004645 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004646
4647 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004648 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004649}
4650
Brian Gix0df4c182011-11-16 13:53:13 -08004651static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004652 u8 link_type, u8 addr_type, u8 status,
4653 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004654{
4655 struct pending_cmd *cmd;
4656 struct mgmt_rp_user_confirm_reply rp;
4657 int err;
4658
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004659 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004660 if (!cmd)
4661 return -ENOENT;
4662
Johan Hedberg272d90d2012-02-09 15:26:12 +02004663 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004664 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004665 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004666 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004667
Johan Hedberga664b5b2011-02-19 12:06:02 -03004668 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004669
4670 return err;
4671}
4672
Johan Hedberg744cf192011-11-08 20:40:14 +02004673int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004674 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004675{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004676 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004677 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004678}
4679
Johan Hedberg272d90d2012-02-09 15:26:12 +02004680int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004681 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004682{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004683 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004684 status,
4685 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004686}
Johan Hedberg2a611692011-02-19 12:06:00 -03004687
Brian Gix604086b2011-11-23 08:28:33 -08004688int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004689 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004690{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004691 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004692 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004693}
4694
Johan Hedberg272d90d2012-02-09 15:26:12 +02004695int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004696 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004697{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004698 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004699 status,
4700 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004701}
4702
Johan Hedberg92a25252012-09-06 18:39:26 +03004703int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4704 u8 link_type, u8 addr_type, u32 passkey,
4705 u8 entered)
4706{
4707 struct mgmt_ev_passkey_notify ev;
4708
4709 BT_DBG("%s", hdev->name);
4710
4711 bacpy(&ev.addr.bdaddr, bdaddr);
4712 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4713 ev.passkey = __cpu_to_le32(passkey);
4714 ev.entered = entered;
4715
4716 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4717}
4718
Marcel Holtmanne5460992013-10-15 14:26:23 -07004719void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4720 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004721{
4722 struct mgmt_ev_auth_failed ev;
4723
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004724 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004725 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004726 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004727
Marcel Holtmanne5460992013-10-15 14:26:23 -07004728 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004729}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004730
Marcel Holtmann464996a2013-10-15 14:26:24 -07004731void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004732{
4733 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004734 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004735
4736 if (status) {
4737 u8 mgmt_err = mgmt_status(status);
4738 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004739 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004740 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004741 }
4742
Marcel Holtmann464996a2013-10-15 14:26:24 -07004743 if (test_bit(HCI_AUTH, &hdev->flags))
4744 changed = !test_and_set_bit(HCI_LINK_SECURITY,
4745 &hdev->dev_flags);
4746 else
4747 changed = test_and_clear_bit(HCI_LINK_SECURITY,
4748 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02004749
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004750 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004751 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004752
Johan Hedberg47990ea2012-02-22 11:58:37 +02004753 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07004754 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004755
4756 if (match.sk)
4757 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004758}
4759
Johan Hedberg890ea892013-03-15 17:06:52 -05004760static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004761{
Johan Hedberg890ea892013-03-15 17:06:52 -05004762 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004763 struct hci_cp_write_eir cp;
4764
Johan Hedberg976eb202012-10-24 21:12:01 +03004765 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004766 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004767
Johan Hedbergc80da272012-02-22 15:38:48 +02004768 memset(hdev->eir, 0, sizeof(hdev->eir));
4769
Johan Hedbergcacaf522012-02-21 00:52:42 +02004770 memset(&cp, 0, sizeof(cp));
4771
Johan Hedberg890ea892013-03-15 17:06:52 -05004772 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004773}
4774
Marcel Holtmann3e248562013-10-15 14:26:25 -07004775void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004776{
4777 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004778 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004779 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004780
4781 if (status) {
4782 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004783
4784 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004785 &hdev->dev_flags)) {
4786 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004787 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004788 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004789
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004790 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4791 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004792 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004793 }
4794
4795 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004796 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004797 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004798 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4799 if (!changed)
4800 changed = test_and_clear_bit(HCI_HS_ENABLED,
4801 &hdev->dev_flags);
4802 else
4803 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004804 }
4805
4806 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4807
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004808 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07004809 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004810
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004811 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004812 sock_put(match.sk);
4813
Johan Hedberg890ea892013-03-15 17:06:52 -05004814 hci_req_init(&req, hdev);
4815
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004816 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004817 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004818 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004819 clear_eir(&req);
4820
4821 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004822}
4823
Johan Hedberg92da6092013-03-15 17:06:55 -05004824static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004825{
4826 struct cmd_lookup *match = data;
4827
Johan Hedberg90e70452012-02-23 23:09:40 +02004828 if (match->sk == NULL) {
4829 match->sk = cmd->sk;
4830 sock_hold(match->sk);
4831 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004832}
4833
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004834void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
4835 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004836{
Johan Hedberg90e70452012-02-23 23:09:40 +02004837 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004838
Johan Hedberg92da6092013-03-15 17:06:55 -05004839 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4840 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4841 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004842
4843 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004844 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
4845 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004846
4847 if (match.sk)
4848 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004849}
4850
Marcel Holtmann7667da32013-10-15 14:26:27 -07004851void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004852{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004853 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004854 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004855
Johan Hedberg13928972013-03-15 17:07:00 -05004856 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07004857 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004858
4859 memset(&ev, 0, sizeof(ev));
4860 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004861 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004862
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004863 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004864 if (!cmd) {
4865 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004866
Johan Hedberg13928972013-03-15 17:07:00 -05004867 /* If this is a HCI command related to powering on the
4868 * HCI dev don't send any mgmt signals.
4869 */
4870 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07004871 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004872 }
4873
Marcel Holtmann7667da32013-10-15 14:26:27 -07004874 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4875 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004876}
Szymon Jancc35938b2011-03-22 13:12:21 +01004877
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004878void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
4879 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004880{
4881 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01004882
Johan Hedberg744cf192011-11-08 20:40:14 +02004883 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004884
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004885 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004886 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004887 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01004888
4889 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004890 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4891 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004892 } else {
4893 struct mgmt_rp_read_local_oob_data rp;
4894
4895 memcpy(rp.hash, hash, sizeof(rp.hash));
4896 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4897
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004898 cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4899 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004900 }
4901
4902 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01004903}
Johan Hedberge17acd42011-03-30 23:57:16 +03004904
Marcel Holtmann901801b2013-10-06 23:55:51 -07004905void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4906 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4907 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004908{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004909 char buf[512];
4910 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004911 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004912
Andre Guedes12602d02013-04-30 15:29:40 -03004913 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004914 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004915
Johan Hedberg1dc06092012-01-15 21:01:23 +02004916 /* Leave 5 bytes for a potential CoD field */
4917 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004918 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004919
Johan Hedberg1dc06092012-01-15 21:01:23 +02004920 memset(buf, 0, sizeof(buf));
4921
Johan Hedberge319d2e2012-01-15 19:51:59 +02004922 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004923 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004924 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004925 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304926 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004927 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304928 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004929
Johan Hedberg1dc06092012-01-15 21:01:23 +02004930 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004931 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004932
Johan Hedberg1dc06092012-01-15 21:01:23 +02004933 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4934 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004935 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004936
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004937 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004938 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004939
Marcel Holtmann901801b2013-10-06 23:55:51 -07004940 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004941}
Johan Hedberga88a9652011-03-30 13:18:12 +03004942
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004943void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4944 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004945{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004946 struct mgmt_ev_device_found *ev;
4947 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4948 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004949
Johan Hedbergb644ba32012-01-17 21:48:47 +02004950 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004951
Johan Hedbergb644ba32012-01-17 21:48:47 +02004952 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004953
Johan Hedbergb644ba32012-01-17 21:48:47 +02004954 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004955 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004956 ev->rssi = rssi;
4957
4958 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004959 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004960
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004961 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004962
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004963 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004964}
Johan Hedberg314b2382011-04-27 10:29:57 -04004965
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004966void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004967{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004968 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004969 struct pending_cmd *cmd;
4970
Andre Guedes343fb142011-11-22 17:14:19 -03004971 BT_DBG("%s discovering %u", hdev->name, discovering);
4972
Johan Hedberg164a6e72011-11-01 17:06:44 +02004973 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004974 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004975 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004976 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004977
4978 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004979 u8 type = hdev->discovery.type;
4980
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004981 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4982 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004983 mgmt_pending_remove(cmd);
4984 }
4985
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004986 memset(&ev, 0, sizeof(ev));
4987 ev.type = hdev->discovery.type;
4988 ev.discovering = discovering;
4989
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004990 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004991}
Antti Julku5e762442011-08-25 16:48:02 +03004992
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004993int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004994{
4995 struct pending_cmd *cmd;
4996 struct mgmt_ev_device_blocked ev;
4997
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004998 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004999
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005000 bacpy(&ev.addr.bdaddr, bdaddr);
5001 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005002
Johan Hedberg744cf192011-11-08 20:40:14 +02005003 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005004 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005005}
5006
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005007int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005008{
5009 struct pending_cmd *cmd;
5010 struct mgmt_ev_device_unblocked ev;
5011
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005012 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005013
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005014 bacpy(&ev.addr.bdaddr, bdaddr);
5015 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005016
Johan Hedberg744cf192011-11-08 20:40:14 +02005017 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005018 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005019}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005020
5021static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5022{
5023 BT_DBG("%s status %u", hdev->name, status);
5024
5025 /* Clear the advertising mgmt setting if we failed to re-enable it */
5026 if (status) {
5027 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005028 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005029 }
5030}
5031
5032void mgmt_reenable_advertising(struct hci_dev *hdev)
5033{
5034 struct hci_request req;
5035
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005036 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005037 return;
5038
5039 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5040 return;
5041
5042 hci_req_init(&req, hdev);
5043 enable_advertising(&req);
5044
5045 /* If this fails we have no option but to let user space know
5046 * that we've disabled advertising.
5047 */
5048 if (hci_req_run(&req, adv_enable_complete) < 0) {
5049 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005050 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005051 }
5052}