blob: c363285c64a820d321f333396fd3935ef9adfd65 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070033
34#include "smp.h"
Johan Hedberg03811012010-12-08 00:21:06 +020035
Johan Hedberg2da9c552012-02-17 14:39:28 +020036#define MGMT_VERSION 1
Marcel Holtmann9ab8cf32013-10-02 05:18:31 -070037#define MGMT_REVISION 4
Johan Hedberg02d98122010-12-13 21:07:04 +020038
Johan Hedberge70bb2e2012-02-13 16:59:33 +020039static const u16 mgmt_commands[] = {
40 MGMT_OP_READ_INDEX_LIST,
41 MGMT_OP_READ_INFO,
42 MGMT_OP_SET_POWERED,
43 MGMT_OP_SET_DISCOVERABLE,
44 MGMT_OP_SET_CONNECTABLE,
45 MGMT_OP_SET_FAST_CONNECTABLE,
46 MGMT_OP_SET_PAIRABLE,
47 MGMT_OP_SET_LINK_SECURITY,
48 MGMT_OP_SET_SSP,
49 MGMT_OP_SET_HS,
50 MGMT_OP_SET_LE,
51 MGMT_OP_SET_DEV_CLASS,
52 MGMT_OP_SET_LOCAL_NAME,
53 MGMT_OP_ADD_UUID,
54 MGMT_OP_REMOVE_UUID,
55 MGMT_OP_LOAD_LINK_KEYS,
56 MGMT_OP_LOAD_LONG_TERM_KEYS,
57 MGMT_OP_DISCONNECT,
58 MGMT_OP_GET_CONNECTIONS,
59 MGMT_OP_PIN_CODE_REPLY,
60 MGMT_OP_PIN_CODE_NEG_REPLY,
61 MGMT_OP_SET_IO_CAPABILITY,
62 MGMT_OP_PAIR_DEVICE,
63 MGMT_OP_CANCEL_PAIR_DEVICE,
64 MGMT_OP_UNPAIR_DEVICE,
65 MGMT_OP_USER_CONFIRM_REPLY,
66 MGMT_OP_USER_CONFIRM_NEG_REPLY,
67 MGMT_OP_USER_PASSKEY_REPLY,
68 MGMT_OP_USER_PASSKEY_NEG_REPLY,
69 MGMT_OP_READ_LOCAL_OOB_DATA,
70 MGMT_OP_ADD_REMOTE_OOB_DATA,
71 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
72 MGMT_OP_START_DISCOVERY,
73 MGMT_OP_STOP_DISCOVERY,
74 MGMT_OP_CONFIRM_NAME,
75 MGMT_OP_BLOCK_DEVICE,
76 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070077 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030078 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030079 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070080 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070081 MGMT_OP_SET_SCAN_PARAMS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020082};
83
84static const u16 mgmt_events[] = {
85 MGMT_EV_CONTROLLER_ERROR,
86 MGMT_EV_INDEX_ADDED,
87 MGMT_EV_INDEX_REMOVED,
88 MGMT_EV_NEW_SETTINGS,
89 MGMT_EV_CLASS_OF_DEV_CHANGED,
90 MGMT_EV_LOCAL_NAME_CHANGED,
91 MGMT_EV_NEW_LINK_KEY,
92 MGMT_EV_NEW_LONG_TERM_KEY,
93 MGMT_EV_DEVICE_CONNECTED,
94 MGMT_EV_DEVICE_DISCONNECTED,
95 MGMT_EV_CONNECT_FAILED,
96 MGMT_EV_PIN_CODE_REQUEST,
97 MGMT_EV_USER_CONFIRM_REQUEST,
98 MGMT_EV_USER_PASSKEY_REQUEST,
99 MGMT_EV_AUTH_FAILED,
100 MGMT_EV_DEVICE_FOUND,
101 MGMT_EV_DISCOVERING,
102 MGMT_EV_DEVICE_BLOCKED,
103 MGMT_EV_DEVICE_UNBLOCKED,
104 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300105 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200106};
107
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800108#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200109
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200110#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
111 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
112
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200113struct pending_cmd {
114 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200115 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100117 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300119 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200120};
121
Johan Hedbergca69b792011-11-11 18:10:00 +0200122/* HCI to MGMT error code conversion table */
123static u8 mgmt_status_table[] = {
124 MGMT_STATUS_SUCCESS,
125 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
126 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
127 MGMT_STATUS_FAILED, /* Hardware Failure */
128 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
129 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
130 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
131 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
132 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
133 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
134 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
135 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
136 MGMT_STATUS_BUSY, /* Command Disallowed */
137 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
138 MGMT_STATUS_REJECTED, /* Rejected Security */
139 MGMT_STATUS_REJECTED, /* Rejected Personal */
140 MGMT_STATUS_TIMEOUT, /* Host Timeout */
141 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
142 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
143 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
144 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
145 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
146 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
147 MGMT_STATUS_BUSY, /* Repeated Attempts */
148 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
149 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
150 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
151 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
152 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
153 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
154 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
155 MGMT_STATUS_FAILED, /* Unspecified Error */
156 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
157 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
158 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
159 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
160 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
161 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
162 MGMT_STATUS_FAILED, /* Unit Link Key Used */
163 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
164 MGMT_STATUS_TIMEOUT, /* Instant Passed */
165 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
166 MGMT_STATUS_FAILED, /* Transaction Collision */
167 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
168 MGMT_STATUS_REJECTED, /* QoS Rejected */
169 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
170 MGMT_STATUS_REJECTED, /* Insufficient Security */
171 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
172 MGMT_STATUS_BUSY, /* Role Switch Pending */
173 MGMT_STATUS_FAILED, /* Slot Violation */
174 MGMT_STATUS_FAILED, /* Role Switch Failed */
175 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
176 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
177 MGMT_STATUS_BUSY, /* Host Busy Pairing */
178 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
179 MGMT_STATUS_BUSY, /* Controller Busy */
180 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
181 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
182 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
183 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
184 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
185};
186
187static u8 mgmt_status(u8 hci_status)
188{
189 if (hci_status < ARRAY_SIZE(mgmt_status_table))
190 return mgmt_status_table[hci_status];
191
192 return MGMT_STATUS_FAILED;
193}
194
Szymon Janc4e51eae2011-02-25 19:05:48 +0100195static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200196{
197 struct sk_buff *skb;
198 struct mgmt_hdr *hdr;
199 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300200 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200201
Szymon Janc34eb5252011-02-28 14:10:08 +0100202 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200203
Andre Guedes790eff42012-06-07 19:05:46 -0300204 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200205 if (!skb)
206 return -ENOMEM;
207
208 hdr = (void *) skb_put(skb, sizeof(*hdr));
209
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530210 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100211 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212 hdr->len = cpu_to_le16(sizeof(*ev));
213
214 ev = (void *) skb_put(skb, sizeof(*ev));
215 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200216 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200217
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300218 err = sock_queue_rcv_skb(sk, skb);
219 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200220 kfree_skb(skb);
221
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300222 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223}
224
Johan Hedbergaee9b212012-02-18 15:07:59 +0200225static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300226 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200227{
228 struct sk_buff *skb;
229 struct mgmt_hdr *hdr;
230 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300231 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200232
233 BT_DBG("sock %p", sk);
234
Andre Guedes790eff42012-06-07 19:05:46 -0300235 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200236 if (!skb)
237 return -ENOMEM;
238
239 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200240
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530241 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100242 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200243 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200244
Johan Hedberga38528f2011-01-22 06:46:43 +0200245 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200246 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200247 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100248
249 if (rp)
250 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300252 err = sock_queue_rcv_skb(sk, skb);
253 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200254 kfree_skb(skb);
255
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100256 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200257}
258
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300259static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
260 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200261{
262 struct mgmt_rp_read_version rp;
263
264 BT_DBG("sock %p", sk);
265
266 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200267 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200268
Johan Hedbergaee9b212012-02-18 15:07:59 +0200269 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300270 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200271}
272
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
274 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200275{
276 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200277 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
278 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200279 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200280 size_t rp_size;
281 int i, err;
282
283 BT_DBG("sock %p", sk);
284
285 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
286
287 rp = kmalloc(rp_size, GFP_KERNEL);
288 if (!rp)
289 return -ENOMEM;
290
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200291 rp->num_commands = __constant_cpu_to_le16(num_commands);
292 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200293
294 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
295 put_unaligned_le16(mgmt_commands[i], opcode);
296
297 for (i = 0; i < num_events; i++, opcode++)
298 put_unaligned_le16(mgmt_events[i], opcode);
299
Johan Hedbergaee9b212012-02-18 15:07:59 +0200300 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300301 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200302 kfree(rp);
303
304 return err;
305}
306
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300307static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
308 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200309{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200310 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200311 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200312 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300314 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315
316 BT_DBG("sock %p", sk);
317
318 read_lock(&hci_dev_list_lock);
319
320 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300321 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700322 if (d->dev_type == HCI_BREDR)
323 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324 }
325
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 rp_len = sizeof(*rp) + (2 * count);
327 rp = kmalloc(rp_len, GFP_ATOMIC);
328 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100329 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100331 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200332
Johan Hedberg476e44c2012-10-19 20:10:46 +0300333 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200334 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200335 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200336 continue;
337
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700338 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
339 continue;
340
Marcel Holtmann1514b892013-10-06 08:25:01 -0700341 if (d->dev_type == HCI_BREDR) {
342 rp->index[count++] = cpu_to_le16(d->id);
343 BT_DBG("Added hci%u", d->id);
344 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345 }
346
Johan Hedberg476e44c2012-10-19 20:10:46 +0300347 rp->num_controllers = cpu_to_le16(count);
348 rp_len = sizeof(*rp) + (2 * count);
349
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 read_unlock(&hci_dev_list_lock);
351
Johan Hedbergaee9b212012-02-18 15:07:59 +0200352 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300353 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
Johan Hedberga38528f2011-01-22 06:46:43 +0200355 kfree(rp);
356
357 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358}
359
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200360static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200361{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200366
Andre Guedesed3fa312012-07-24 15:03:46 -0300367 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300368 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500369 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
370 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300371 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 settings |= MGMT_SETTING_BREDR;
373 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700374
375 if (lmp_ssp_capable(hdev)) {
376 settings |= MGMT_SETTING_SSP;
377 settings |= MGMT_SETTING_HS;
378 }
Marcel Holtmann848566b2013-10-01 22:59:22 -0700379 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300381 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200382 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300383 settings |= MGMT_SETTING_ADVERTISING;
384 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200385
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200386 return settings;
387}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200388
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389static u32 get_current_settings(struct hci_dev *hdev)
390{
391 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200392
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200393 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100394 settings |= MGMT_SETTING_POWERED;
395
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200396 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200397 settings |= MGMT_SETTING_CONNECTABLE;
398
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500399 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
400 settings |= MGMT_SETTING_FAST_CONNECTABLE;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_DISCOVERABLE;
404
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200405 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_PAIRABLE;
407
Johan Hedberg56f87902013-10-02 13:43:13 +0300408 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_BREDR;
410
Johan Hedberg06199cf2012-02-22 16:37:11 +0200411 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200413
Johan Hedberg47990ea2012-02-22 11:58:37 +0200414 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200416
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200417 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200419
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200420 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
421 settings |= MGMT_SETTING_HS;
422
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200423 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300424 settings |= MGMT_SETTING_ADVERTISING;
425
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200426 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200427}
428
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300429#define PNP_INFO_SVCLASS_ID 0x1200
430
Johan Hedberg213202e2013-01-27 00:31:33 +0200431static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
432{
433 u8 *ptr = data, *uuids_start = NULL;
434 struct bt_uuid *uuid;
435
436 if (len < 4)
437 return ptr;
438
439 list_for_each_entry(uuid, &hdev->uuids, list) {
440 u16 uuid16;
441
442 if (uuid->size != 16)
443 continue;
444
445 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
446 if (uuid16 < 0x1100)
447 continue;
448
449 if (uuid16 == PNP_INFO_SVCLASS_ID)
450 continue;
451
452 if (!uuids_start) {
453 uuids_start = ptr;
454 uuids_start[0] = 1;
455 uuids_start[1] = EIR_UUID16_ALL;
456 ptr += 2;
457 }
458
459 /* Stop if not enough space to put next UUID */
460 if ((ptr - data) + sizeof(u16) > len) {
461 uuids_start[1] = EIR_UUID16_SOME;
462 break;
463 }
464
465 *ptr++ = (uuid16 & 0x00ff);
466 *ptr++ = (uuid16 & 0xff00) >> 8;
467 uuids_start[0] += sizeof(uuid16);
468 }
469
470 return ptr;
471}
472
Johan Hedbergcdf19632013-01-27 00:31:34 +0200473static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
474{
475 u8 *ptr = data, *uuids_start = NULL;
476 struct bt_uuid *uuid;
477
478 if (len < 6)
479 return ptr;
480
481 list_for_each_entry(uuid, &hdev->uuids, list) {
482 if (uuid->size != 32)
483 continue;
484
485 if (!uuids_start) {
486 uuids_start = ptr;
487 uuids_start[0] = 1;
488 uuids_start[1] = EIR_UUID32_ALL;
489 ptr += 2;
490 }
491
492 /* Stop if not enough space to put next UUID */
493 if ((ptr - data) + sizeof(u32) > len) {
494 uuids_start[1] = EIR_UUID32_SOME;
495 break;
496 }
497
498 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
499 ptr += sizeof(u32);
500 uuids_start[0] += sizeof(u32);
501 }
502
503 return ptr;
504}
505
Johan Hedbergc00d5752013-01-27 00:31:35 +0200506static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
507{
508 u8 *ptr = data, *uuids_start = NULL;
509 struct bt_uuid *uuid;
510
511 if (len < 18)
512 return ptr;
513
514 list_for_each_entry(uuid, &hdev->uuids, list) {
515 if (uuid->size != 128)
516 continue;
517
518 if (!uuids_start) {
519 uuids_start = ptr;
520 uuids_start[0] = 1;
521 uuids_start[1] = EIR_UUID128_ALL;
522 ptr += 2;
523 }
524
525 /* Stop if not enough space to put next UUID */
526 if ((ptr - data) + 16 > len) {
527 uuids_start[1] = EIR_UUID128_SOME;
528 break;
529 }
530
531 memcpy(ptr, uuid->uuid, 16);
532 ptr += 16;
533 uuids_start[0] += 16;
534 }
535
536 return ptr;
537}
538
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700539static u8 create_scan_rsp_data(struct hci_dev *hdev, u8 *ptr)
540{
Marcel Holtmann7a5f4992013-10-16 00:16:49 -0700541 u8 ad_len = 0;
542 size_t name_len;
543
544 name_len = strlen(hdev->dev_name);
545 if (name_len > 0) {
546 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
547
548 if (name_len > max_len) {
549 name_len = max_len;
550 ptr[1] = EIR_NAME_SHORT;
551 } else
552 ptr[1] = EIR_NAME_COMPLETE;
553
554 ptr[0] = name_len + 1;
555
556 memcpy(ptr + 2, hdev->dev_name, name_len);
557
558 ad_len += (name_len + 2);
559 ptr += (name_len + 2);
560 }
561
562 return ad_len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700563}
564
565static void update_scan_rsp_data(struct hci_request *req)
566{
567 struct hci_dev *hdev = req->hdev;
568 struct hci_cp_le_set_scan_rsp_data cp;
569 u8 len;
570
Johan Hedberg7751ef12013-10-19 23:38:15 +0300571 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700572 return;
573
574 memset(&cp, 0, sizeof(cp));
575
576 len = create_scan_rsp_data(hdev, cp.data);
577
Johan Hedbergeb438b52013-10-16 15:31:07 +0300578 if (hdev->scan_rsp_data_len == len &&
579 memcmp(cp.data, hdev->scan_rsp_data, len) == 0)
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700580 return;
581
Johan Hedbergeb438b52013-10-16 15:31:07 +0300582 memcpy(hdev->scan_rsp_data, cp.data, sizeof(cp.data));
583 hdev->scan_rsp_data_len = len;
Marcel Holtmannf14d8f62013-10-16 00:16:48 -0700584
585 cp.length = len;
586
587 hci_req_add(req, HCI_OP_LE_SET_SCAN_RSP_DATA, sizeof(cp), &cp);
588}
589
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700590static u8 create_adv_data(struct hci_dev *hdev, u8 *ptr)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700591{
592 u8 ad_len = 0, flags = 0;
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700593
594 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
595 flags |= LE_AD_GENERAL;
596
597 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
598 if (lmp_le_br_capable(hdev))
599 flags |= LE_AD_SIM_LE_BREDR_CTRL;
600 if (lmp_host_le_br_capable(hdev))
601 flags |= LE_AD_SIM_LE_BREDR_HOST;
602 } else {
603 flags |= LE_AD_NO_BREDR;
604 }
605
606 if (flags) {
607 BT_DBG("adv flags 0x%02x", flags);
608
609 ptr[0] = 2;
610 ptr[1] = EIR_FLAGS;
611 ptr[2] = flags;
612
613 ad_len += 3;
614 ptr += 3;
615 }
616
617 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
618 ptr[0] = 2;
619 ptr[1] = EIR_TX_POWER;
620 ptr[2] = (u8) hdev->adv_tx_power;
621
622 ad_len += 3;
623 ptr += 3;
624 }
625
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700626 return ad_len;
627}
628
Marcel Holtmann5947f4b2013-10-16 00:16:50 -0700629static void update_adv_data(struct hci_request *req)
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700630{
631 struct hci_dev *hdev = req->hdev;
632 struct hci_cp_le_set_adv_data cp;
633 u8 len;
634
Johan Hedberg10994ce2013-10-19 23:38:16 +0300635 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700636 return;
637
638 memset(&cp, 0, sizeof(cp));
639
Marcel Holtmann46cad2e2013-10-16 00:16:46 -0700640 len = create_adv_data(hdev, cp.data);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700641
642 if (hdev->adv_data_len == len &&
643 memcmp(cp.data, hdev->adv_data, len) == 0)
644 return;
645
646 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
647 hdev->adv_data_len = len;
648
649 cp.length = len;
650
651 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
652}
653
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300654static void create_eir(struct hci_dev *hdev, u8 *data)
655{
656 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300657 size_t name_len;
658
659 name_len = strlen(hdev->dev_name);
660
661 if (name_len > 0) {
662 /* EIR Data type */
663 if (name_len > 48) {
664 name_len = 48;
665 ptr[1] = EIR_NAME_SHORT;
666 } else
667 ptr[1] = EIR_NAME_COMPLETE;
668
669 /* EIR Data length */
670 ptr[0] = name_len + 1;
671
672 memcpy(ptr + 2, hdev->dev_name, name_len);
673
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300674 ptr += (name_len + 2);
675 }
676
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100677 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700678 ptr[0] = 2;
679 ptr[1] = EIR_TX_POWER;
680 ptr[2] = (u8) hdev->inq_tx_power;
681
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700682 ptr += 3;
683 }
684
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700685 if (hdev->devid_source > 0) {
686 ptr[0] = 9;
687 ptr[1] = EIR_DEVICE_ID;
688
689 put_unaligned_le16(hdev->devid_source, ptr + 2);
690 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
691 put_unaligned_le16(hdev->devid_product, ptr + 6);
692 put_unaligned_le16(hdev->devid_version, ptr + 8);
693
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700694 ptr += 10;
695 }
696
Johan Hedberg213202e2013-01-27 00:31:33 +0200697 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200698 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200699 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300700}
701
Johan Hedberg890ea892013-03-15 17:06:52 -0500702static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300703{
Johan Hedberg890ea892013-03-15 17:06:52 -0500704 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300705 struct hci_cp_write_eir cp;
706
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200707 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500708 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200709
Johan Hedberg976eb202012-10-24 21:12:01 +0300710 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500711 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300712
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200713 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500714 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300715
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200716 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500717 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300718
719 memset(&cp, 0, sizeof(cp));
720
721 create_eir(hdev, cp.data);
722
723 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500724 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300725
726 memcpy(hdev->eir, cp.data, sizeof(cp.data));
727
Johan Hedberg890ea892013-03-15 17:06:52 -0500728 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300729}
730
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200731static u8 get_service_classes(struct hci_dev *hdev)
732{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300733 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200734 u8 val = 0;
735
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300736 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200737 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200738
739 return val;
740}
741
Johan Hedberg890ea892013-03-15 17:06:52 -0500742static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200743{
Johan Hedberg890ea892013-03-15 17:06:52 -0500744 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200745 u8 cod[3];
746
747 BT_DBG("%s", hdev->name);
748
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200749 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500750 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200751
Johan Hedbergf87ea1d2013-10-19 23:38:17 +0300752 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
753 return;
754
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200755 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500756 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200757
758 cod[0] = hdev->minor_class;
759 cod[1] = hdev->major_class;
760 cod[2] = get_service_classes(hdev);
761
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700762 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
763 cod[1] |= 0x20;
764
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200765 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500766 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200767
Johan Hedberg890ea892013-03-15 17:06:52 -0500768 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200769}
770
Johan Hedberg7d785252011-12-15 00:47:39 +0200771static void service_cache_off(struct work_struct *work)
772{
773 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300774 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500775 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200776
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200777 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200778 return;
779
Johan Hedberg890ea892013-03-15 17:06:52 -0500780 hci_req_init(&req, hdev);
781
Johan Hedberg7d785252011-12-15 00:47:39 +0200782 hci_dev_lock(hdev);
783
Johan Hedberg890ea892013-03-15 17:06:52 -0500784 update_eir(&req);
785 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200786
787 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500788
789 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200790}
791
Johan Hedberg6a919082012-02-28 06:17:26 +0200792static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200793{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200794 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200795 return;
796
Johan Hedberg4f87da82012-03-02 19:55:56 +0200797 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200798
Johan Hedberg4f87da82012-03-02 19:55:56 +0200799 /* Non-mgmt controlled devices get this bit set
800 * implicitly so that pairing works for them, however
801 * for mgmt we require user-space to explicitly enable
802 * it
803 */
804 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200805}
806
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200807static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300808 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200809{
810 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200811
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200812 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200813
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300814 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200815
Johan Hedberg03811012010-12-08 00:21:06 +0200816 memset(&rp, 0, sizeof(rp));
817
Johan Hedberg03811012010-12-08 00:21:06 +0200818 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200819
820 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200821 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200822
823 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
824 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
825
826 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200827
828 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200829 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200830
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300831 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200832
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200833 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300834 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200835}
836
837static void mgmt_pending_free(struct pending_cmd *cmd)
838{
839 sock_put(cmd->sk);
840 kfree(cmd->param);
841 kfree(cmd);
842}
843
844static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300845 struct hci_dev *hdev, void *data,
846 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200847{
848 struct pending_cmd *cmd;
849
Andre Guedes12b94562012-06-07 19:05:45 -0300850 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200851 if (!cmd)
852 return NULL;
853
854 cmd->opcode = opcode;
855 cmd->index = hdev->id;
856
Andre Guedes12b94562012-06-07 19:05:45 -0300857 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200858 if (!cmd->param) {
859 kfree(cmd);
860 return NULL;
861 }
862
863 if (data)
864 memcpy(cmd->param, data, len);
865
866 cmd->sk = sk;
867 sock_hold(sk);
868
869 list_add(&cmd->list, &hdev->mgmt_pending);
870
871 return cmd;
872}
873
874static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300875 void (*cb)(struct pending_cmd *cmd,
876 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300877 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200878{
Andre Guedesa3d09352013-02-01 11:21:30 -0300879 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200880
Andre Guedesa3d09352013-02-01 11:21:30 -0300881 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200882 if (opcode > 0 && cmd->opcode != opcode)
883 continue;
884
885 cb(cmd, data);
886 }
887}
888
889static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
890{
891 struct pending_cmd *cmd;
892
893 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
894 if (cmd->opcode == opcode)
895 return cmd;
896 }
897
898 return NULL;
899}
900
901static void mgmt_pending_remove(struct pending_cmd *cmd)
902{
903 list_del(&cmd->list);
904 mgmt_pending_free(cmd);
905}
906
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200907static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200908{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200909 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200910
Johan Hedbergaee9b212012-02-18 15:07:59 +0200911 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300912 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200913}
914
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200915static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300916 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200917{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300918 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200919 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200920 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200921
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200922 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200923
Johan Hedberga7e80f22013-01-09 16:05:19 +0200924 if (cp->val != 0x00 && cp->val != 0x01)
925 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
926 MGMT_STATUS_INVALID_PARAMS);
927
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300928 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200929
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300930 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
931 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
932 MGMT_STATUS_BUSY);
933 goto failed;
934 }
935
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100936 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
937 cancel_delayed_work(&hdev->power_off);
938
939 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200940 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
941 data, len);
942 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100943 goto failed;
944 }
945 }
946
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200947 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200948 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200949 goto failed;
950 }
951
Johan Hedberg03811012010-12-08 00:21:06 +0200952 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
953 if (!cmd) {
954 err = -ENOMEM;
955 goto failed;
956 }
957
958 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200959 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200960 else
Johan Hedberg19202572013-01-14 22:33:51 +0200961 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200962
963 err = 0;
964
965failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300966 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200967 return err;
968}
969
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300970static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
971 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200972{
973 struct sk_buff *skb;
974 struct mgmt_hdr *hdr;
975
Andre Guedes790eff42012-06-07 19:05:46 -0300976 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200977 if (!skb)
978 return -ENOMEM;
979
980 hdr = (void *) skb_put(skb, sizeof(*hdr));
981 hdr->opcode = cpu_to_le16(event);
982 if (hdev)
983 hdr->index = cpu_to_le16(hdev->id);
984 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530985 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200986 hdr->len = cpu_to_le16(data_len);
987
988 if (data)
989 memcpy(skb_put(skb, data_len), data, data_len);
990
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100991 /* Time stamp */
992 __net_timestamp(skb);
993
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200994 hci_send_to_control(skb, skip_sk);
995 kfree_skb(skb);
996
997 return 0;
998}
999
1000static int new_settings(struct hci_dev *hdev, struct sock *skip)
1001{
1002 __le32 ev;
1003
1004 ev = cpu_to_le32(get_current_settings(hdev));
1005
1006 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
1007}
1008
Johan Hedbergbd99abd2013-09-25 13:26:07 +03001009struct cmd_lookup {
1010 struct sock *sk;
1011 struct hci_dev *hdev;
1012 u8 mgmt_status;
1013};
1014
1015static void settings_rsp(struct pending_cmd *cmd, void *data)
1016{
1017 struct cmd_lookup *match = data;
1018
1019 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
1020
1021 list_del(&cmd->list);
1022
1023 if (match->sk == NULL) {
1024 match->sk = cmd->sk;
1025 sock_hold(match->sk);
1026 }
1027
1028 mgmt_pending_free(cmd);
1029}
1030
1031static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
1032{
1033 u8 *status = data;
1034
1035 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1036 mgmt_pending_remove(cmd);
1037}
1038
Johan Hedberge6fe7982013-10-02 15:45:22 +03001039static u8 mgmt_bredr_support(struct hci_dev *hdev)
1040{
1041 if (!lmp_bredr_capable(hdev))
1042 return MGMT_STATUS_NOT_SUPPORTED;
1043 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1044 return MGMT_STATUS_REJECTED;
1045 else
1046 return MGMT_STATUS_SUCCESS;
1047}
1048
1049static u8 mgmt_le_support(struct hci_dev *hdev)
1050{
1051 if (!lmp_le_capable(hdev))
1052 return MGMT_STATUS_NOT_SUPPORTED;
1053 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1054 return MGMT_STATUS_REJECTED;
1055 else
1056 return MGMT_STATUS_SUCCESS;
1057}
1058
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001059static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1060{
1061 struct pending_cmd *cmd;
1062 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001063 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001064 bool changed;
1065
1066 BT_DBG("status 0x%02x", status);
1067
1068 hci_dev_lock(hdev);
1069
1070 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1071 if (!cmd)
1072 goto unlock;
1073
1074 if (status) {
1075 u8 mgmt_err = mgmt_status(status);
1076 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001077 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001078 goto remove_cmd;
1079 }
1080
1081 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001082 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001083 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1084 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001085
1086 if (hdev->discov_timeout > 0) {
1087 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1088 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1089 to);
1090 }
1091 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001092 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1093 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001094 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001095
1096 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1097
1098 if (changed)
1099 new_settings(hdev, cmd->sk);
1100
Marcel Holtmann970ba522013-10-15 06:33:57 -07001101 /* When the discoverable mode gets changed, make sure
1102 * that class of device has the limited discoverable
1103 * bit correctly set.
1104 */
1105 hci_req_init(&req, hdev);
1106 update_class(&req);
1107 hci_req_run(&req, NULL);
1108
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001109remove_cmd:
1110 mgmt_pending_remove(cmd);
1111
1112unlock:
1113 hci_dev_unlock(hdev);
1114}
1115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001116static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001117 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001118{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001119 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001120 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001121 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001122 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001123 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001124 int err;
1125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001126 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001127
Johan Hedberge6fe7982013-10-02 15:45:22 +03001128 status = mgmt_bredr_support(hdev);
1129 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001130 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001131 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001132
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001133 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001134 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1135 MGMT_STATUS_INVALID_PARAMS);
1136
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001137 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001138
1139 /* Disabling discoverable requires that no timeout is set,
1140 * and enabling limited discoverable requires a timeout.
1141 */
1142 if ((cp->val == 0x00 && timeout > 0) ||
1143 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001144 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001145 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001146
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001147 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001148
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001149 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001150 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001151 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001152 goto failed;
1153 }
1154
1155 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001156 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001157 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001158 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001159 goto failed;
1160 }
1161
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001162 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001163 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001164 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001165 goto failed;
1166 }
1167
1168 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001169 bool changed = false;
1170
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001171 /* Setting limited discoverable when powered off is
1172 * not a valid operation since it requires a timeout
1173 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1174 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001175 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1176 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1177 changed = true;
1178 }
1179
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001180 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001181 if (err < 0)
1182 goto failed;
1183
1184 if (changed)
1185 err = new_settings(hdev, sk);
1186
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001187 goto failed;
1188 }
1189
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001190 /* If the current mode is the same, then just update the timeout
1191 * value with the new value. And if only the timeout gets updated,
1192 * then no need for any HCI transactions.
1193 */
1194 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1195 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1196 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001197 cancel_delayed_work(&hdev->discov_off);
1198 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001199
Marcel Holtmann36261542013-10-15 08:28:51 -07001200 if (cp->val && hdev->discov_timeout > 0) {
1201 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001202 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001203 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001204 }
1205
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001206 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001207 goto failed;
1208 }
1209
1210 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1211 if (!cmd) {
1212 err = -ENOMEM;
1213 goto failed;
1214 }
1215
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001216 /* Cancel any potential discoverable timeout that might be
1217 * still active and store new timeout value. The arming of
1218 * the timeout happens in the complete handler.
1219 */
1220 cancel_delayed_work(&hdev->discov_off);
1221 hdev->discov_timeout = timeout;
1222
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001223 hci_req_init(&req, hdev);
1224
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001225 scan = SCAN_PAGE;
1226
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001227 if (cp->val) {
1228 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001229
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001230 if (cp->val == 0x02) {
1231 /* Limited discoverable mode */
1232 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1233
1234 hci_cp.num_iac = 2;
1235 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1236 hci_cp.iac_lap[1] = 0x8b;
1237 hci_cp.iac_lap[2] = 0x9e;
1238 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1239 hci_cp.iac_lap[4] = 0x8b;
1240 hci_cp.iac_lap[5] = 0x9e;
1241 } else {
1242 /* General discoverable mode */
1243 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1244
1245 hci_cp.num_iac = 1;
1246 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1247 hci_cp.iac_lap[1] = 0x8b;
1248 hci_cp.iac_lap[2] = 0x9e;
1249 }
1250
1251 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1252 (hci_cp.num_iac * 3) + 1, &hci_cp);
1253
1254 scan |= SCAN_INQUIRY;
1255 } else {
1256 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1257 }
1258
1259 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001260
1261 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001262 if (err < 0)
1263 mgmt_pending_remove(cmd);
1264
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001265failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001266 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001267 return err;
1268}
1269
Johan Hedberg406d7802013-03-15 17:07:09 -05001270static void write_fast_connectable(struct hci_request *req, bool enable)
1271{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001272 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001273 struct hci_cp_write_page_scan_activity acp;
1274 u8 type;
1275
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001276 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1277 return;
1278
Johan Hedberg406d7802013-03-15 17:07:09 -05001279 if (enable) {
1280 type = PAGE_SCAN_TYPE_INTERLACED;
1281
1282 /* 160 msec page scan interval */
1283 acp.interval = __constant_cpu_to_le16(0x0100);
1284 } else {
1285 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1286
1287 /* default 1.28 sec page scan */
1288 acp.interval = __constant_cpu_to_le16(0x0800);
1289 }
1290
1291 acp.window = __constant_cpu_to_le16(0x0012);
1292
Johan Hedbergbd98b992013-03-15 17:07:13 -05001293 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1294 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1295 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1296 sizeof(acp), &acp);
1297
1298 if (hdev->page_scan_type != type)
1299 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001300}
1301
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001302static u8 get_adv_type(struct hci_dev *hdev)
1303{
1304 struct pending_cmd *cmd;
1305 bool connectable;
1306
1307 /* If there's a pending mgmt command the flag will not yet have
1308 * it's final value, so check for this first.
1309 */
1310 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1311 if (cmd) {
1312 struct mgmt_mode *cp = cmd->param;
1313 connectable = !!cp->val;
1314 } else {
1315 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1316 }
1317
1318 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1319}
1320
Johan Hedberg95c66e72013-10-14 16:20:06 +03001321static void enable_advertising(struct hci_request *req)
1322{
1323 struct hci_dev *hdev = req->hdev;
1324 struct hci_cp_le_set_adv_param cp;
1325 u8 enable = 0x01;
1326
1327 memset(&cp, 0, sizeof(cp));
1328 cp.min_interval = __constant_cpu_to_le16(0x0800);
1329 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001330 cp.type = get_adv_type(hdev);
Marcel Holtmann79830f62013-10-18 16:38:09 -07001331 cp.own_address_type = hdev->own_addr_type;
Johan Hedberg95c66e72013-10-14 16:20:06 +03001332 cp.channel_map = 0x07;
1333
1334 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1335
1336 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1337}
1338
1339static void disable_advertising(struct hci_request *req)
1340{
1341 u8 enable = 0x00;
1342
1343 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1344}
1345
Johan Hedberg2b76f452013-03-15 17:07:04 -05001346static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1347{
1348 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001349 struct mgmt_mode *cp;
1350 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001351
1352 BT_DBG("status 0x%02x", status);
1353
1354 hci_dev_lock(hdev);
1355
1356 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1357 if (!cmd)
1358 goto unlock;
1359
Johan Hedberg37438c12013-10-14 16:20:05 +03001360 if (status) {
1361 u8 mgmt_err = mgmt_status(status);
1362 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1363 goto remove_cmd;
1364 }
1365
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001366 cp = cmd->param;
1367 if (cp->val)
1368 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1369 else
1370 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1371
Johan Hedberg2b76f452013-03-15 17:07:04 -05001372 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1373
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001374 if (changed)
1375 new_settings(hdev, cmd->sk);
1376
Johan Hedberg37438c12013-10-14 16:20:05 +03001377remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001378 mgmt_pending_remove(cmd);
1379
1380unlock:
1381 hci_dev_unlock(hdev);
1382}
1383
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001384static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001385 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001386{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001387 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001388 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001389 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001390 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001391 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001392
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001393 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001394
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001395 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1396 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001397 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001398 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001399
Johan Hedberga7e80f22013-01-09 16:05:19 +02001400 if (cp->val != 0x00 && cp->val != 0x01)
1401 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1402 MGMT_STATUS_INVALID_PARAMS);
1403
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001404 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001405
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001406 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001407 bool changed = false;
1408
1409 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1410 changed = true;
1411
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001412 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001413 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001414 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001415 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1416 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1417 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001418
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001419 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001420 if (err < 0)
1421 goto failed;
1422
1423 if (changed)
1424 err = new_settings(hdev, sk);
1425
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001426 goto failed;
1427 }
1428
1429 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001430 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001431 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001432 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001433 goto failed;
1434 }
1435
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001436 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1437 if (!cmd) {
1438 err = -ENOMEM;
1439 goto failed;
1440 }
1441
Johan Hedberg2b76f452013-03-15 17:07:04 -05001442 hci_req_init(&req, hdev);
1443
Johan Hedberg9b742462013-10-14 16:20:03 +03001444 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1445 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001446 if (cp->val) {
1447 scan = SCAN_PAGE;
1448 } else {
1449 scan = 0;
1450
1451 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001452 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001453 cancel_delayed_work(&hdev->discov_off);
1454 }
1455
1456 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1457 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001458
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001459 /* If we're going from non-connectable to connectable or
1460 * vice-versa when fast connectable is enabled ensure that fast
1461 * connectable gets disabled. write_fast_connectable won't do
1462 * anything if the page scan parameters are already what they
1463 * should be.
1464 */
1465 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001466 write_fast_connectable(&req, false);
1467
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001468 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1469 hci_conn_num(hdev, LE_LINK) == 0) {
1470 disable_advertising(&req);
1471 enable_advertising(&req);
1472 }
1473
Johan Hedberg2b76f452013-03-15 17:07:04 -05001474 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001475 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001476 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001477 if (err == -ENODATA)
1478 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1479 hdev);
1480 goto failed;
1481 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001482
1483failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001484 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001485 return err;
1486}
1487
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001488static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001489 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001490{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001491 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001492 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001493 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001494
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001495 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001496
Johan Hedberga7e80f22013-01-09 16:05:19 +02001497 if (cp->val != 0x00 && cp->val != 0x01)
1498 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1499 MGMT_STATUS_INVALID_PARAMS);
1500
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001501 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001502
1503 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001504 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001505 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001506 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001507
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001508 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001509 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001510 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001511
Marcel Holtmann55594352013-10-06 16:11:57 -07001512 if (changed)
1513 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001514
Marcel Holtmann55594352013-10-06 16:11:57 -07001515unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001516 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001517 return err;
1518}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001519
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001520static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1521 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001522{
1523 struct mgmt_mode *cp = data;
1524 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001525 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001526 int err;
1527
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001528 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001529
Johan Hedberge6fe7982013-10-02 15:45:22 +03001530 status = mgmt_bredr_support(hdev);
1531 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001532 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001533 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001534
Johan Hedberga7e80f22013-01-09 16:05:19 +02001535 if (cp->val != 0x00 && cp->val != 0x01)
1536 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1537 MGMT_STATUS_INVALID_PARAMS);
1538
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001539 hci_dev_lock(hdev);
1540
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001541 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001542 bool changed = false;
1543
1544 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001545 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001546 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1547 changed = true;
1548 }
1549
1550 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1551 if (err < 0)
1552 goto failed;
1553
1554 if (changed)
1555 err = new_settings(hdev, sk);
1556
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001557 goto failed;
1558 }
1559
1560 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001561 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001562 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001563 goto failed;
1564 }
1565
1566 val = !!cp->val;
1567
1568 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1569 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1570 goto failed;
1571 }
1572
1573 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1574 if (!cmd) {
1575 err = -ENOMEM;
1576 goto failed;
1577 }
1578
1579 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1580 if (err < 0) {
1581 mgmt_pending_remove(cmd);
1582 goto failed;
1583 }
1584
1585failed:
1586 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001587 return err;
1588}
1589
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001590static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001591{
1592 struct mgmt_mode *cp = data;
1593 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001594 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001595 int err;
1596
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001597 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001598
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001599 status = mgmt_bredr_support(hdev);
1600 if (status)
1601 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1602
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001603 if (!lmp_ssp_capable(hdev))
1604 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1605 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001606
Johan Hedberga7e80f22013-01-09 16:05:19 +02001607 if (cp->val != 0x00 && cp->val != 0x01)
1608 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1609 MGMT_STATUS_INVALID_PARAMS);
1610
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001611 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001612
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001613 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001614 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001615
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001616 if (cp->val) {
1617 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1618 &hdev->dev_flags);
1619 } else {
1620 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1621 &hdev->dev_flags);
1622 if (!changed)
1623 changed = test_and_clear_bit(HCI_HS_ENABLED,
1624 &hdev->dev_flags);
1625 else
1626 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001627 }
1628
1629 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1630 if (err < 0)
1631 goto failed;
1632
1633 if (changed)
1634 err = new_settings(hdev, sk);
1635
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001636 goto failed;
1637 }
1638
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001639 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1640 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001641 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1642 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001643 goto failed;
1644 }
1645
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001646 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001647 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1648 goto failed;
1649 }
1650
1651 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1652 if (!cmd) {
1653 err = -ENOMEM;
1654 goto failed;
1655 }
1656
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001657 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001658 if (err < 0) {
1659 mgmt_pending_remove(cmd);
1660 goto failed;
1661 }
1662
1663failed:
1664 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001665 return err;
1666}
1667
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001668static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001669{
1670 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001671 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001672 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001673 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001674
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001675 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001676
Johan Hedberge6fe7982013-10-02 15:45:22 +03001677 status = mgmt_bredr_support(hdev);
1678 if (status)
1679 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001680
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001681 if (!lmp_ssp_capable(hdev))
1682 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1683 MGMT_STATUS_NOT_SUPPORTED);
1684
1685 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1686 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1687 MGMT_STATUS_REJECTED);
1688
Johan Hedberga7e80f22013-01-09 16:05:19 +02001689 if (cp->val != 0x00 && cp->val != 0x01)
1690 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1691 MGMT_STATUS_INVALID_PARAMS);
1692
Marcel Holtmannee392692013-10-01 22:59:23 -07001693 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001694
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001695 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001696 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001697 } else {
1698 if (hdev_is_powered(hdev)) {
1699 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1700 MGMT_STATUS_REJECTED);
1701 goto unlock;
1702 }
1703
Marcel Holtmannee392692013-10-01 22:59:23 -07001704 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001705 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001706
1707 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1708 if (err < 0)
1709 goto unlock;
1710
1711 if (changed)
1712 err = new_settings(hdev, sk);
1713
1714unlock:
1715 hci_dev_unlock(hdev);
1716 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001717}
1718
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001719static void le_enable_complete(struct hci_dev *hdev, u8 status)
1720{
1721 struct cmd_lookup match = { NULL, hdev };
1722
1723 if (status) {
1724 u8 mgmt_err = mgmt_status(status);
1725
1726 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1727 &mgmt_err);
1728 return;
1729 }
1730
1731 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1732
1733 new_settings(hdev, match.sk);
1734
1735 if (match.sk)
1736 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001737
1738 /* Make sure the controller has a good default for
1739 * advertising data. Restrict the update to when LE
1740 * has actually been enabled. During power on, the
1741 * update in powered_update_hci will take care of it.
1742 */
1743 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1744 struct hci_request req;
1745
1746 hci_dev_lock(hdev);
1747
1748 hci_req_init(&req, hdev);
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07001749 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07001750 update_scan_rsp_data(&req);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001751 hci_req_run(&req, NULL);
1752
1753 hci_dev_unlock(hdev);
1754 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001755}
1756
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001757static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001758{
1759 struct mgmt_mode *cp = data;
1760 struct hci_cp_write_le_host_supported hci_cp;
1761 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001762 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001763 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001764 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001765
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001766 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001767
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001768 if (!lmp_le_capable(hdev))
1769 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1770 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001771
Johan Hedberga7e80f22013-01-09 16:05:19 +02001772 if (cp->val != 0x00 && cp->val != 0x01)
1773 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1774 MGMT_STATUS_INVALID_PARAMS);
1775
Johan Hedbergc73eee92013-04-19 18:35:21 +03001776 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001777 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001778 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1779 MGMT_STATUS_REJECTED);
1780
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001781 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001782
1783 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001784 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001785
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001786 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001787 bool changed = false;
1788
1789 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1790 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1791 changed = true;
1792 }
1793
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001794 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1795 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001796 changed = true;
1797 }
1798
Johan Hedberg06199cf2012-02-22 16:37:11 +02001799 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1800 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001801 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001802
1803 if (changed)
1804 err = new_settings(hdev, sk);
1805
Johan Hedberg1de028c2012-02-29 19:55:35 -08001806 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001807 }
1808
Johan Hedberg4375f102013-09-25 13:26:10 +03001809 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1810 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001811 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001812 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001813 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001814 }
1815
1816 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1817 if (!cmd) {
1818 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001819 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001820 }
1821
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001822 hci_req_init(&req, hdev);
1823
Johan Hedberg06199cf2012-02-22 16:37:11 +02001824 memset(&hci_cp, 0, sizeof(hci_cp));
1825
1826 if (val) {
1827 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001828 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001829 } else {
1830 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1831 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001832 }
1833
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001834 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1835 &hci_cp);
1836
1837 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301838 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001839 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001840
Johan Hedberg1de028c2012-02-29 19:55:35 -08001841unlock:
1842 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001843 return err;
1844}
1845
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001846/* This is a helper function to test for pending mgmt commands that can
1847 * cause CoD or EIR HCI commands. We can only allow one such pending
1848 * mgmt command at a time since otherwise we cannot easily track what
1849 * the current values are, will be, and based on that calculate if a new
1850 * HCI command needs to be sent and if yes with what value.
1851 */
1852static bool pending_eir_or_class(struct hci_dev *hdev)
1853{
1854 struct pending_cmd *cmd;
1855
1856 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1857 switch (cmd->opcode) {
1858 case MGMT_OP_ADD_UUID:
1859 case MGMT_OP_REMOVE_UUID:
1860 case MGMT_OP_SET_DEV_CLASS:
1861 case MGMT_OP_SET_POWERED:
1862 return true;
1863 }
1864 }
1865
1866 return false;
1867}
1868
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001869static const u8 bluetooth_base_uuid[] = {
1870 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1871 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1872};
1873
1874static u8 get_uuid_size(const u8 *uuid)
1875{
1876 u32 val;
1877
1878 if (memcmp(uuid, bluetooth_base_uuid, 12))
1879 return 128;
1880
1881 val = get_unaligned_le32(&uuid[12]);
1882 if (val > 0xffff)
1883 return 32;
1884
1885 return 16;
1886}
1887
Johan Hedberg92da6092013-03-15 17:06:55 -05001888static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1889{
1890 struct pending_cmd *cmd;
1891
1892 hci_dev_lock(hdev);
1893
1894 cmd = mgmt_pending_find(mgmt_op, hdev);
1895 if (!cmd)
1896 goto unlock;
1897
1898 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1899 hdev->dev_class, 3);
1900
1901 mgmt_pending_remove(cmd);
1902
1903unlock:
1904 hci_dev_unlock(hdev);
1905}
1906
1907static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1908{
1909 BT_DBG("status 0x%02x", status);
1910
1911 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1912}
1913
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001914static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001915{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001916 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001917 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001918 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001919 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001920 int err;
1921
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001922 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001923
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001924 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001925
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001926 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001927 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001928 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001929 goto failed;
1930 }
1931
Andre Guedes92c4c202012-06-07 19:05:44 -03001932 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001933 if (!uuid) {
1934 err = -ENOMEM;
1935 goto failed;
1936 }
1937
1938 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001939 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001940 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001941
Johan Hedbergde66aa62013-01-27 00:31:27 +02001942 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001943
Johan Hedberg890ea892013-03-15 17:06:52 -05001944 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001945
Johan Hedberg890ea892013-03-15 17:06:52 -05001946 update_class(&req);
1947 update_eir(&req);
1948
Johan Hedberg92da6092013-03-15 17:06:55 -05001949 err = hci_req_run(&req, add_uuid_complete);
1950 if (err < 0) {
1951 if (err != -ENODATA)
1952 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001953
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001954 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001955 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001956 goto failed;
1957 }
1958
1959 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001960 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001961 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001962 goto failed;
1963 }
1964
1965 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001966
1967failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001968 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001969 return err;
1970}
1971
Johan Hedberg24b78d02012-02-23 23:24:30 +02001972static bool enable_service_cache(struct hci_dev *hdev)
1973{
1974 if (!hdev_is_powered(hdev))
1975 return false;
1976
1977 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001978 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1979 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001980 return true;
1981 }
1982
1983 return false;
1984}
1985
Johan Hedberg92da6092013-03-15 17:06:55 -05001986static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1987{
1988 BT_DBG("status 0x%02x", status);
1989
1990 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1991}
1992
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001993static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001994 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001995{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001996 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001997 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001998 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001999 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg890ea892013-03-15 17:06:52 -05002000 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002001 int err, found;
2002
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002003 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002004
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002005 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002006
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002007 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002008 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002009 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002010 goto unlock;
2011 }
2012
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002013 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
2014 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002015
Johan Hedberg24b78d02012-02-23 23:24:30 +02002016 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002017 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002018 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02002019 goto unlock;
2020 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02002021
Johan Hedberg9246a862012-02-23 21:33:16 +02002022 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002023 }
2024
2025 found = 0;
2026
Johan Hedberg056341c2013-01-27 00:31:30 +02002027 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002028 if (memcmp(match->uuid, cp->uuid, 16) != 0)
2029 continue;
2030
2031 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01002032 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002033 found++;
2034 }
2035
2036 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002037 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002038 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002039 goto unlock;
2040 }
2041
Johan Hedberg9246a862012-02-23 21:33:16 +02002042update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002043 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002044
Johan Hedberg890ea892013-03-15 17:06:52 -05002045 update_class(&req);
2046 update_eir(&req);
2047
Johan Hedberg92da6092013-03-15 17:06:55 -05002048 err = hci_req_run(&req, remove_uuid_complete);
2049 if (err < 0) {
2050 if (err != -ENODATA)
2051 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002052
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002053 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002054 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002055 goto unlock;
2056 }
2057
2058 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002059 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002060 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002061 goto unlock;
2062 }
2063
2064 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002065
2066unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002067 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002068 return err;
2069}
2070
Johan Hedberg92da6092013-03-15 17:06:55 -05002071static void set_class_complete(struct hci_dev *hdev, u8 status)
2072{
2073 BT_DBG("status 0x%02x", status);
2074
2075 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2076}
2077
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002078static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002079 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002080{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002081 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002082 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002083 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002084 int err;
2085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002086 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002087
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002088 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002089 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2090 MGMT_STATUS_NOT_SUPPORTED);
2091
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002092 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002093
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002094 if (pending_eir_or_class(hdev)) {
2095 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2096 MGMT_STATUS_BUSY);
2097 goto unlock;
2098 }
2099
2100 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2101 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2102 MGMT_STATUS_INVALID_PARAMS);
2103 goto unlock;
2104 }
2105
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002106 hdev->major_class = cp->major;
2107 hdev->minor_class = cp->minor;
2108
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002109 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002110 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002111 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002112 goto unlock;
2113 }
2114
Johan Hedberg890ea892013-03-15 17:06:52 -05002115 hci_req_init(&req, hdev);
2116
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002117 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002118 hci_dev_unlock(hdev);
2119 cancel_delayed_work_sync(&hdev->service_cache);
2120 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002121 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002122 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002123
Johan Hedberg890ea892013-03-15 17:06:52 -05002124 update_class(&req);
2125
Johan Hedberg92da6092013-03-15 17:06:55 -05002126 err = hci_req_run(&req, set_class_complete);
2127 if (err < 0) {
2128 if (err != -ENODATA)
2129 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002130
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002131 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002132 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002133 goto unlock;
2134 }
2135
2136 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002137 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002138 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002139 goto unlock;
2140 }
2141
2142 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002143
Johan Hedbergb5235a62012-02-21 14:32:24 +02002144unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002145 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002146 return err;
2147}
2148
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002149static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002150 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002151{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002152 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002153 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002154 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002155
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002156 BT_DBG("request for %s", hdev->name);
2157
2158 if (!lmp_bredr_capable(hdev))
2159 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2160 MGMT_STATUS_NOT_SUPPORTED);
2161
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002162 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002163
Johan Hedberg86742e12011-11-07 23:13:38 +02002164 expected_len = sizeof(*cp) + key_count *
2165 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002166 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002167 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002168 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002169 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002170 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002171 }
2172
Johan Hedberg4ae14302013-01-20 14:27:13 +02002173 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2174 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2175 MGMT_STATUS_INVALID_PARAMS);
2176
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002177 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002178 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002179
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002180 for (i = 0; i < key_count; i++) {
2181 struct mgmt_link_key_info *key = &cp->keys[i];
2182
2183 if (key->addr.type != BDADDR_BREDR)
2184 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2185 MGMT_STATUS_INVALID_PARAMS);
2186 }
2187
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002188 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002189
2190 hci_link_keys_clear(hdev);
2191
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002192 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002193 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002194 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002195 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002196
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002197 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002198 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002199
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002200 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002201 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002202 }
2203
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002204 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002205
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002206 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002207
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002208 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002209}
2210
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002211static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002212 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002213{
2214 struct mgmt_ev_device_unpaired ev;
2215
2216 bacpy(&ev.addr.bdaddr, bdaddr);
2217 ev.addr.type = addr_type;
2218
2219 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002220 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002221}
2222
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002223static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002224 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002225{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002226 struct mgmt_cp_unpair_device *cp = data;
2227 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002228 struct hci_cp_disconnect dc;
2229 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002230 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002231 int err;
2232
Johan Hedberga8a1d192011-11-10 15:54:38 +02002233 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002234 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2235 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002236
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002237 if (!bdaddr_type_is_valid(cp->addr.type))
2238 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2239 MGMT_STATUS_INVALID_PARAMS,
2240 &rp, sizeof(rp));
2241
Johan Hedberg118da702013-01-20 14:27:20 +02002242 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2243 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2244 MGMT_STATUS_INVALID_PARAMS,
2245 &rp, sizeof(rp));
2246
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002247 hci_dev_lock(hdev);
2248
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002249 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002250 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002251 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002252 goto unlock;
2253 }
2254
Andre Guedes591f47f2012-04-24 21:02:49 -03002255 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002256 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2257 else
2258 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002259
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002260 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002261 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002262 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002263 goto unlock;
2264 }
2265
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002266 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002267 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002268 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002269 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002270 else
2271 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002272 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002273 } else {
2274 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002275 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002276
Johan Hedberga8a1d192011-11-10 15:54:38 +02002277 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002278 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002279 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002280 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002281 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002282 }
2283
Johan Hedberg124f6e32012-02-09 13:50:12 +02002284 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002285 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002286 if (!cmd) {
2287 err = -ENOMEM;
2288 goto unlock;
2289 }
2290
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002291 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002292 dc.reason = 0x13; /* Remote User Terminated Connection */
2293 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2294 if (err < 0)
2295 mgmt_pending_remove(cmd);
2296
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002297unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002298 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002299 return err;
2300}
2301
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002302static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002303 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002304{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002305 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002306 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002307 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002308 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002309 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002310 int err;
2311
2312 BT_DBG("");
2313
Johan Hedberg06a63b12013-01-20 14:27:21 +02002314 memset(&rp, 0, sizeof(rp));
2315 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2316 rp.addr.type = cp->addr.type;
2317
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002318 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002319 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2320 MGMT_STATUS_INVALID_PARAMS,
2321 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002322
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002323 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002324
2325 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002326 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2327 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002328 goto failed;
2329 }
2330
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002331 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002332 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2333 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002334 goto failed;
2335 }
2336
Andre Guedes591f47f2012-04-24 21:02:49 -03002337 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002338 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2339 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002340 else
2341 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002342
Vishal Agarwalf9607272012-06-13 05:32:43 +05302343 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002344 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2345 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002346 goto failed;
2347 }
2348
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002349 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002350 if (!cmd) {
2351 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002352 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002353 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002354
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002355 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002356 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002357
2358 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2359 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002360 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002361
2362failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002363 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002364 return err;
2365}
2366
Andre Guedes57c14772012-04-24 21:02:50 -03002367static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002368{
2369 switch (link_type) {
2370 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002371 switch (addr_type) {
2372 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002373 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002374
Johan Hedberg48264f02011-11-09 13:58:58 +02002375 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002376 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002377 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002378 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002379
Johan Hedberg4c659c32011-11-07 23:13:39 +02002380 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002381 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002382 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002383 }
2384}
2385
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002386static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2387 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002388{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002389 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002390 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002391 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002392 int err;
2393 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002394
2395 BT_DBG("");
2396
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002397 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002398
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002399 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002400 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002401 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002402 goto unlock;
2403 }
2404
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002405 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002406 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2407 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002408 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002409 }
2410
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002411 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002412 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002413 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002414 err = -ENOMEM;
2415 goto unlock;
2416 }
2417
Johan Hedberg2784eb42011-01-21 13:56:35 +02002418 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002419 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002420 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2421 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002422 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002423 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002424 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002425 continue;
2426 i++;
2427 }
2428
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002429 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002430
Johan Hedberg4c659c32011-11-07 23:13:39 +02002431 /* Recalculate length in case of filtered SCO connections, etc */
2432 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002433
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002434 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002435 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002436
Johan Hedberga38528f2011-01-22 06:46:43 +02002437 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002438
2439unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002440 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002441 return err;
2442}
2443
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002444static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002445 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002446{
2447 struct pending_cmd *cmd;
2448 int err;
2449
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002450 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002451 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002452 if (!cmd)
2453 return -ENOMEM;
2454
Johan Hedbergd8457692012-02-17 14:24:57 +02002455 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002456 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002457 if (err < 0)
2458 mgmt_pending_remove(cmd);
2459
2460 return err;
2461}
2462
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002463static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002464 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002465{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002466 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002467 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002468 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002469 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002470 int err;
2471
2472 BT_DBG("");
2473
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002474 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002475
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002476 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002477 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002478 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002479 goto failed;
2480 }
2481
Johan Hedbergd8457692012-02-17 14:24:57 +02002482 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002483 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002484 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002485 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002486 goto failed;
2487 }
2488
2489 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002490 struct mgmt_cp_pin_code_neg_reply ncp;
2491
2492 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002493
2494 BT_ERR("PIN code is not 16 bytes long");
2495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002496 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002497 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002498 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002499 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002500
2501 goto failed;
2502 }
2503
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002504 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002505 if (!cmd) {
2506 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002507 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002508 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002509
Johan Hedbergd8457692012-02-17 14:24:57 +02002510 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002511 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002512 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002513
2514 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2515 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002516 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002517
2518failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002519 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002520 return err;
2521}
2522
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002523static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2524 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002525{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002526 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002527
2528 BT_DBG("");
2529
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002530 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002531
2532 hdev->io_capability = cp->io_capability;
2533
2534 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002535 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002536
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002537 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002538
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002539 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2540 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002541}
2542
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002543static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002544{
2545 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002546 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002547
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002548 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002549 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2550 continue;
2551
Johan Hedberge9a416b2011-02-19 12:05:56 -03002552 if (cmd->user_data != conn)
2553 continue;
2554
2555 return cmd;
2556 }
2557
2558 return NULL;
2559}
2560
2561static void pairing_complete(struct pending_cmd *cmd, u8 status)
2562{
2563 struct mgmt_rp_pair_device rp;
2564 struct hci_conn *conn = cmd->user_data;
2565
Johan Hedbergba4e5642011-11-11 00:07:34 +02002566 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002567 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002568
Johan Hedbergaee9b212012-02-18 15:07:59 +02002569 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002570 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002571
2572 /* So we don't get further callbacks for this connection */
2573 conn->connect_cfm_cb = NULL;
2574 conn->security_cfm_cb = NULL;
2575 conn->disconn_cfm_cb = NULL;
2576
David Herrmann76a68ba2013-04-06 20:28:37 +02002577 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002578
Johan Hedberga664b5b2011-02-19 12:06:02 -03002579 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002580}
2581
2582static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2583{
2584 struct pending_cmd *cmd;
2585
2586 BT_DBG("status %u", status);
2587
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002588 cmd = find_pairing(conn);
2589 if (!cmd)
2590 BT_DBG("Unable to find a pending command");
2591 else
Johan Hedberge2113262012-02-18 15:20:03 +02002592 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002593}
2594
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302595static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2596{
2597 struct pending_cmd *cmd;
2598
2599 BT_DBG("status %u", status);
2600
2601 if (!status)
2602 return;
2603
2604 cmd = find_pairing(conn);
2605 if (!cmd)
2606 BT_DBG("Unable to find a pending command");
2607 else
2608 pairing_complete(cmd, mgmt_status(status));
2609}
2610
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002611static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002612 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002613{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002614 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002615 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002616 struct pending_cmd *cmd;
2617 u8 sec_level, auth_type;
2618 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002619 int err;
2620
2621 BT_DBG("");
2622
Szymon Jancf950a30e2013-01-18 12:48:07 +01002623 memset(&rp, 0, sizeof(rp));
2624 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2625 rp.addr.type = cp->addr.type;
2626
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002627 if (!bdaddr_type_is_valid(cp->addr.type))
2628 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2629 MGMT_STATUS_INVALID_PARAMS,
2630 &rp, sizeof(rp));
2631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002632 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002633
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002634 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002635 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2636 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002637 goto unlock;
2638 }
2639
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002640 sec_level = BT_SECURITY_MEDIUM;
2641 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002642 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002643 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002644 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002645
Andre Guedes591f47f2012-04-24 21:02:49 -03002646 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002647 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2648 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002649 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002650 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2651 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002652
Ville Tervo30e76272011-02-22 16:10:53 -03002653 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002654 int status;
2655
2656 if (PTR_ERR(conn) == -EBUSY)
2657 status = MGMT_STATUS_BUSY;
2658 else
2659 status = MGMT_STATUS_CONNECT_FAILED;
2660
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002661 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002662 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002663 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002664 goto unlock;
2665 }
2666
2667 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002668 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002669 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002670 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002671 goto unlock;
2672 }
2673
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002674 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002675 if (!cmd) {
2676 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002677 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002678 goto unlock;
2679 }
2680
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002681 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002682 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002683 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302684 else
2685 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002686
Johan Hedberge9a416b2011-02-19 12:05:56 -03002687 conn->security_cfm_cb = pairing_complete_cb;
2688 conn->disconn_cfm_cb = pairing_complete_cb;
2689 conn->io_capability = cp->io_cap;
2690 cmd->user_data = conn;
2691
2692 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002693 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002694 pairing_complete(cmd, 0);
2695
2696 err = 0;
2697
2698unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002699 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002700 return err;
2701}
2702
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002703static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2704 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002705{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002706 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002707 struct pending_cmd *cmd;
2708 struct hci_conn *conn;
2709 int err;
2710
2711 BT_DBG("");
2712
Johan Hedberg28424702012-02-02 04:02:29 +02002713 hci_dev_lock(hdev);
2714
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002715 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002716 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002717 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002718 goto unlock;
2719 }
2720
Johan Hedberg28424702012-02-02 04:02:29 +02002721 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2722 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002723 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002724 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002725 goto unlock;
2726 }
2727
2728 conn = cmd->user_data;
2729
2730 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002731 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002732 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002733 goto unlock;
2734 }
2735
2736 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002738 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002739 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002740unlock:
2741 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002742 return err;
2743}
2744
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002745static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002746 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002747 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002748{
Johan Hedberga5c29682011-02-19 12:05:57 -03002749 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002750 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002751 int err;
2752
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002753 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002754
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002755 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002756 err = cmd_complete(sk, hdev->id, mgmt_op,
2757 MGMT_STATUS_NOT_POWERED, addr,
2758 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002759 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002760 }
2761
Johan Hedberg1707c602013-03-15 17:07:15 -05002762 if (addr->type == BDADDR_BREDR)
2763 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002764 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002765 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002766
Johan Hedberg272d90d2012-02-09 15:26:12 +02002767 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002768 err = cmd_complete(sk, hdev->id, mgmt_op,
2769 MGMT_STATUS_NOT_CONNECTED, addr,
2770 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002771 goto done;
2772 }
2773
Johan Hedberg1707c602013-03-15 17:07:15 -05002774 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002775 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002776 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002777
Brian Gix5fe57d92011-12-21 16:12:13 -08002778 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002779 err = cmd_complete(sk, hdev->id, mgmt_op,
2780 MGMT_STATUS_SUCCESS, addr,
2781 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002782 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002783 err = cmd_complete(sk, hdev->id, mgmt_op,
2784 MGMT_STATUS_FAILED, addr,
2785 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002786
Brian Gix47c15e22011-11-16 13:53:14 -08002787 goto done;
2788 }
2789
Johan Hedberg1707c602013-03-15 17:07:15 -05002790 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002791 if (!cmd) {
2792 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002793 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002794 }
2795
Brian Gix0df4c182011-11-16 13:53:13 -08002796 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002797 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2798 struct hci_cp_user_passkey_reply cp;
2799
Johan Hedberg1707c602013-03-15 17:07:15 -05002800 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002801 cp.passkey = passkey;
2802 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2803 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002804 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2805 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002806
Johan Hedberga664b5b2011-02-19 12:06:02 -03002807 if (err < 0)
2808 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002809
Brian Gix0df4c182011-11-16 13:53:13 -08002810done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002811 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002812 return err;
2813}
2814
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302815static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2816 void *data, u16 len)
2817{
2818 struct mgmt_cp_pin_code_neg_reply *cp = data;
2819
2820 BT_DBG("");
2821
Johan Hedberg1707c602013-03-15 17:07:15 -05002822 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302823 MGMT_OP_PIN_CODE_NEG_REPLY,
2824 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2825}
2826
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002827static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2828 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002829{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002830 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002831
2832 BT_DBG("");
2833
2834 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002835 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002836 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002837
Johan Hedberg1707c602013-03-15 17:07:15 -05002838 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002839 MGMT_OP_USER_CONFIRM_REPLY,
2840 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002841}
2842
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002843static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002844 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002845{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002846 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002847
2848 BT_DBG("");
2849
Johan Hedberg1707c602013-03-15 17:07:15 -05002850 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002851 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2852 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002853}
2854
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002855static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2856 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002857{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002858 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002859
2860 BT_DBG("");
2861
Johan Hedberg1707c602013-03-15 17:07:15 -05002862 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002863 MGMT_OP_USER_PASSKEY_REPLY,
2864 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002865}
2866
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002867static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002868 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002869{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002870 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002871
2872 BT_DBG("");
2873
Johan Hedberg1707c602013-03-15 17:07:15 -05002874 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002875 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2876 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002877}
2878
Johan Hedberg13928972013-03-15 17:07:00 -05002879static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002880{
Johan Hedberg13928972013-03-15 17:07:00 -05002881 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002882 struct hci_cp_write_local_name cp;
2883
Johan Hedberg13928972013-03-15 17:07:00 -05002884 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002885
Johan Hedberg890ea892013-03-15 17:06:52 -05002886 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002887}
2888
Johan Hedberg13928972013-03-15 17:07:00 -05002889static void set_name_complete(struct hci_dev *hdev, u8 status)
2890{
2891 struct mgmt_cp_set_local_name *cp;
2892 struct pending_cmd *cmd;
2893
2894 BT_DBG("status 0x%02x", status);
2895
2896 hci_dev_lock(hdev);
2897
2898 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2899 if (!cmd)
2900 goto unlock;
2901
2902 cp = cmd->param;
2903
2904 if (status)
2905 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2906 mgmt_status(status));
2907 else
2908 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2909 cp, sizeof(*cp));
2910
2911 mgmt_pending_remove(cmd);
2912
2913unlock:
2914 hci_dev_unlock(hdev);
2915}
2916
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002917static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002918 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002919{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002920 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002921 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002922 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002923 int err;
2924
2925 BT_DBG("");
2926
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002927 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002928
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002929 /* If the old values are the same as the new ones just return a
2930 * direct command complete event.
2931 */
2932 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2933 !memcmp(hdev->short_name, cp->short_name,
2934 sizeof(hdev->short_name))) {
2935 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2936 data, len);
2937 goto failed;
2938 }
2939
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002940 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002941
Johan Hedbergb5235a62012-02-21 14:32:24 +02002942 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002943 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002944
2945 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002946 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002947 if (err < 0)
2948 goto failed;
2949
2950 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002951 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002952
Johan Hedbergb5235a62012-02-21 14:32:24 +02002953 goto failed;
2954 }
2955
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002956 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002957 if (!cmd) {
2958 err = -ENOMEM;
2959 goto failed;
2960 }
2961
Johan Hedberg13928972013-03-15 17:07:00 -05002962 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2963
Johan Hedberg890ea892013-03-15 17:06:52 -05002964 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002965
2966 if (lmp_bredr_capable(hdev)) {
2967 update_name(&req);
2968 update_eir(&req);
2969 }
2970
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07002971 /* The name is stored in the scan response data and so
2972 * no need to udpate the advertising data here.
2973 */
Johan Hedberg3f985052013-03-15 17:07:02 -05002974 if (lmp_le_capable(hdev))
Marcel Holtmann7a5f4992013-10-16 00:16:49 -07002975 update_scan_rsp_data(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05002976
Johan Hedberg13928972013-03-15 17:07:00 -05002977 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002978 if (err < 0)
2979 mgmt_pending_remove(cmd);
2980
2981failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002982 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002983 return err;
2984}
2985
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002986static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002987 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002988{
Szymon Jancc35938b2011-03-22 13:12:21 +01002989 struct pending_cmd *cmd;
2990 int err;
2991
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002992 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002993
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002994 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002995
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002996 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002997 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002998 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002999 goto unlock;
3000 }
3001
Andre Guedes9a1a1992012-07-24 15:03:48 -03003002 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003003 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003004 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01003005 goto unlock;
3006 }
3007
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003008 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003009 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003010 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01003011 goto unlock;
3012 }
3013
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003014 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01003015 if (!cmd) {
3016 err = -ENOMEM;
3017 goto unlock;
3018 }
3019
3020 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
3021 if (err < 0)
3022 mgmt_pending_remove(cmd);
3023
3024unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003025 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003026 return err;
3027}
3028
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003029static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003030 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003031{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003032 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003033 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003034 int err;
3035
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003036 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003037
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003038 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003039
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003040 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003041 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01003042 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003043 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01003044 else
Szymon Janca6785be2012-12-13 15:11:21 +01003045 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003046
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003047 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003048 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003049
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003050 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003051 return err;
3052}
3053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003054static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003055 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003056{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003057 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003058 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003059 int err;
3060
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003061 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003062
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003063 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003064
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003065 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003066 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003067 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003068 else
Szymon Janca6785be2012-12-13 15:11:21 +01003069 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003070
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003071 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003072 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003073
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003074 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003075 return err;
3076}
3077
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003078static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3079{
3080 struct pending_cmd *cmd;
3081 u8 type;
3082 int err;
3083
3084 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3085
3086 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3087 if (!cmd)
3088 return -ENOENT;
3089
3090 type = hdev->discovery.type;
3091
3092 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3093 &type, sizeof(type));
3094 mgmt_pending_remove(cmd);
3095
3096 return err;
3097}
3098
Andre Guedes7c307722013-04-30 15:29:28 -03003099static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3100{
3101 BT_DBG("status %d", status);
3102
3103 if (status) {
3104 hci_dev_lock(hdev);
3105 mgmt_start_discovery_failed(hdev, status);
3106 hci_dev_unlock(hdev);
3107 return;
3108 }
3109
3110 hci_dev_lock(hdev);
3111 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3112 hci_dev_unlock(hdev);
3113
3114 switch (hdev->discovery.type) {
3115 case DISCOV_TYPE_LE:
3116 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003117 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003118 break;
3119
3120 case DISCOV_TYPE_INTERLEAVED:
3121 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003122 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003123 break;
3124
3125 case DISCOV_TYPE_BREDR:
3126 break;
3127
3128 default:
3129 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3130 }
3131}
3132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003133static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003134 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003135{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003136 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003137 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003138 struct hci_cp_le_set_scan_param param_cp;
3139 struct hci_cp_le_set_scan_enable enable_cp;
3140 struct hci_cp_inquiry inq_cp;
3141 struct hci_request req;
3142 /* General inquiry access code (GIAC) */
3143 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003144 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003145 int err;
3146
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003147 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003148
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003149 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003150
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003151 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003152 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003153 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003154 goto failed;
3155 }
3156
Andre Guedes642be6c2012-03-21 00:03:37 -03003157 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3158 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3159 MGMT_STATUS_BUSY);
3160 goto failed;
3161 }
3162
Johan Hedbergff9ef572012-01-04 14:23:45 +02003163 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003164 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003165 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003166 goto failed;
3167 }
3168
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003169 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003170 if (!cmd) {
3171 err = -ENOMEM;
3172 goto failed;
3173 }
3174
Andre Guedes4aab14e2012-02-17 20:39:36 -03003175 hdev->discovery.type = cp->type;
3176
Andre Guedes7c307722013-04-30 15:29:28 -03003177 hci_req_init(&req, hdev);
3178
Andre Guedes4aab14e2012-02-17 20:39:36 -03003179 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003180 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003181 status = mgmt_bredr_support(hdev);
3182 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003183 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003184 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003185 mgmt_pending_remove(cmd);
3186 goto failed;
3187 }
3188
Andre Guedes7c307722013-04-30 15:29:28 -03003189 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3190 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3191 MGMT_STATUS_BUSY);
3192 mgmt_pending_remove(cmd);
3193 goto failed;
3194 }
3195
3196 hci_inquiry_cache_flush(hdev);
3197
3198 memset(&inq_cp, 0, sizeof(inq_cp));
3199 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003200 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003201 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003202 break;
3203
3204 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003205 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003206 status = mgmt_le_support(hdev);
3207 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003208 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003209 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003210 mgmt_pending_remove(cmd);
3211 goto failed;
3212 }
3213
Andre Guedes7c307722013-04-30 15:29:28 -03003214 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003215 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003216 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3217 MGMT_STATUS_NOT_SUPPORTED);
3218 mgmt_pending_remove(cmd);
3219 goto failed;
3220 }
3221
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003222 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003223 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3224 MGMT_STATUS_REJECTED);
3225 mgmt_pending_remove(cmd);
3226 goto failed;
3227 }
3228
3229 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3230 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3231 MGMT_STATUS_BUSY);
3232 mgmt_pending_remove(cmd);
3233 goto failed;
3234 }
3235
3236 memset(&param_cp, 0, sizeof(param_cp));
3237 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003238 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3239 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmann79830f62013-10-18 16:38:09 -07003240 param_cp.own_address_type = hdev->own_addr_type;
Andre Guedes7c307722013-04-30 15:29:28 -03003241 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3242 &param_cp);
3243
3244 memset(&enable_cp, 0, sizeof(enable_cp));
3245 enable_cp.enable = LE_SCAN_ENABLE;
3246 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3247 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3248 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003249 break;
3250
Andre Guedesf39799f2012-02-17 20:39:35 -03003251 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003252 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3253 MGMT_STATUS_INVALID_PARAMS);
3254 mgmt_pending_remove(cmd);
3255 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003256 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003257
Andre Guedes7c307722013-04-30 15:29:28 -03003258 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003259 if (err < 0)
3260 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003261 else
3262 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003263
3264failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003265 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003266 return err;
3267}
3268
Andre Guedes1183fdc2013-04-30 15:29:35 -03003269static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3270{
3271 struct pending_cmd *cmd;
3272 int err;
3273
3274 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3275 if (!cmd)
3276 return -ENOENT;
3277
3278 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3279 &hdev->discovery.type, sizeof(hdev->discovery.type));
3280 mgmt_pending_remove(cmd);
3281
3282 return err;
3283}
3284
Andre Guedes0e05bba2013-04-30 15:29:33 -03003285static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3286{
3287 BT_DBG("status %d", status);
3288
3289 hci_dev_lock(hdev);
3290
3291 if (status) {
3292 mgmt_stop_discovery_failed(hdev, status);
3293 goto unlock;
3294 }
3295
3296 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3297
3298unlock:
3299 hci_dev_unlock(hdev);
3300}
3301
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003302static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003303 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003304{
Johan Hedbergd9306502012-02-20 23:25:18 +02003305 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003306 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003307 struct hci_cp_remote_name_req_cancel cp;
3308 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003309 struct hci_request req;
3310 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003311 int err;
3312
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003313 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003314
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003315 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003316
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003317 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003318 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003319 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3320 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003321 goto unlock;
3322 }
3323
3324 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003325 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003326 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3327 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003328 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003329 }
3330
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003331 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003332 if (!cmd) {
3333 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003334 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003335 }
3336
Andre Guedes0e05bba2013-04-30 15:29:33 -03003337 hci_req_init(&req, hdev);
3338
Andre Guedese0d9727e2012-03-20 15:15:36 -03003339 switch (hdev->discovery.state) {
3340 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003341 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3342 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3343 } else {
3344 cancel_delayed_work(&hdev->le_scan_disable);
3345
3346 memset(&enable_cp, 0, sizeof(enable_cp));
3347 enable_cp.enable = LE_SCAN_DISABLE;
3348 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3349 sizeof(enable_cp), &enable_cp);
3350 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003351
Andre Guedese0d9727e2012-03-20 15:15:36 -03003352 break;
3353
3354 case DISCOVERY_RESOLVING:
3355 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003356 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003357 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003358 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003359 err = cmd_complete(sk, hdev->id,
3360 MGMT_OP_STOP_DISCOVERY, 0,
3361 &mgmt_cp->type,
3362 sizeof(mgmt_cp->type));
3363 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3364 goto unlock;
3365 }
3366
3367 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003368 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3369 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003370
3371 break;
3372
3373 default:
3374 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003375
3376 mgmt_pending_remove(cmd);
3377 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3378 MGMT_STATUS_FAILED, &mgmt_cp->type,
3379 sizeof(mgmt_cp->type));
3380 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003381 }
3382
Andre Guedes0e05bba2013-04-30 15:29:33 -03003383 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003384 if (err < 0)
3385 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003386 else
3387 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003388
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003389unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003390 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003391 return err;
3392}
3393
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003394static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003395 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003396{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003397 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003398 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003399 int err;
3400
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003401 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003402
Johan Hedberg561aafb2012-01-04 13:31:59 +02003403 hci_dev_lock(hdev);
3404
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003405 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003406 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003407 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003408 goto failed;
3409 }
3410
Johan Hedberga198e7b2012-02-17 14:27:06 +02003411 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003412 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003413 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003414 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003415 goto failed;
3416 }
3417
3418 if (cp->name_known) {
3419 e->name_state = NAME_KNOWN;
3420 list_del(&e->list);
3421 } else {
3422 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003423 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003424 }
3425
Johan Hedberge3846622013-01-09 15:29:33 +02003426 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3427 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003428
3429failed:
3430 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003431 return err;
3432}
3433
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003434static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003435 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003436{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003437 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003438 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003439 int err;
3440
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003441 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003442
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003443 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003444 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3445 MGMT_STATUS_INVALID_PARAMS,
3446 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003447
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003448 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003449
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003450 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003451 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003452 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003453 else
Szymon Janca6785be2012-12-13 15:11:21 +01003454 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003455
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003456 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003457 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003458
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003459 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003460
3461 return err;
3462}
3463
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003464static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003465 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003466{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003467 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003468 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003469 int err;
3470
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003471 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003472
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003473 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003474 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3475 MGMT_STATUS_INVALID_PARAMS,
3476 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003477
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003478 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003479
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003480 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003481 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003482 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003483 else
Szymon Janca6785be2012-12-13 15:11:21 +01003484 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003485
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003486 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003487 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003488
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003489 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003490
3491 return err;
3492}
3493
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003494static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3495 u16 len)
3496{
3497 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003498 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003499 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003500 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003501
3502 BT_DBG("%s", hdev->name);
3503
Szymon Jancc72d4b82012-03-16 16:02:57 +01003504 source = __le16_to_cpu(cp->source);
3505
3506 if (source > 0x0002)
3507 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3508 MGMT_STATUS_INVALID_PARAMS);
3509
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003510 hci_dev_lock(hdev);
3511
Szymon Jancc72d4b82012-03-16 16:02:57 +01003512 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003513 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3514 hdev->devid_product = __le16_to_cpu(cp->product);
3515 hdev->devid_version = __le16_to_cpu(cp->version);
3516
3517 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3518
Johan Hedberg890ea892013-03-15 17:06:52 -05003519 hci_req_init(&req, hdev);
3520 update_eir(&req);
3521 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003522
3523 hci_dev_unlock(hdev);
3524
3525 return err;
3526}
3527
Johan Hedberg4375f102013-09-25 13:26:10 +03003528static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3529{
3530 struct cmd_lookup match = { NULL, hdev };
3531
3532 if (status) {
3533 u8 mgmt_err = mgmt_status(status);
3534
3535 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3536 cmd_status_rsp, &mgmt_err);
3537 return;
3538 }
3539
3540 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3541 &match);
3542
3543 new_settings(hdev, match.sk);
3544
3545 if (match.sk)
3546 sock_put(match.sk);
3547}
3548
Marcel Holtmann21b51872013-10-10 09:47:53 -07003549static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3550 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003551{
3552 struct mgmt_mode *cp = data;
3553 struct pending_cmd *cmd;
3554 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003555 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003556 int err;
3557
3558 BT_DBG("request for %s", hdev->name);
3559
Johan Hedberge6fe7982013-10-02 15:45:22 +03003560 status = mgmt_le_support(hdev);
3561 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003562 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003563 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003564
3565 if (cp->val != 0x00 && cp->val != 0x01)
3566 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3567 MGMT_STATUS_INVALID_PARAMS);
3568
3569 hci_dev_lock(hdev);
3570
3571 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003572 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003573
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003574 /* The following conditions are ones which mean that we should
3575 * not do any HCI communication but directly send a mgmt
3576 * response to user space (after toggling the flag if
3577 * necessary).
3578 */
3579 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003580 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003581 bool changed = false;
3582
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003583 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3584 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003585 changed = true;
3586 }
3587
3588 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3589 if (err < 0)
3590 goto unlock;
3591
3592 if (changed)
3593 err = new_settings(hdev, sk);
3594
3595 goto unlock;
3596 }
3597
3598 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3599 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3600 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3601 MGMT_STATUS_BUSY);
3602 goto unlock;
3603 }
3604
3605 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3606 if (!cmd) {
3607 err = -ENOMEM;
3608 goto unlock;
3609 }
3610
3611 hci_req_init(&req, hdev);
3612
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003613 if (val)
3614 enable_advertising(&req);
3615 else
3616 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003617
3618 err = hci_req_run(&req, set_advertising_complete);
3619 if (err < 0)
3620 mgmt_pending_remove(cmd);
3621
3622unlock:
3623 hci_dev_unlock(hdev);
3624 return err;
3625}
3626
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003627static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3628 void *data, u16 len)
3629{
3630 struct mgmt_cp_set_static_address *cp = data;
3631 int err;
3632
3633 BT_DBG("%s", hdev->name);
3634
Marcel Holtmann62af4442013-10-02 22:10:32 -07003635 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003636 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003637 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003638
3639 if (hdev_is_powered(hdev))
3640 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3641 MGMT_STATUS_REJECTED);
3642
3643 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3644 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3645 return cmd_status(sk, hdev->id,
3646 MGMT_OP_SET_STATIC_ADDRESS,
3647 MGMT_STATUS_INVALID_PARAMS);
3648
3649 /* Two most significant bits shall be set */
3650 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3651 return cmd_status(sk, hdev->id,
3652 MGMT_OP_SET_STATIC_ADDRESS,
3653 MGMT_STATUS_INVALID_PARAMS);
3654 }
3655
3656 hci_dev_lock(hdev);
3657
3658 bacpy(&hdev->static_addr, &cp->bdaddr);
3659
3660 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3661
3662 hci_dev_unlock(hdev);
3663
3664 return err;
3665}
3666
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003667static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3668 void *data, u16 len)
3669{
3670 struct mgmt_cp_set_scan_params *cp = data;
3671 __u16 interval, window;
3672 int err;
3673
3674 BT_DBG("%s", hdev->name);
3675
3676 if (!lmp_le_capable(hdev))
3677 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3678 MGMT_STATUS_NOT_SUPPORTED);
3679
3680 interval = __le16_to_cpu(cp->interval);
3681
3682 if (interval < 0x0004 || interval > 0x4000)
3683 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3684 MGMT_STATUS_INVALID_PARAMS);
3685
3686 window = __le16_to_cpu(cp->window);
3687
3688 if (window < 0x0004 || window > 0x4000)
3689 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3690 MGMT_STATUS_INVALID_PARAMS);
3691
Marcel Holtmann899e1072013-10-14 09:55:32 -07003692 if (window > interval)
3693 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3694 MGMT_STATUS_INVALID_PARAMS);
3695
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003696 hci_dev_lock(hdev);
3697
3698 hdev->le_scan_interval = interval;
3699 hdev->le_scan_window = window;
3700
3701 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3702
3703 hci_dev_unlock(hdev);
3704
3705 return err;
3706}
3707
Johan Hedberg33e38b32013-03-15 17:07:05 -05003708static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3709{
3710 struct pending_cmd *cmd;
3711
3712 BT_DBG("status 0x%02x", status);
3713
3714 hci_dev_lock(hdev);
3715
3716 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3717 if (!cmd)
3718 goto unlock;
3719
3720 if (status) {
3721 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3722 mgmt_status(status));
3723 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003724 struct mgmt_mode *cp = cmd->param;
3725
3726 if (cp->val)
3727 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3728 else
3729 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3730
Johan Hedberg33e38b32013-03-15 17:07:05 -05003731 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3732 new_settings(hdev, cmd->sk);
3733 }
3734
3735 mgmt_pending_remove(cmd);
3736
3737unlock:
3738 hci_dev_unlock(hdev);
3739}
3740
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003741static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003742 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003743{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003744 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003745 struct pending_cmd *cmd;
3746 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003747 int err;
3748
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003749 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003750
Johan Hedberg56f87902013-10-02 13:43:13 +03003751 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3752 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003753 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3754 MGMT_STATUS_NOT_SUPPORTED);
3755
Johan Hedberga7e80f22013-01-09 16:05:19 +02003756 if (cp->val != 0x00 && cp->val != 0x01)
3757 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3758 MGMT_STATUS_INVALID_PARAMS);
3759
Johan Hedberg5400c042012-02-21 16:40:33 +02003760 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003761 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003762 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003763
3764 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003765 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003766 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003767
3768 hci_dev_lock(hdev);
3769
Johan Hedberg05cbf292013-03-15 17:07:07 -05003770 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3771 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3772 MGMT_STATUS_BUSY);
3773 goto unlock;
3774 }
3775
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003776 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3777 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3778 hdev);
3779 goto unlock;
3780 }
3781
Johan Hedberg33e38b32013-03-15 17:07:05 -05003782 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3783 data, len);
3784 if (!cmd) {
3785 err = -ENOMEM;
3786 goto unlock;
3787 }
3788
3789 hci_req_init(&req, hdev);
3790
Johan Hedberg406d7802013-03-15 17:07:09 -05003791 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003792
3793 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003794 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003795 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003796 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003797 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003798 }
3799
Johan Hedberg33e38b32013-03-15 17:07:05 -05003800unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003801 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003802
Antti Julkuf6422ec2011-06-22 13:11:56 +03003803 return err;
3804}
3805
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003806static void set_bredr_scan(struct hci_request *req)
3807{
3808 struct hci_dev *hdev = req->hdev;
3809 u8 scan = 0;
3810
3811 /* Ensure that fast connectable is disabled. This function will
3812 * not do anything if the page scan parameters are already what
3813 * they should be.
3814 */
3815 write_fast_connectable(req, false);
3816
3817 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3818 scan |= SCAN_PAGE;
3819 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3820 scan |= SCAN_INQUIRY;
3821
3822 if (scan)
3823 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3824}
3825
Johan Hedberg0663ca22013-10-02 13:43:14 +03003826static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3827{
3828 struct pending_cmd *cmd;
3829
3830 BT_DBG("status 0x%02x", status);
3831
3832 hci_dev_lock(hdev);
3833
3834 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3835 if (!cmd)
3836 goto unlock;
3837
3838 if (status) {
3839 u8 mgmt_err = mgmt_status(status);
3840
3841 /* We need to restore the flag if related HCI commands
3842 * failed.
3843 */
3844 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3845
3846 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3847 } else {
3848 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3849 new_settings(hdev, cmd->sk);
3850 }
3851
3852 mgmt_pending_remove(cmd);
3853
3854unlock:
3855 hci_dev_unlock(hdev);
3856}
3857
3858static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3859{
3860 struct mgmt_mode *cp = data;
3861 struct pending_cmd *cmd;
3862 struct hci_request req;
3863 int err;
3864
3865 BT_DBG("request for %s", hdev->name);
3866
3867 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3868 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3869 MGMT_STATUS_NOT_SUPPORTED);
3870
3871 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3872 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3873 MGMT_STATUS_REJECTED);
3874
3875 if (cp->val != 0x00 && cp->val != 0x01)
3876 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3877 MGMT_STATUS_INVALID_PARAMS);
3878
3879 hci_dev_lock(hdev);
3880
3881 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3882 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3883 goto unlock;
3884 }
3885
3886 if (!hdev_is_powered(hdev)) {
3887 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003888 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3889 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3890 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3891 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3892 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3893 }
3894
3895 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3896
3897 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3898 if (err < 0)
3899 goto unlock;
3900
3901 err = new_settings(hdev, sk);
3902 goto unlock;
3903 }
3904
3905 /* Reject disabling when powered on */
3906 if (!cp->val) {
3907 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3908 MGMT_STATUS_REJECTED);
3909 goto unlock;
3910 }
3911
3912 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3913 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3914 MGMT_STATUS_BUSY);
3915 goto unlock;
3916 }
3917
3918 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3919 if (!cmd) {
3920 err = -ENOMEM;
3921 goto unlock;
3922 }
3923
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003924 /* We need to flip the bit already here so that update_adv_data
Johan Hedberg0663ca22013-10-02 13:43:14 +03003925 * generates the correct flags.
3926 */
3927 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3928
3929 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003930
3931 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3932 set_bredr_scan(&req);
3933
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07003934 /* Since only the advertising data flags will change, there
3935 * is no need to update the scan response data.
3936 */
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07003937 update_adv_data(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003938
Johan Hedberg0663ca22013-10-02 13:43:14 +03003939 err = hci_req_run(&req, set_bredr_complete);
3940 if (err < 0)
3941 mgmt_pending_remove(cmd);
3942
3943unlock:
3944 hci_dev_unlock(hdev);
3945 return err;
3946}
3947
Johan Hedberg3f706b72013-01-20 14:27:16 +02003948static bool ltk_is_valid(struct mgmt_ltk_info *key)
3949{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003950 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3951 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003952 if (key->master != 0x00 && key->master != 0x01)
3953 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003954 if (!bdaddr_type_is_le(key->addr.type))
3955 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003956 return true;
3957}
3958
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003959static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003960 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003961{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003962 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3963 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003964 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003965
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003966 BT_DBG("request for %s", hdev->name);
3967
3968 if (!lmp_le_capable(hdev))
3969 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3970 MGMT_STATUS_NOT_SUPPORTED);
3971
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003972 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003973
3974 expected_len = sizeof(*cp) + key_count *
3975 sizeof(struct mgmt_ltk_info);
3976 if (expected_len != len) {
3977 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003978 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003979 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003980 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003981 }
3982
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003983 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003984
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003985 for (i = 0; i < key_count; i++) {
3986 struct mgmt_ltk_info *key = &cp->keys[i];
3987
Johan Hedberg3f706b72013-01-20 14:27:16 +02003988 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003989 return cmd_status(sk, hdev->id,
3990 MGMT_OP_LOAD_LONG_TERM_KEYS,
3991 MGMT_STATUS_INVALID_PARAMS);
3992 }
3993
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003994 hci_dev_lock(hdev);
3995
3996 hci_smp_ltks_clear(hdev);
3997
3998 for (i = 0; i < key_count; i++) {
3999 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004000 u8 type, addr_type;
4001
4002 if (key->addr.type == BDADDR_LE_PUBLIC)
4003 addr_type = ADDR_LE_DEV_PUBLIC;
4004 else
4005 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004006
4007 if (key->master)
4008 type = HCI_SMP_LTK;
4009 else
4010 type = HCI_SMP_LTK_SLAVE;
4011
Marcel Holtmann79d95a12013-10-13 03:57:38 -07004012 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004013 type, 0, key->authenticated, key->val,
4014 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004015 }
4016
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004017 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
4018 NULL, 0);
4019
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004020 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004021
Johan Hedberg715a5bf2013-01-09 15:29:34 +02004022 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004023}
4024
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004025static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004026 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
4027 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004028 bool var_len;
4029 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004030} mgmt_handlers[] = {
4031 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02004032 { read_version, false, MGMT_READ_VERSION_SIZE },
4033 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
4034 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
4035 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4036 { set_powered, false, MGMT_SETTING_SIZE },
4037 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4038 { set_connectable, false, MGMT_SETTING_SIZE },
4039 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4040 { set_pairable, false, MGMT_SETTING_SIZE },
4041 { set_link_security, false, MGMT_SETTING_SIZE },
4042 { set_ssp, false, MGMT_SETTING_SIZE },
4043 { set_hs, false, MGMT_SETTING_SIZE },
4044 { set_le, false, MGMT_SETTING_SIZE },
4045 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4046 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4047 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4048 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4049 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4050 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4051 { disconnect, false, MGMT_DISCONNECT_SIZE },
4052 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4053 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4054 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4055 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4056 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4057 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4058 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4059 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4060 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4061 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4062 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4063 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
4064 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
4065 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4066 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4067 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4068 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4069 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4070 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004071 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004072 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004073 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004074 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004075 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004076};
4077
4078
Johan Hedberg03811012010-12-08 00:21:06 +02004079int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4080{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004081 void *buf;
4082 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004083 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004084 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004085 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004086 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004087 int err;
4088
4089 BT_DBG("got %zu bytes", msglen);
4090
4091 if (msglen < sizeof(*hdr))
4092 return -EINVAL;
4093
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004094 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004095 if (!buf)
4096 return -ENOMEM;
4097
4098 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4099 err = -EFAULT;
4100 goto done;
4101 }
4102
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004103 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004104 opcode = __le16_to_cpu(hdr->opcode);
4105 index = __le16_to_cpu(hdr->index);
4106 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004107
4108 if (len != msglen - sizeof(*hdr)) {
4109 err = -EINVAL;
4110 goto done;
4111 }
4112
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004113 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004114 hdev = hci_dev_get(index);
4115 if (!hdev) {
4116 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004117 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004118 goto done;
4119 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004120
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004121 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4122 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004123 err = cmd_status(sk, index, opcode,
4124 MGMT_STATUS_INVALID_INDEX);
4125 goto done;
4126 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004127 }
4128
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004129 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004130 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004131 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004132 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004133 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004134 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004135 }
4136
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004137 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004138 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004139 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004140 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004141 goto done;
4142 }
4143
Johan Hedbergbe22b542012-03-01 22:24:41 +02004144 handler = &mgmt_handlers[opcode];
4145
4146 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004147 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004148 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004149 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004150 goto done;
4151 }
4152
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004153 if (hdev)
4154 mgmt_init_hdev(sk, hdev);
4155
4156 cp = buf + sizeof(*hdr);
4157
Johan Hedbergbe22b542012-03-01 22:24:41 +02004158 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004159 if (err < 0)
4160 goto done;
4161
Johan Hedberg03811012010-12-08 00:21:06 +02004162 err = msglen;
4163
4164done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004165 if (hdev)
4166 hci_dev_put(hdev);
4167
Johan Hedberg03811012010-12-08 00:21:06 +02004168 kfree(buf);
4169 return err;
4170}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004171
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004172void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004173{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004174 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004175 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004176
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004177 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004178}
4179
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004180void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004181{
Johan Hedberg5f159032012-03-02 03:13:19 +02004182 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004183
Marcel Holtmann1514b892013-10-06 08:25:01 -07004184 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004185 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004186
Johan Hedberg744cf192011-11-08 20:40:14 +02004187 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004188
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004189 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004190}
4191
Johan Hedberg229ab392013-03-15 17:06:53 -05004192static void powered_complete(struct hci_dev *hdev, u8 status)
4193{
4194 struct cmd_lookup match = { NULL, hdev };
4195
4196 BT_DBG("status 0x%02x", status);
4197
4198 hci_dev_lock(hdev);
4199
4200 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4201
4202 new_settings(hdev, match.sk);
4203
4204 hci_dev_unlock(hdev);
4205
4206 if (match.sk)
4207 sock_put(match.sk);
4208}
4209
Johan Hedberg70da6242013-03-15 17:06:51 -05004210static int powered_update_hci(struct hci_dev *hdev)
4211{
Johan Hedberg890ea892013-03-15 17:06:52 -05004212 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004213 u8 link_sec;
4214
Johan Hedberg890ea892013-03-15 17:06:52 -05004215 hci_req_init(&req, hdev);
4216
Johan Hedberg70da6242013-03-15 17:06:51 -05004217 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4218 !lmp_host_ssp_capable(hdev)) {
4219 u8 ssp = 1;
4220
Johan Hedberg890ea892013-03-15 17:06:52 -05004221 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004222 }
4223
Johan Hedbergc73eee92013-04-19 18:35:21 +03004224 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4225 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004226 struct hci_cp_write_le_host_supported cp;
4227
4228 cp.le = 1;
4229 cp.simul = lmp_le_br_capable(hdev);
4230
4231 /* Check first if we already have the right
4232 * host state (host features set)
4233 */
4234 if (cp.le != lmp_host_le_capable(hdev) ||
4235 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004236 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4237 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004238 }
4239
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004240 if (lmp_le_capable(hdev)) {
4241 /* Set random address to static address if configured */
4242 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4243 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4244 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004245
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004246 /* Make sure the controller has a good default for
4247 * advertising data. This also applies to the case
4248 * where BR/EDR was toggled during the AUTO_OFF phase.
4249 */
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004250 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
Marcel Holtmann5947f4b2013-10-16 00:16:50 -07004251 update_adv_data(&req);
Marcel Holtmannf14d8f62013-10-16 00:16:48 -07004252 update_scan_rsp_data(&req);
4253 }
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004254
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004255 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4256 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004257 }
4258
Johan Hedberg70da6242013-03-15 17:06:51 -05004259 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4260 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004261 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4262 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004263
4264 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004265 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4266 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004267 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004268 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004269 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004270 }
4271
Johan Hedberg229ab392013-03-15 17:06:53 -05004272 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004273}
4274
Johan Hedberg744cf192011-11-08 20:40:14 +02004275int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004276{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004277 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004278 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4279 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004280 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004281
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004282 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4283 return 0;
4284
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004285 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004286 if (powered_update_hci(hdev) == 0)
4287 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004288
Johan Hedberg229ab392013-03-15 17:06:53 -05004289 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4290 &match);
4291 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004292 }
4293
Johan Hedberg229ab392013-03-15 17:06:53 -05004294 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4295 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4296
4297 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4298 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4299 zero_cod, sizeof(zero_cod), NULL);
4300
4301new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004302 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004303
4304 if (match.sk)
4305 sock_put(match.sk);
4306
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004307 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004308}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004309
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004310void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004311{
4312 struct pending_cmd *cmd;
4313 u8 status;
4314
4315 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4316 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004317 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004318
4319 if (err == -ERFKILL)
4320 status = MGMT_STATUS_RFKILLED;
4321 else
4322 status = MGMT_STATUS_FAILED;
4323
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004324 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004325
4326 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004327}
4328
Marcel Holtmannd1967ff2013-10-15 10:57:40 -07004329void mgmt_discoverable_timeout(struct hci_dev *hdev)
4330{
4331 struct hci_request req;
4332 u8 scan = SCAN_PAGE;
4333
4334 hci_dev_lock(hdev);
4335
4336 /* When discoverable timeout triggers, then just make sure
4337 * the limited discoverable flag is cleared. Even in the case
4338 * of a timeout triggered from general discoverable, it is
4339 * safe to unconditionally clear the flag.
4340 */
4341 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
4342
4343 hci_req_init(&req, hdev);
4344 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
4345 update_class(&req);
4346 hci_req_run(&req, NULL);
4347
4348 hdev->discov_timeout = 0;
4349
4350 hci_dev_unlock(hdev);
4351}
4352
Marcel Holtmann86a75642013-10-15 06:33:54 -07004353void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004354{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004355 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004356
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004357 /* Nothing needed here if there's a pending command since that
4358 * commands request completion callback takes care of everything
4359 * necessary.
4360 */
4361 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004362 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004363
Marcel Holtmann86a75642013-10-15 06:33:54 -07004364 if (discoverable)
4365 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4366 else
4367 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004368
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004369 if (changed)
Marcel Holtmann86a75642013-10-15 06:33:54 -07004370 new_settings(hdev, NULL);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004371}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004372
Marcel Holtmanna3309162013-10-15 06:33:55 -07004373void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004374{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004375 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004376
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004377 /* Nothing needed here if there's a pending command since that
4378 * commands request completion callback takes care of everything
4379 * necessary.
4380 */
4381 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004382 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004383
Marcel Holtmanna3309162013-10-15 06:33:55 -07004384 if (connectable)
4385 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4386 else
4387 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004388
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004389 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004390 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004391}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004392
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004393void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004394{
Johan Hedbergca69b792011-11-11 18:10:00 +02004395 u8 mgmt_err = mgmt_status(status);
4396
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004397 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004398 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004399 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004400
4401 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004402 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004403 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004404}
4405
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004406void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4407 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004408{
Johan Hedberg86742e12011-11-07 23:13:38 +02004409 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004410
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004411 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004412
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004413 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004414 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004415 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004416 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004417 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004418 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004419
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004420 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004421}
Johan Hedbergf7520542011-01-20 12:34:39 +02004422
Marcel Holtmann083368f2013-10-15 14:26:29 -07004423void mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004424{
4425 struct mgmt_ev_new_long_term_key ev;
4426
4427 memset(&ev, 0, sizeof(ev));
4428
4429 ev.store_hint = persistent;
4430 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004431 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004432 ev.key.authenticated = key->authenticated;
4433 ev.key.enc_size = key->enc_size;
4434 ev.key.ediv = key->ediv;
4435
4436 if (key->type == HCI_SMP_LTK)
4437 ev.key.master = 1;
4438
4439 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4440 memcpy(ev.key.val, key->val, sizeof(key->val));
4441
Marcel Holtmann083368f2013-10-15 14:26:29 -07004442 mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev), NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004443}
4444
Marcel Holtmann94933992013-10-15 10:26:39 -07004445static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4446 u8 data_len)
4447{
4448 eir[eir_len++] = sizeof(type) + data_len;
4449 eir[eir_len++] = type;
4450 memcpy(&eir[eir_len], data, data_len);
4451 eir_len += data_len;
4452
4453 return eir_len;
4454}
4455
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004456void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4457 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4458 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004459{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004460 char buf[512];
4461 struct mgmt_ev_device_connected *ev = (void *) buf;
4462 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004463
Johan Hedbergb644ba32012-01-17 21:48:47 +02004464 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004465 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004466
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004467 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004468
Johan Hedbergb644ba32012-01-17 21:48:47 +02004469 if (name_len > 0)
4470 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004471 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004472
4473 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004474 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004475 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004476
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004477 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004478
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004479 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4480 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004481}
4482
Johan Hedberg8962ee72011-01-20 12:40:27 +02004483static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4484{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004485 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004486 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004487 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004488
Johan Hedberg88c3df12012-02-09 14:27:38 +02004489 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4490 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004491
Johan Hedbergaee9b212012-02-18 15:07:59 +02004492 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004493 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004494
4495 *sk = cmd->sk;
4496 sock_hold(*sk);
4497
Johan Hedberga664b5b2011-02-19 12:06:02 -03004498 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004499}
4500
Johan Hedberg124f6e32012-02-09 13:50:12 +02004501static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004502{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004503 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004504 struct mgmt_cp_unpair_device *cp = cmd->param;
4505 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004506
4507 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004508 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4509 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004510
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004511 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4512
Johan Hedbergaee9b212012-02-18 15:07:59 +02004513 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004514
4515 mgmt_pending_remove(cmd);
4516}
4517
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004518void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4519 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004520{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004521 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004522 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004523
Johan Hedberg744cf192011-11-08 20:40:14 +02004524 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004525
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004526 bacpy(&ev.addr.bdaddr, bdaddr);
4527 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4528 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004529
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004530 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004531
4532 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004533 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004534
Johan Hedberg124f6e32012-02-09 13:50:12 +02004535 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004536 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004537}
4538
Marcel Holtmann78929242013-10-06 23:55:47 -07004539void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4540 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004541{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004542 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004543 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004544
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004545 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4546 hdev);
4547
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004548 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004549 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004550 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004551
Johan Hedberg88c3df12012-02-09 14:27:38 +02004552 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004553 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004554
Marcel Holtmann78929242013-10-06 23:55:47 -07004555 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4556 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004557
Johan Hedberga664b5b2011-02-19 12:06:02 -03004558 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004559}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004560
Marcel Holtmann445608d2013-10-06 23:55:48 -07004561void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4562 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004563{
4564 struct mgmt_ev_connect_failed ev;
4565
Johan Hedberg4c659c32011-11-07 23:13:39 +02004566 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004567 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004568 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004569
Marcel Holtmann445608d2013-10-06 23:55:48 -07004570 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004571}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004572
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004573void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004574{
4575 struct mgmt_ev_pin_code_request ev;
4576
Johan Hedbergd8457692012-02-17 14:24:57 +02004577 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004578 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004579 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004580
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004581 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004582}
4583
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004584void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4585 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004586{
4587 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004588 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004589
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004590 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004591 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004592 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004593
Johan Hedbergd8457692012-02-17 14:24:57 +02004594 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004595 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004596
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004597 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4598 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004599
Johan Hedberga664b5b2011-02-19 12:06:02 -03004600 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004601}
4602
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004603void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4604 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004605{
4606 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004607 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004608
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004609 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004610 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004611 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004612
Johan Hedbergd8457692012-02-17 14:24:57 +02004613 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004614 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004615
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004616 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4617 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004618
Johan Hedberga664b5b2011-02-19 12:06:02 -03004619 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004620}
Johan Hedberga5c29682011-02-19 12:05:57 -03004621
Johan Hedberg744cf192011-11-08 20:40:14 +02004622int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004623 u8 link_type, u8 addr_type, __le32 value,
4624 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004625{
4626 struct mgmt_ev_user_confirm_request ev;
4627
Johan Hedberg744cf192011-11-08 20:40:14 +02004628 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004629
Johan Hedberg272d90d2012-02-09 15:26:12 +02004630 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004631 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004632 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004633 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004634
Johan Hedberg744cf192011-11-08 20:40:14 +02004635 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004636 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004637}
4638
Johan Hedberg272d90d2012-02-09 15:26:12 +02004639int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004640 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004641{
4642 struct mgmt_ev_user_passkey_request ev;
4643
4644 BT_DBG("%s", hdev->name);
4645
Johan Hedberg272d90d2012-02-09 15:26:12 +02004646 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004647 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004648
4649 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004650 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004651}
4652
Brian Gix0df4c182011-11-16 13:53:13 -08004653static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004654 u8 link_type, u8 addr_type, u8 status,
4655 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004656{
4657 struct pending_cmd *cmd;
4658 struct mgmt_rp_user_confirm_reply rp;
4659 int err;
4660
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004661 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004662 if (!cmd)
4663 return -ENOENT;
4664
Johan Hedberg272d90d2012-02-09 15:26:12 +02004665 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004666 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004667 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004668 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004669
Johan Hedberga664b5b2011-02-19 12:06:02 -03004670 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004671
4672 return err;
4673}
4674
Johan Hedberg744cf192011-11-08 20:40:14 +02004675int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004676 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004677{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004678 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004679 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004680}
4681
Johan Hedberg272d90d2012-02-09 15:26:12 +02004682int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004683 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004684{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004685 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004686 status,
4687 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004688}
Johan Hedberg2a611692011-02-19 12:06:00 -03004689
Brian Gix604086b2011-11-23 08:28:33 -08004690int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004691 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004692{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004693 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004694 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004695}
4696
Johan Hedberg272d90d2012-02-09 15:26:12 +02004697int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004698 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004699{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004700 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004701 status,
4702 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004703}
4704
Johan Hedberg92a25252012-09-06 18:39:26 +03004705int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4706 u8 link_type, u8 addr_type, u32 passkey,
4707 u8 entered)
4708{
4709 struct mgmt_ev_passkey_notify ev;
4710
4711 BT_DBG("%s", hdev->name);
4712
4713 bacpy(&ev.addr.bdaddr, bdaddr);
4714 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4715 ev.passkey = __cpu_to_le32(passkey);
4716 ev.entered = entered;
4717
4718 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4719}
4720
Marcel Holtmanne5460992013-10-15 14:26:23 -07004721void mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4722 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004723{
4724 struct mgmt_ev_auth_failed ev;
4725
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004726 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004727 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004728 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004729
Marcel Holtmanne5460992013-10-15 14:26:23 -07004730 mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004731}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004732
Marcel Holtmann464996a2013-10-15 14:26:24 -07004733void mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004734{
4735 struct cmd_lookup match = { NULL, hdev };
Marcel Holtmann464996a2013-10-15 14:26:24 -07004736 bool changed;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004737
4738 if (status) {
4739 u8 mgmt_err = mgmt_status(status);
4740 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004741 cmd_status_rsp, &mgmt_err);
Marcel Holtmann464996a2013-10-15 14:26:24 -07004742 return;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004743 }
4744
Marcel Holtmann464996a2013-10-15 14:26:24 -07004745 if (test_bit(HCI_AUTH, &hdev->flags))
4746 changed = !test_and_set_bit(HCI_LINK_SECURITY,
4747 &hdev->dev_flags);
4748 else
4749 changed = test_and_clear_bit(HCI_LINK_SECURITY,
4750 &hdev->dev_flags);
Johan Hedberg47990ea2012-02-22 11:58:37 +02004751
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004752 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004753 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004754
Johan Hedberg47990ea2012-02-22 11:58:37 +02004755 if (changed)
Marcel Holtmann464996a2013-10-15 14:26:24 -07004756 new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004757
4758 if (match.sk)
4759 sock_put(match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004760}
4761
Johan Hedberg890ea892013-03-15 17:06:52 -05004762static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004763{
Johan Hedberg890ea892013-03-15 17:06:52 -05004764 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004765 struct hci_cp_write_eir cp;
4766
Johan Hedberg976eb202012-10-24 21:12:01 +03004767 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004768 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004769
Johan Hedbergc80da272012-02-22 15:38:48 +02004770 memset(hdev->eir, 0, sizeof(hdev->eir));
4771
Johan Hedbergcacaf522012-02-21 00:52:42 +02004772 memset(&cp, 0, sizeof(cp));
4773
Johan Hedberg890ea892013-03-15 17:06:52 -05004774 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004775}
4776
Marcel Holtmann3e248562013-10-15 14:26:25 -07004777void mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004778{
4779 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004780 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004781 bool changed = false;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004782
4783 if (status) {
4784 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004785
4786 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004787 &hdev->dev_flags)) {
4788 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004789 new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004790 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004791
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004792 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4793 &mgmt_err);
Marcel Holtmann3e248562013-10-15 14:26:25 -07004794 return;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004795 }
4796
4797 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004798 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004799 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004800 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4801 if (!changed)
4802 changed = test_and_clear_bit(HCI_HS_ENABLED,
4803 &hdev->dev_flags);
4804 else
4805 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004806 }
4807
4808 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4809
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004810 if (changed)
Marcel Holtmann3e248562013-10-15 14:26:25 -07004811 new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004812
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004813 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004814 sock_put(match.sk);
4815
Johan Hedberg890ea892013-03-15 17:06:52 -05004816 hci_req_init(&req, hdev);
4817
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004818 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004819 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004820 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004821 clear_eir(&req);
4822
4823 hci_req_run(&req, NULL);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004824}
4825
Johan Hedberg92da6092013-03-15 17:06:55 -05004826static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004827{
4828 struct cmd_lookup *match = data;
4829
Johan Hedberg90e70452012-02-23 23:09:40 +02004830 if (match->sk == NULL) {
4831 match->sk = cmd->sk;
4832 sock_hold(match->sk);
4833 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004834}
4835
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004836void mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
4837 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004838{
Johan Hedberg90e70452012-02-23 23:09:40 +02004839 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004840
Johan Hedberg92da6092013-03-15 17:06:55 -05004841 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4842 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4843 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004844
4845 if (!status)
Marcel Holtmann4e1b0242013-10-15 14:26:26 -07004846 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class, 3,
4847 NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004848
4849 if (match.sk)
4850 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004851}
4852
Marcel Holtmann7667da32013-10-15 14:26:27 -07004853void mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004854{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004855 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004856 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004857
Johan Hedberg13928972013-03-15 17:07:00 -05004858 if (status)
Marcel Holtmann7667da32013-10-15 14:26:27 -07004859 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004860
4861 memset(&ev, 0, sizeof(ev));
4862 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004863 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004864
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004865 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004866 if (!cmd) {
4867 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004868
Johan Hedberg13928972013-03-15 17:07:00 -05004869 /* If this is a HCI command related to powering on the
4870 * HCI dev don't send any mgmt signals.
4871 */
4872 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
Marcel Holtmann7667da32013-10-15 14:26:27 -07004873 return;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004874 }
4875
Marcel Holtmann7667da32013-10-15 14:26:27 -07004876 mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4877 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004878}
Szymon Jancc35938b2011-03-22 13:12:21 +01004879
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004880void mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
4881 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004882{
4883 struct pending_cmd *cmd;
Szymon Jancc35938b2011-03-22 13:12:21 +01004884
Johan Hedberg744cf192011-11-08 20:40:14 +02004885 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004886
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004887 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004888 if (!cmd)
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004889 return;
Szymon Jancc35938b2011-03-22 13:12:21 +01004890
4891 if (status) {
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004892 cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4893 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004894 } else {
4895 struct mgmt_rp_read_local_oob_data rp;
4896
4897 memcpy(rp.hash, hash, sizeof(rp.hash));
4898 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4899
Marcel Holtmann3edaf092013-10-15 14:26:28 -07004900 cmd_complete(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4901 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004902 }
4903
4904 mgmt_pending_remove(cmd);
Szymon Jancc35938b2011-03-22 13:12:21 +01004905}
Johan Hedberge17acd42011-03-30 23:57:16 +03004906
Marcel Holtmann901801b2013-10-06 23:55:51 -07004907void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4908 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4909 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004910{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004911 char buf[512];
4912 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004913 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004914
Andre Guedes12602d02013-04-30 15:29:40 -03004915 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004916 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004917
Johan Hedberg1dc06092012-01-15 21:01:23 +02004918 /* Leave 5 bytes for a potential CoD field */
4919 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004920 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004921
Johan Hedberg1dc06092012-01-15 21:01:23 +02004922 memset(buf, 0, sizeof(buf));
4923
Johan Hedberge319d2e2012-01-15 19:51:59 +02004924 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004925 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004926 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004927 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304928 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004929 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304930 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004931
Johan Hedberg1dc06092012-01-15 21:01:23 +02004932 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004933 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004934
Johan Hedberg1dc06092012-01-15 21:01:23 +02004935 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4936 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004937 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004938
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004939 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004940 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004941
Marcel Holtmann901801b2013-10-06 23:55:51 -07004942 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004943}
Johan Hedberga88a9652011-03-30 13:18:12 +03004944
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004945void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4946 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004947{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004948 struct mgmt_ev_device_found *ev;
4949 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4950 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004951
Johan Hedbergb644ba32012-01-17 21:48:47 +02004952 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004953
Johan Hedbergb644ba32012-01-17 21:48:47 +02004954 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004955
Johan Hedbergb644ba32012-01-17 21:48:47 +02004956 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004957 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004958 ev->rssi = rssi;
4959
4960 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004961 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004962
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004963 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004964
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004965 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004966}
Johan Hedberg314b2382011-04-27 10:29:57 -04004967
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004968void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004969{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004970 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004971 struct pending_cmd *cmd;
4972
Andre Guedes343fb142011-11-22 17:14:19 -03004973 BT_DBG("%s discovering %u", hdev->name, discovering);
4974
Johan Hedberg164a6e72011-11-01 17:06:44 +02004975 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004976 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004977 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004978 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004979
4980 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004981 u8 type = hdev->discovery.type;
4982
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004983 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4984 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004985 mgmt_pending_remove(cmd);
4986 }
4987
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004988 memset(&ev, 0, sizeof(ev));
4989 ev.type = hdev->discovery.type;
4990 ev.discovering = discovering;
4991
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004992 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004993}
Antti Julku5e762442011-08-25 16:48:02 +03004994
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004995int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004996{
4997 struct pending_cmd *cmd;
4998 struct mgmt_ev_device_blocked ev;
4999
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005000 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005001
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005002 bacpy(&ev.addr.bdaddr, bdaddr);
5003 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005004
Johan Hedberg744cf192011-11-08 20:40:14 +02005005 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005006 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005007}
5008
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005009int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03005010{
5011 struct pending_cmd *cmd;
5012 struct mgmt_ev_device_unblocked ev;
5013
Johan Hedberg2e58ef32011-11-08 20:40:15 +02005014 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03005015
Johan Hedberg88c1fe42012-02-09 15:56:11 +02005016 bacpy(&ev.addr.bdaddr, bdaddr);
5017 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03005018
Johan Hedberg744cf192011-11-08 20:40:14 +02005019 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03005020 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03005021}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005022
5023static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5024{
5025 BT_DBG("%s status %u", hdev->name, status);
5026
5027 /* Clear the advertising mgmt setting if we failed to re-enable it */
5028 if (status) {
5029 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005030 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005031 }
5032}
5033
5034void mgmt_reenable_advertising(struct hci_dev *hdev)
5035{
5036 struct hci_request req;
5037
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005038 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005039 return;
5040
5041 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5042 return;
5043
5044 hci_req_init(&req, hdev);
5045 enable_advertising(&req);
5046
5047 /* If this fails we have no option but to let user space know
5048 * that we've disabled advertising.
5049 */
5050 if (hci_req_run(&req, adv_enable_complete) < 0) {
5051 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005052 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005053 }
5054}