blob: 338878c1357116cbb44907a431cd33fb47535262 [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 Hedbergaee9b2182012-02-18 15:07:59 +0200225static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300226 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200227{
228 struct sk_buff *skb;
229 struct mgmt_hdr *hdr;
230 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300231 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200232
233 BT_DBG("sock %p", sk);
234
Andre Guedes790eff42012-06-07 19:05:46 -0300235 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200236 if (!skb)
237 return -ENOMEM;
238
239 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200240
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530241 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100242 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200243 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200244
Johan Hedberga38528f2011-01-22 06:46:43 +0200245 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200246 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200247 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100248
249 if (rp)
250 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300252 err = sock_queue_rcv_skb(sk, skb);
253 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200254 kfree_skb(skb);
255
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100256 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200257}
258
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300259static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
260 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200261{
262 struct mgmt_rp_read_version rp;
263
264 BT_DBG("sock %p", sk);
265
266 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200267 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200268
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200269 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300270 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200271}
272
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
274 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200275{
276 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200277 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
278 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200279 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200280 size_t rp_size;
281 int i, err;
282
283 BT_DBG("sock %p", sk);
284
285 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
286
287 rp = kmalloc(rp_size, GFP_KERNEL);
288 if (!rp)
289 return -ENOMEM;
290
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200291 rp->num_commands = __constant_cpu_to_le16(num_commands);
292 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200293
294 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
295 put_unaligned_le16(mgmt_commands[i], opcode);
296
297 for (i = 0; i < num_events; i++, opcode++)
298 put_unaligned_le16(mgmt_events[i], opcode);
299
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200300 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300301 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200302 kfree(rp);
303
304 return err;
305}
306
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300307static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
308 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200309{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200310 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200311 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200312 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300314 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315
316 BT_DBG("sock %p", sk);
317
318 read_lock(&hci_dev_list_lock);
319
320 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300321 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700322 if (d->dev_type == HCI_BREDR)
323 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324 }
325
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 rp_len = sizeof(*rp) + (2 * count);
327 rp = kmalloc(rp_len, GFP_ATOMIC);
328 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100329 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100331 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200332
Johan Hedberg476e44c2012-10-19 20:10:46 +0300333 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200334 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200335 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200336 continue;
337
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700338 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
339 continue;
340
Marcel Holtmann1514b892013-10-06 08:25:01 -0700341 if (d->dev_type == HCI_BREDR) {
342 rp->index[count++] = cpu_to_le16(d->id);
343 BT_DBG("Added hci%u", d->id);
344 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345 }
346
Johan Hedberg476e44c2012-10-19 20:10:46 +0300347 rp->num_controllers = cpu_to_le16(count);
348 rp_len = sizeof(*rp) + (2 * count);
349
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 read_unlock(&hci_dev_list_lock);
351
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200352 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300353 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
Johan Hedberga38528f2011-01-22 06:46:43 +0200355 kfree(rp);
356
357 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358}
359
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200360static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200361{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200366
Andre Guedesed3fa312012-07-24 15:03:46 -0300367 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300368 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500369 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
370 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300371 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 settings |= MGMT_SETTING_BREDR;
373 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700374
375 if (lmp_ssp_capable(hdev)) {
376 settings |= MGMT_SETTING_SSP;
377 settings |= MGMT_SETTING_HS;
378 }
Marcel Holtmann848566b2013-10-01 22:59:22 -0700379 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300381 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200382 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300383 settings |= MGMT_SETTING_ADVERTISING;
384 }
Johan 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
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300539static void create_eir(struct hci_dev *hdev, u8 *data)
540{
541 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 size_t name_len;
543
544 name_len = strlen(hdev->dev_name);
545
546 if (name_len > 0) {
547 /* EIR Data type */
548 if (name_len > 48) {
549 name_len = 48;
550 ptr[1] = EIR_NAME_SHORT;
551 } else
552 ptr[1] = EIR_NAME_COMPLETE;
553
554 /* EIR Data length */
555 ptr[0] = name_len + 1;
556
557 memcpy(ptr + 2, hdev->dev_name, name_len);
558
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300559 ptr += (name_len + 2);
560 }
561
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100562 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700563 ptr[0] = 2;
564 ptr[1] = EIR_TX_POWER;
565 ptr[2] = (u8) hdev->inq_tx_power;
566
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700567 ptr += 3;
568 }
569
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700570 if (hdev->devid_source > 0) {
571 ptr[0] = 9;
572 ptr[1] = EIR_DEVICE_ID;
573
574 put_unaligned_le16(hdev->devid_source, ptr + 2);
575 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
576 put_unaligned_le16(hdev->devid_product, ptr + 6);
577 put_unaligned_le16(hdev->devid_version, ptr + 8);
578
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700579 ptr += 10;
580 }
581
Johan Hedberg213202e2013-01-27 00:31:33 +0200582 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200583 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200584 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300585}
586
Johan Hedberg890ea892013-03-15 17:06:52 -0500587static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300588{
Johan Hedberg890ea892013-03-15 17:06:52 -0500589 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300590 struct hci_cp_write_eir cp;
591
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200592 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500593 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200594
Johan Hedberg976eb202012-10-24 21:12:01 +0300595 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500596 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300597
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200598 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500599 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300600
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200601 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500602 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300603
604 memset(&cp, 0, sizeof(cp));
605
606 create_eir(hdev, cp.data);
607
608 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500609 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300610
611 memcpy(hdev->eir, cp.data, sizeof(cp.data));
612
Johan Hedberg890ea892013-03-15 17:06:52 -0500613 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300614}
615
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200616static u8 get_service_classes(struct hci_dev *hdev)
617{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300618 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200619 u8 val = 0;
620
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300621 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200622 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200623
624 return val;
625}
626
Johan Hedberg890ea892013-03-15 17:06:52 -0500627static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200628{
Johan Hedberg890ea892013-03-15 17:06:52 -0500629 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200630 u8 cod[3];
631
632 BT_DBG("%s", hdev->name);
633
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200634 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500635 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200636
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200637 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500638 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200639
640 cod[0] = hdev->minor_class;
641 cod[1] = hdev->major_class;
642 cod[2] = get_service_classes(hdev);
643
644 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500645 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200646
Johan Hedberg890ea892013-03-15 17:06:52 -0500647 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200648}
649
Johan Hedberg7d785252011-12-15 00:47:39 +0200650static void service_cache_off(struct work_struct *work)
651{
652 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300653 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500654 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200655
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200656 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200657 return;
658
Johan Hedberg890ea892013-03-15 17:06:52 -0500659 hci_req_init(&req, hdev);
660
Johan Hedberg7d785252011-12-15 00:47:39 +0200661 hci_dev_lock(hdev);
662
Johan Hedberg890ea892013-03-15 17:06:52 -0500663 update_eir(&req);
664 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200665
666 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500667
668 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200669}
670
Johan Hedberg6a919082012-02-28 06:17:26 +0200671static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200672{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200673 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200674 return;
675
Johan Hedberg4f87da82012-03-02 19:55:56 +0200676 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200677
Johan Hedberg4f87da82012-03-02 19:55:56 +0200678 /* Non-mgmt controlled devices get this bit set
679 * implicitly so that pairing works for them, however
680 * for mgmt we require user-space to explicitly enable
681 * it
682 */
683 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200684}
685
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200686static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300687 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200688{
689 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200690
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200691 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200692
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300693 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200694
Johan Hedberg03811012010-12-08 00:21:06 +0200695 memset(&rp, 0, sizeof(rp));
696
Johan Hedberg03811012010-12-08 00:21:06 +0200697 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200698
699 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200700 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200701
702 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
703 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
704
705 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200706
707 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200708 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200709
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300710 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200711
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200712 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300713 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200714}
715
716static void mgmt_pending_free(struct pending_cmd *cmd)
717{
718 sock_put(cmd->sk);
719 kfree(cmd->param);
720 kfree(cmd);
721}
722
723static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300724 struct hci_dev *hdev, void *data,
725 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200726{
727 struct pending_cmd *cmd;
728
Andre Guedes12b94562012-06-07 19:05:45 -0300729 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200730 if (!cmd)
731 return NULL;
732
733 cmd->opcode = opcode;
734 cmd->index = hdev->id;
735
Andre Guedes12b94562012-06-07 19:05:45 -0300736 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200737 if (!cmd->param) {
738 kfree(cmd);
739 return NULL;
740 }
741
742 if (data)
743 memcpy(cmd->param, data, len);
744
745 cmd->sk = sk;
746 sock_hold(sk);
747
748 list_add(&cmd->list, &hdev->mgmt_pending);
749
750 return cmd;
751}
752
753static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300754 void (*cb)(struct pending_cmd *cmd,
755 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300756 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200757{
Andre Guedesa3d09352013-02-01 11:21:30 -0300758 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200759
Andre Guedesa3d09352013-02-01 11:21:30 -0300760 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200761 if (opcode > 0 && cmd->opcode != opcode)
762 continue;
763
764 cb(cmd, data);
765 }
766}
767
768static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
769{
770 struct pending_cmd *cmd;
771
772 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
773 if (cmd->opcode == opcode)
774 return cmd;
775 }
776
777 return NULL;
778}
779
780static void mgmt_pending_remove(struct pending_cmd *cmd)
781{
782 list_del(&cmd->list);
783 mgmt_pending_free(cmd);
784}
785
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200786static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200787{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200788 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200789
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200790 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300791 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200792}
793
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200794static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300795 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200796{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300797 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200798 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200799 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200800
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200801 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200802
Johan Hedberga7e80f22013-01-09 16:05:19 +0200803 if (cp->val != 0x00 && cp->val != 0x01)
804 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
805 MGMT_STATUS_INVALID_PARAMS);
806
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300807 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200808
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300809 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
810 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
811 MGMT_STATUS_BUSY);
812 goto failed;
813 }
814
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100815 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
816 cancel_delayed_work(&hdev->power_off);
817
818 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200819 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
820 data, len);
821 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100822 goto failed;
823 }
824 }
825
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200826 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200827 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200828 goto failed;
829 }
830
Johan Hedberg03811012010-12-08 00:21:06 +0200831 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
832 if (!cmd) {
833 err = -ENOMEM;
834 goto failed;
835 }
836
837 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200838 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200839 else
Johan Hedberg19202572013-01-14 22:33:51 +0200840 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200841
842 err = 0;
843
844failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300845 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200846 return err;
847}
848
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300849static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
850 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200851{
852 struct sk_buff *skb;
853 struct mgmt_hdr *hdr;
854
Andre Guedes790eff42012-06-07 19:05:46 -0300855 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200856 if (!skb)
857 return -ENOMEM;
858
859 hdr = (void *) skb_put(skb, sizeof(*hdr));
860 hdr->opcode = cpu_to_le16(event);
861 if (hdev)
862 hdr->index = cpu_to_le16(hdev->id);
863 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530864 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200865 hdr->len = cpu_to_le16(data_len);
866
867 if (data)
868 memcpy(skb_put(skb, data_len), data, data_len);
869
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100870 /* Time stamp */
871 __net_timestamp(skb);
872
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200873 hci_send_to_control(skb, skip_sk);
874 kfree_skb(skb);
875
876 return 0;
877}
878
879static int new_settings(struct hci_dev *hdev, struct sock *skip)
880{
881 __le32 ev;
882
883 ev = cpu_to_le32(get_current_settings(hdev));
884
885 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
886}
887
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300888struct cmd_lookup {
889 struct sock *sk;
890 struct hci_dev *hdev;
891 u8 mgmt_status;
892};
893
894static void settings_rsp(struct pending_cmd *cmd, void *data)
895{
896 struct cmd_lookup *match = data;
897
898 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
899
900 list_del(&cmd->list);
901
902 if (match->sk == NULL) {
903 match->sk = cmd->sk;
904 sock_hold(match->sk);
905 }
906
907 mgmt_pending_free(cmd);
908}
909
910static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
911{
912 u8 *status = data;
913
914 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
915 mgmt_pending_remove(cmd);
916}
917
Johan Hedberge6fe7982013-10-02 15:45:22 +0300918static u8 mgmt_bredr_support(struct hci_dev *hdev)
919{
920 if (!lmp_bredr_capable(hdev))
921 return MGMT_STATUS_NOT_SUPPORTED;
922 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
923 return MGMT_STATUS_REJECTED;
924 else
925 return MGMT_STATUS_SUCCESS;
926}
927
928static u8 mgmt_le_support(struct hci_dev *hdev)
929{
930 if (!lmp_le_capable(hdev))
931 return MGMT_STATUS_NOT_SUPPORTED;
932 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
933 return MGMT_STATUS_REJECTED;
934 else
935 return MGMT_STATUS_SUCCESS;
936}
937
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200938static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300939 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200940{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300941 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200942 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200943 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +0300944 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +0200945 int err;
946
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200947 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200948
Johan Hedberge6fe7982013-10-02 15:45:22 +0300949 status = mgmt_bredr_support(hdev);
950 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +0300951 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +0300952 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +0300953
Johan Hedberga7e80f22013-01-09 16:05:19 +0200954 if (cp->val != 0x00 && cp->val != 0x01)
955 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
956 MGMT_STATUS_INVALID_PARAMS);
957
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700958 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100959 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200960 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300961 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200962
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300963 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200964
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200965 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200966 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300967 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200968 goto failed;
969 }
970
971 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300972 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200973 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300974 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200975 goto failed;
976 }
977
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200978 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200979 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300980 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200981 goto failed;
982 }
983
984 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200985 bool changed = false;
986
987 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
988 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
989 changed = true;
990 }
991
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200992 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200993 if (err < 0)
994 goto failed;
995
996 if (changed)
997 err = new_settings(hdev, sk);
998
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200999 goto failed;
1000 }
1001
1002 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001003 if (hdev->discov_timeout > 0) {
1004 cancel_delayed_work(&hdev->discov_off);
1005 hdev->discov_timeout = 0;
1006 }
1007
1008 if (cp->val && timeout > 0) {
1009 hdev->discov_timeout = timeout;
1010 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1011 msecs_to_jiffies(hdev->discov_timeout * 1000));
1012 }
1013
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001014 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001015 goto failed;
1016 }
1017
1018 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1019 if (!cmd) {
1020 err = -ENOMEM;
1021 goto failed;
1022 }
1023
1024 scan = SCAN_PAGE;
1025
1026 if (cp->val)
1027 scan |= SCAN_INQUIRY;
1028 else
1029 cancel_delayed_work(&hdev->discov_off);
1030
1031 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1032 if (err < 0)
1033 mgmt_pending_remove(cmd);
1034
Johan Hedberg03811012010-12-08 00:21:06 +02001035 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001036 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001037
1038failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001039 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001040 return err;
1041}
1042
Johan Hedberg406d7802013-03-15 17:07:09 -05001043static void write_fast_connectable(struct hci_request *req, bool enable)
1044{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001045 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001046 struct hci_cp_write_page_scan_activity acp;
1047 u8 type;
1048
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001049 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1050 return;
1051
Johan Hedberg406d7802013-03-15 17:07:09 -05001052 if (enable) {
1053 type = PAGE_SCAN_TYPE_INTERLACED;
1054
1055 /* 160 msec page scan interval */
1056 acp.interval = __constant_cpu_to_le16(0x0100);
1057 } else {
1058 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1059
1060 /* default 1.28 sec page scan */
1061 acp.interval = __constant_cpu_to_le16(0x0800);
1062 }
1063
1064 acp.window = __constant_cpu_to_le16(0x0012);
1065
Johan Hedbergbd98b992013-03-15 17:07:13 -05001066 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1067 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1068 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1069 sizeof(acp), &acp);
1070
1071 if (hdev->page_scan_type != type)
1072 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001073}
1074
Johan Hedberg2b76f452013-03-15 17:07:04 -05001075static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1076{
1077 struct pending_cmd *cmd;
1078
1079 BT_DBG("status 0x%02x", status);
1080
1081 hci_dev_lock(hdev);
1082
1083 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1084 if (!cmd)
1085 goto unlock;
1086
1087 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1088
1089 mgmt_pending_remove(cmd);
1090
1091unlock:
1092 hci_dev_unlock(hdev);
1093}
1094
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001095static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001096 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001097{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001098 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001099 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001100 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001101 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001102 int err;
1103
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001104 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001105
Johan Hedberge6fe7982013-10-02 15:45:22 +03001106 status = mgmt_bredr_support(hdev);
1107 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001108 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001109 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001110
Johan Hedberga7e80f22013-01-09 16:05:19 +02001111 if (cp->val != 0x00 && cp->val != 0x01)
1112 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1113 MGMT_STATUS_INVALID_PARAMS);
1114
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001115 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001116
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001117 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001118 bool changed = false;
1119
1120 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1121 changed = true;
1122
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001123 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001124 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001125 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001126 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1127 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1128 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001129
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001130 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001131 if (err < 0)
1132 goto failed;
1133
1134 if (changed)
1135 err = new_settings(hdev, sk);
1136
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001137 goto failed;
1138 }
1139
1140 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001141 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001142 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001143 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001144 goto failed;
1145 }
1146
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001147 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001148 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001149 goto failed;
1150 }
1151
1152 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1153 if (!cmd) {
1154 err = -ENOMEM;
1155 goto failed;
1156 }
1157
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001158 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001159 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001160 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001161 scan = 0;
1162
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001163 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001164 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001165 cancel_delayed_work(&hdev->discov_off);
1166 }
1167
Johan Hedberg2b76f452013-03-15 17:07:04 -05001168 hci_req_init(&req, hdev);
1169
1170 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1171
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001172 /* If we're going from non-connectable to connectable or
1173 * vice-versa when fast connectable is enabled ensure that fast
1174 * connectable gets disabled. write_fast_connectable won't do
1175 * anything if the page scan parameters are already what they
1176 * should be.
1177 */
1178 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001179 write_fast_connectable(&req, false);
1180
Johan Hedberg2b76f452013-03-15 17:07:04 -05001181 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001182 if (err < 0)
1183 mgmt_pending_remove(cmd);
1184
1185failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001186 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001187 return err;
1188}
1189
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001190static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001191 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001192{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001193 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001194 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001195 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001196
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001197 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001198
Johan Hedberga7e80f22013-01-09 16:05:19 +02001199 if (cp->val != 0x00 && cp->val != 0x01)
1200 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1201 MGMT_STATUS_INVALID_PARAMS);
1202
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001203 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001204
1205 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001206 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001208 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001209
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001210 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001211 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001212 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001213
Marcel Holtmann55594352013-10-06 16:11:57 -07001214 if (changed)
1215 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001216
Marcel Holtmann55594352013-10-06 16:11:57 -07001217unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001218 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001219 return err;
1220}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001221
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001222static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1223 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001224{
1225 struct mgmt_mode *cp = data;
1226 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001227 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001228 int err;
1229
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001230 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001231
Johan Hedberge6fe7982013-10-02 15:45:22 +03001232 status = mgmt_bredr_support(hdev);
1233 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001234 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001235 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001236
Johan Hedberga7e80f22013-01-09 16:05:19 +02001237 if (cp->val != 0x00 && cp->val != 0x01)
1238 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1239 MGMT_STATUS_INVALID_PARAMS);
1240
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001241 hci_dev_lock(hdev);
1242
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001243 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001244 bool changed = false;
1245
1246 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001247 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001248 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1249 changed = true;
1250 }
1251
1252 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1253 if (err < 0)
1254 goto failed;
1255
1256 if (changed)
1257 err = new_settings(hdev, sk);
1258
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001259 goto failed;
1260 }
1261
1262 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001263 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001264 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001265 goto failed;
1266 }
1267
1268 val = !!cp->val;
1269
1270 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1271 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1272 goto failed;
1273 }
1274
1275 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1276 if (!cmd) {
1277 err = -ENOMEM;
1278 goto failed;
1279 }
1280
1281 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1282 if (err < 0) {
1283 mgmt_pending_remove(cmd);
1284 goto failed;
1285 }
1286
1287failed:
1288 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001289 return err;
1290}
1291
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001292static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001293{
1294 struct mgmt_mode *cp = data;
1295 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001296 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001297 int err;
1298
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001299 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001300
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001301 status = mgmt_bredr_support(hdev);
1302 if (status)
1303 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1304
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001305 if (!lmp_ssp_capable(hdev))
1306 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1307 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001308
Johan Hedberga7e80f22013-01-09 16:05:19 +02001309 if (cp->val != 0x00 && cp->val != 0x01)
1310 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1311 MGMT_STATUS_INVALID_PARAMS);
1312
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001313 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001314
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001315 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001316 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001317
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001318 if (cp->val) {
1319 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1320 &hdev->dev_flags);
1321 } else {
1322 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1323 &hdev->dev_flags);
1324 if (!changed)
1325 changed = test_and_clear_bit(HCI_HS_ENABLED,
1326 &hdev->dev_flags);
1327 else
1328 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001329 }
1330
1331 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1332 if (err < 0)
1333 goto failed;
1334
1335 if (changed)
1336 err = new_settings(hdev, sk);
1337
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001338 goto failed;
1339 }
1340
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001341 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1342 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001343 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1344 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001345 goto failed;
1346 }
1347
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001348 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001349 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1350 goto failed;
1351 }
1352
1353 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1354 if (!cmd) {
1355 err = -ENOMEM;
1356 goto failed;
1357 }
1358
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001359 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001360 if (err < 0) {
1361 mgmt_pending_remove(cmd);
1362 goto failed;
1363 }
1364
1365failed:
1366 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001367 return err;
1368}
1369
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001370static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001371{
1372 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001373 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001374 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001375 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001376
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001377 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001378
Johan Hedberge6fe7982013-10-02 15:45:22 +03001379 status = mgmt_bredr_support(hdev);
1380 if (status)
1381 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001382
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001383 if (!lmp_ssp_capable(hdev))
1384 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1385 MGMT_STATUS_NOT_SUPPORTED);
1386
1387 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1388 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1389 MGMT_STATUS_REJECTED);
1390
Johan Hedberga7e80f22013-01-09 16:05:19 +02001391 if (cp->val != 0x00 && cp->val != 0x01)
1392 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1393 MGMT_STATUS_INVALID_PARAMS);
1394
Marcel Holtmannee392692013-10-01 22:59:23 -07001395 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001396
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001397 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001398 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001399 } else {
1400 if (hdev_is_powered(hdev)) {
1401 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1402 MGMT_STATUS_REJECTED);
1403 goto unlock;
1404 }
1405
Marcel Holtmannee392692013-10-01 22:59:23 -07001406 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001407 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001408
1409 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1410 if (err < 0)
1411 goto unlock;
1412
1413 if (changed)
1414 err = new_settings(hdev, sk);
1415
1416unlock:
1417 hci_dev_unlock(hdev);
1418 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001419}
1420
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001421static void enable_advertising(struct hci_request *req)
1422{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001423 struct hci_dev *hdev = req->hdev;
1424 struct hci_cp_le_set_adv_param cp;
1425 u8 enable = 0x01;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001426
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001427 memset(&cp, 0, sizeof(cp));
1428 cp.min_interval = __constant_cpu_to_le16(0x0800);
1429 cp.max_interval = __constant_cpu_to_le16(0x0800);
1430 cp.type = LE_ADV_IND;
1431 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1432 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1433 else
1434 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1435 cp.channel_map = 0x07;
1436
1437 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1438
1439 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001440}
1441
1442static void disable_advertising(struct hci_request *req)
1443{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001444 u8 enable = 0x00;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001445
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001446 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001447}
1448
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001449static void le_enable_complete(struct hci_dev *hdev, u8 status)
1450{
1451 struct cmd_lookup match = { NULL, hdev };
1452
1453 if (status) {
1454 u8 mgmt_err = mgmt_status(status);
1455
1456 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1457 &mgmt_err);
1458 return;
1459 }
1460
1461 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1462
1463 new_settings(hdev, match.sk);
1464
1465 if (match.sk)
1466 sock_put(match.sk);
1467}
1468
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001469static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001470{
1471 struct mgmt_mode *cp = data;
1472 struct hci_cp_write_le_host_supported hci_cp;
1473 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001474 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001475 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001476 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001477
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001478 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001479
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001480 if (!lmp_le_capable(hdev))
1481 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1482 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001483
Johan Hedberga7e80f22013-01-09 16:05:19 +02001484 if (cp->val != 0x00 && cp->val != 0x01)
1485 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1486 MGMT_STATUS_INVALID_PARAMS);
1487
Johan Hedbergc73eee92013-04-19 18:35:21 +03001488 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001489 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001490 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1491 MGMT_STATUS_REJECTED);
1492
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001493 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001494
1495 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001496 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001497
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001498 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001499 bool changed = false;
1500
1501 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1502 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1503 changed = true;
1504 }
1505
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001506 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1507 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001508 changed = true;
1509 }
1510
Johan Hedberg06199cf2012-02-22 16:37:11 +02001511 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1512 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001513 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001514
1515 if (changed)
1516 err = new_settings(hdev, sk);
1517
Johan Hedberg1de028c2012-02-29 19:55:35 -08001518 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001519 }
1520
Johan Hedberg4375f102013-09-25 13:26:10 +03001521 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1522 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001523 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001524 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001525 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001526 }
1527
1528 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1529 if (!cmd) {
1530 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001531 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001532 }
1533
1534 memset(&hci_cp, 0, sizeof(hci_cp));
1535
1536 if (val) {
1537 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001538 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001539 }
1540
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001541 hci_req_init(&req, hdev);
1542
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001543 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1544 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001545
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001546 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1547 &hci_cp);
1548
1549 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301550 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001551 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001552
Johan Hedberg1de028c2012-02-29 19:55:35 -08001553unlock:
1554 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001555 return err;
1556}
1557
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001558/* This is a helper function to test for pending mgmt commands that can
1559 * cause CoD or EIR HCI commands. We can only allow one such pending
1560 * mgmt command at a time since otherwise we cannot easily track what
1561 * the current values are, will be, and based on that calculate if a new
1562 * HCI command needs to be sent and if yes with what value.
1563 */
1564static bool pending_eir_or_class(struct hci_dev *hdev)
1565{
1566 struct pending_cmd *cmd;
1567
1568 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1569 switch (cmd->opcode) {
1570 case MGMT_OP_ADD_UUID:
1571 case MGMT_OP_REMOVE_UUID:
1572 case MGMT_OP_SET_DEV_CLASS:
1573 case MGMT_OP_SET_POWERED:
1574 return true;
1575 }
1576 }
1577
1578 return false;
1579}
1580
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001581static const u8 bluetooth_base_uuid[] = {
1582 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1583 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1584};
1585
1586static u8 get_uuid_size(const u8 *uuid)
1587{
1588 u32 val;
1589
1590 if (memcmp(uuid, bluetooth_base_uuid, 12))
1591 return 128;
1592
1593 val = get_unaligned_le32(&uuid[12]);
1594 if (val > 0xffff)
1595 return 32;
1596
1597 return 16;
1598}
1599
Johan Hedberg92da6092013-03-15 17:06:55 -05001600static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1601{
1602 struct pending_cmd *cmd;
1603
1604 hci_dev_lock(hdev);
1605
1606 cmd = mgmt_pending_find(mgmt_op, hdev);
1607 if (!cmd)
1608 goto unlock;
1609
1610 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1611 hdev->dev_class, 3);
1612
1613 mgmt_pending_remove(cmd);
1614
1615unlock:
1616 hci_dev_unlock(hdev);
1617}
1618
1619static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1620{
1621 BT_DBG("status 0x%02x", status);
1622
1623 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1624}
1625
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001626static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001627{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001628 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001629 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001630 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001631 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001632 int err;
1633
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001634 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001635
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001636 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001637
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001638 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001639 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001640 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001641 goto failed;
1642 }
1643
Andre Guedes92c4c202012-06-07 19:05:44 -03001644 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001645 if (!uuid) {
1646 err = -ENOMEM;
1647 goto failed;
1648 }
1649
1650 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001651 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001652 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001653
Johan Hedbergde66aa62013-01-27 00:31:27 +02001654 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001655
Johan Hedberg890ea892013-03-15 17:06:52 -05001656 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001657
Johan Hedberg890ea892013-03-15 17:06:52 -05001658 update_class(&req);
1659 update_eir(&req);
1660
Johan Hedberg92da6092013-03-15 17:06:55 -05001661 err = hci_req_run(&req, add_uuid_complete);
1662 if (err < 0) {
1663 if (err != -ENODATA)
1664 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001665
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001666 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001667 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001668 goto failed;
1669 }
1670
1671 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001672 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001673 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001674 goto failed;
1675 }
1676
1677 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001678
1679failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001680 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001681 return err;
1682}
1683
Johan Hedberg24b78d02012-02-23 23:24:30 +02001684static bool enable_service_cache(struct hci_dev *hdev)
1685{
1686 if (!hdev_is_powered(hdev))
1687 return false;
1688
1689 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001690 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1691 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001692 return true;
1693 }
1694
1695 return false;
1696}
1697
Johan Hedberg92da6092013-03-15 17:06:55 -05001698static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1699{
1700 BT_DBG("status 0x%02x", status);
1701
1702 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1703}
1704
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001705static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001706 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001707{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001708 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001709 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001710 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001711 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 -05001712 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001713 int err, found;
1714
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001715 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001716
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001717 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001718
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001719 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001720 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001721 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001722 goto unlock;
1723 }
1724
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001725 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1726 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001727
Johan Hedberg24b78d02012-02-23 23:24:30 +02001728 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001729 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001730 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001731 goto unlock;
1732 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001733
Johan Hedberg9246a862012-02-23 21:33:16 +02001734 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001735 }
1736
1737 found = 0;
1738
Johan Hedberg056341c2013-01-27 00:31:30 +02001739 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001740 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1741 continue;
1742
1743 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001744 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001745 found++;
1746 }
1747
1748 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001749 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001751 goto unlock;
1752 }
1753
Johan Hedberg9246a862012-02-23 21:33:16 +02001754update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001755 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001756
Johan Hedberg890ea892013-03-15 17:06:52 -05001757 update_class(&req);
1758 update_eir(&req);
1759
Johan Hedberg92da6092013-03-15 17:06:55 -05001760 err = hci_req_run(&req, remove_uuid_complete);
1761 if (err < 0) {
1762 if (err != -ENODATA)
1763 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001764
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001765 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001766 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001767 goto unlock;
1768 }
1769
1770 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001771 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001772 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001773 goto unlock;
1774 }
1775
1776 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001777
1778unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001779 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001780 return err;
1781}
1782
Johan Hedberg92da6092013-03-15 17:06:55 -05001783static void set_class_complete(struct hci_dev *hdev, u8 status)
1784{
1785 BT_DBG("status 0x%02x", status);
1786
1787 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1788}
1789
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001790static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001791 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001792{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001793 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001794 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001795 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001796 int err;
1797
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001798 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001799
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001800 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001801 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1802 MGMT_STATUS_NOT_SUPPORTED);
1803
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001804 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001805
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001806 if (pending_eir_or_class(hdev)) {
1807 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1808 MGMT_STATUS_BUSY);
1809 goto unlock;
1810 }
1811
1812 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1813 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1814 MGMT_STATUS_INVALID_PARAMS);
1815 goto unlock;
1816 }
1817
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001818 hdev->major_class = cp->major;
1819 hdev->minor_class = cp->minor;
1820
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001821 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001822 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001823 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001824 goto unlock;
1825 }
1826
Johan Hedberg890ea892013-03-15 17:06:52 -05001827 hci_req_init(&req, hdev);
1828
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001829 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001830 hci_dev_unlock(hdev);
1831 cancel_delayed_work_sync(&hdev->service_cache);
1832 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001833 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001834 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001835
Johan Hedberg890ea892013-03-15 17:06:52 -05001836 update_class(&req);
1837
Johan Hedberg92da6092013-03-15 17:06:55 -05001838 err = hci_req_run(&req, set_class_complete);
1839 if (err < 0) {
1840 if (err != -ENODATA)
1841 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001842
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001843 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001844 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001845 goto unlock;
1846 }
1847
1848 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001849 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001850 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001851 goto unlock;
1852 }
1853
1854 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001855
Johan Hedbergb5235a62012-02-21 14:32:24 +02001856unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001857 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001858 return err;
1859}
1860
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001861static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001862 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001863{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001864 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001865 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001866 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001867
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001868 BT_DBG("request for %s", hdev->name);
1869
1870 if (!lmp_bredr_capable(hdev))
1871 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1872 MGMT_STATUS_NOT_SUPPORTED);
1873
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001874 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001875
Johan Hedberg86742e12011-11-07 23:13:38 +02001876 expected_len = sizeof(*cp) + key_count *
1877 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001878 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001879 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001880 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001881 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001882 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001883 }
1884
Johan Hedberg4ae143012013-01-20 14:27:13 +02001885 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1886 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1887 MGMT_STATUS_INVALID_PARAMS);
1888
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001889 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001890 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001891
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001892 for (i = 0; i < key_count; i++) {
1893 struct mgmt_link_key_info *key = &cp->keys[i];
1894
1895 if (key->addr.type != BDADDR_BREDR)
1896 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1897 MGMT_STATUS_INVALID_PARAMS);
1898 }
1899
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001900 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001901
1902 hci_link_keys_clear(hdev);
1903
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001904 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001905 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001906 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001907 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001908
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001909 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001910 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001911
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001912 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001913 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001914 }
1915
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001916 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001917
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001918 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001919
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001920 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001921}
1922
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001923static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001924 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001925{
1926 struct mgmt_ev_device_unpaired ev;
1927
1928 bacpy(&ev.addr.bdaddr, bdaddr);
1929 ev.addr.type = addr_type;
1930
1931 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001932 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001933}
1934
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001935static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001936 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001937{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001938 struct mgmt_cp_unpair_device *cp = data;
1939 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001940 struct hci_cp_disconnect dc;
1941 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001942 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001943 int err;
1944
Johan Hedberga8a1d192011-11-10 15:54:38 +02001945 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001946 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1947 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001948
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001949 if (!bdaddr_type_is_valid(cp->addr.type))
1950 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1951 MGMT_STATUS_INVALID_PARAMS,
1952 &rp, sizeof(rp));
1953
Johan Hedberg118da702013-01-20 14:27:20 +02001954 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1955 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1956 MGMT_STATUS_INVALID_PARAMS,
1957 &rp, sizeof(rp));
1958
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001959 hci_dev_lock(hdev);
1960
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001961 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001962 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001963 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001964 goto unlock;
1965 }
1966
Andre Guedes591f47f2012-04-24 21:02:49 -03001967 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001968 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1969 else
1970 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001971
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001972 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001973 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001974 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001975 goto unlock;
1976 }
1977
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001978 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001979 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001980 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001981 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001982 else
1983 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001984 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001985 } else {
1986 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001987 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001988
Johan Hedberga8a1d192011-11-10 15:54:38 +02001989 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001990 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001991 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001992 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001993 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001994 }
1995
Johan Hedberg124f6e32012-02-09 13:50:12 +02001996 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001997 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001998 if (!cmd) {
1999 err = -ENOMEM;
2000 goto unlock;
2001 }
2002
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002003 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002004 dc.reason = 0x13; /* Remote User Terminated Connection */
2005 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2006 if (err < 0)
2007 mgmt_pending_remove(cmd);
2008
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002009unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002010 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002011 return err;
2012}
2013
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002014static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002015 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002016{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002017 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002018 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002019 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002020 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002021 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002022 int err;
2023
2024 BT_DBG("");
2025
Johan Hedberg06a63b12013-01-20 14:27:21 +02002026 memset(&rp, 0, sizeof(rp));
2027 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2028 rp.addr.type = cp->addr.type;
2029
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002030 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002031 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2032 MGMT_STATUS_INVALID_PARAMS,
2033 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002034
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002035 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002036
2037 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002038 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2039 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002040 goto failed;
2041 }
2042
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002043 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002044 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2045 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002046 goto failed;
2047 }
2048
Andre Guedes591f47f2012-04-24 21:02:49 -03002049 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002050 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2051 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002052 else
2053 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002054
Vishal Agarwalf9607272012-06-13 05:32:43 +05302055 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002056 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2057 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002058 goto failed;
2059 }
2060
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002061 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002062 if (!cmd) {
2063 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002064 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002065 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002066
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002067 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002068 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002069
2070 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2071 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002072 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002073
2074failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002075 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002076 return err;
2077}
2078
Andre Guedes57c14772012-04-24 21:02:50 -03002079static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002080{
2081 switch (link_type) {
2082 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002083 switch (addr_type) {
2084 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002085 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002086
Johan Hedberg48264f02011-11-09 13:58:58 +02002087 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002088 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002089 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002090 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002091
Johan Hedberg4c659c32011-11-07 23:13:39 +02002092 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002093 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002094 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002095 }
2096}
2097
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002098static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2099 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002100{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002101 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002102 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002103 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002104 int err;
2105 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002106
2107 BT_DBG("");
2108
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002109 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002110
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002111 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002112 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002113 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002114 goto unlock;
2115 }
2116
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002117 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002118 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2119 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002120 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002121 }
2122
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002123 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002124 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002125 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002126 err = -ENOMEM;
2127 goto unlock;
2128 }
2129
Johan Hedberg2784eb42011-01-21 13:56:35 +02002130 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002131 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002132 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2133 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002134 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002135 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002136 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002137 continue;
2138 i++;
2139 }
2140
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002141 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002142
Johan Hedberg4c659c32011-11-07 23:13:39 +02002143 /* Recalculate length in case of filtered SCO connections, etc */
2144 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002146 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002147 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002148
Johan Hedberga38528f2011-01-22 06:46:43 +02002149 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002150
2151unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002152 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002153 return err;
2154}
2155
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002156static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002157 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002158{
2159 struct pending_cmd *cmd;
2160 int err;
2161
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002162 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002163 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002164 if (!cmd)
2165 return -ENOMEM;
2166
Johan Hedbergd8457692012-02-17 14:24:57 +02002167 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002168 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002169 if (err < 0)
2170 mgmt_pending_remove(cmd);
2171
2172 return err;
2173}
2174
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002175static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002176 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002177{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002178 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002179 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002180 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002181 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002182 int err;
2183
2184 BT_DBG("");
2185
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002186 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002187
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002188 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002189 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002190 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002191 goto failed;
2192 }
2193
Johan Hedbergd8457692012-02-17 14:24:57 +02002194 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002195 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002196 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002197 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002198 goto failed;
2199 }
2200
2201 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002202 struct mgmt_cp_pin_code_neg_reply ncp;
2203
2204 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002205
2206 BT_ERR("PIN code is not 16 bytes long");
2207
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002208 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002209 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002210 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002211 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002212
2213 goto failed;
2214 }
2215
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002216 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002217 if (!cmd) {
2218 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002219 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002220 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002221
Johan Hedbergd8457692012-02-17 14:24:57 +02002222 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002223 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002224 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002225
2226 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2227 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002228 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002229
2230failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002231 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002232 return err;
2233}
2234
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002235static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2236 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002237{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002238 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002239
2240 BT_DBG("");
2241
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002242 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002243
2244 hdev->io_capability = cp->io_capability;
2245
2246 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002247 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002248
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002249 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002250
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002251 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2252 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002253}
2254
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002255static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002256{
2257 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002258 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002259
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002260 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002261 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2262 continue;
2263
Johan Hedberge9a416b2011-02-19 12:05:56 -03002264 if (cmd->user_data != conn)
2265 continue;
2266
2267 return cmd;
2268 }
2269
2270 return NULL;
2271}
2272
2273static void pairing_complete(struct pending_cmd *cmd, u8 status)
2274{
2275 struct mgmt_rp_pair_device rp;
2276 struct hci_conn *conn = cmd->user_data;
2277
Johan Hedbergba4e5642011-11-11 00:07:34 +02002278 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002279 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002280
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002281 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002282 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002283
2284 /* So we don't get further callbacks for this connection */
2285 conn->connect_cfm_cb = NULL;
2286 conn->security_cfm_cb = NULL;
2287 conn->disconn_cfm_cb = NULL;
2288
David Herrmann76a68ba2013-04-06 20:28:37 +02002289 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002290
Johan Hedberga664b5b2011-02-19 12:06:02 -03002291 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002292}
2293
2294static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2295{
2296 struct pending_cmd *cmd;
2297
2298 BT_DBG("status %u", status);
2299
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002300 cmd = find_pairing(conn);
2301 if (!cmd)
2302 BT_DBG("Unable to find a pending command");
2303 else
Johan Hedberge2113262012-02-18 15:20:03 +02002304 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002305}
2306
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302307static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2308{
2309 struct pending_cmd *cmd;
2310
2311 BT_DBG("status %u", status);
2312
2313 if (!status)
2314 return;
2315
2316 cmd = find_pairing(conn);
2317 if (!cmd)
2318 BT_DBG("Unable to find a pending command");
2319 else
2320 pairing_complete(cmd, mgmt_status(status));
2321}
2322
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002323static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002324 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002325{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002326 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002327 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002328 struct pending_cmd *cmd;
2329 u8 sec_level, auth_type;
2330 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002331 int err;
2332
2333 BT_DBG("");
2334
Szymon Jancf950a30e2013-01-18 12:48:07 +01002335 memset(&rp, 0, sizeof(rp));
2336 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2337 rp.addr.type = cp->addr.type;
2338
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002339 if (!bdaddr_type_is_valid(cp->addr.type))
2340 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2341 MGMT_STATUS_INVALID_PARAMS,
2342 &rp, sizeof(rp));
2343
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002344 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002345
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002346 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002347 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2348 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002349 goto unlock;
2350 }
2351
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002352 sec_level = BT_SECURITY_MEDIUM;
2353 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002354 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002355 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002356 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002357
Andre Guedes591f47f2012-04-24 21:02:49 -03002358 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002359 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2360 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002361 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002362 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2363 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002364
Ville Tervo30e76272011-02-22 16:10:53 -03002365 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002366 int status;
2367
2368 if (PTR_ERR(conn) == -EBUSY)
2369 status = MGMT_STATUS_BUSY;
2370 else
2371 status = MGMT_STATUS_CONNECT_FAILED;
2372
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002373 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002374 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002375 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002376 goto unlock;
2377 }
2378
2379 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002380 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002381 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002382 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002383 goto unlock;
2384 }
2385
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002386 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002387 if (!cmd) {
2388 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002389 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002390 goto unlock;
2391 }
2392
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002393 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002394 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002395 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302396 else
2397 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002398
Johan Hedberge9a416b2011-02-19 12:05:56 -03002399 conn->security_cfm_cb = pairing_complete_cb;
2400 conn->disconn_cfm_cb = pairing_complete_cb;
2401 conn->io_capability = cp->io_cap;
2402 cmd->user_data = conn;
2403
2404 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002405 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002406 pairing_complete(cmd, 0);
2407
2408 err = 0;
2409
2410unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002411 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002412 return err;
2413}
2414
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002415static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2416 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002417{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002418 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002419 struct pending_cmd *cmd;
2420 struct hci_conn *conn;
2421 int err;
2422
2423 BT_DBG("");
2424
Johan Hedberg28424702012-02-02 04:02:29 +02002425 hci_dev_lock(hdev);
2426
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002427 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002428 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002429 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002430 goto unlock;
2431 }
2432
Johan Hedberg28424702012-02-02 04:02:29 +02002433 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2434 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002435 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002436 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002437 goto unlock;
2438 }
2439
2440 conn = cmd->user_data;
2441
2442 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002443 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002444 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002445 goto unlock;
2446 }
2447
2448 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2449
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002450 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002451 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002452unlock:
2453 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002454 return err;
2455}
2456
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002457static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002458 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002459 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002460{
Johan Hedberga5c29682011-02-19 12:05:57 -03002461 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002462 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002463 int err;
2464
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002465 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002466
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002467 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002468 err = cmd_complete(sk, hdev->id, mgmt_op,
2469 MGMT_STATUS_NOT_POWERED, addr,
2470 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002471 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002472 }
2473
Johan Hedberg1707c602013-03-15 17:07:15 -05002474 if (addr->type == BDADDR_BREDR)
2475 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002476 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002477 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002478
Johan Hedberg272d90d2012-02-09 15:26:12 +02002479 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002480 err = cmd_complete(sk, hdev->id, mgmt_op,
2481 MGMT_STATUS_NOT_CONNECTED, addr,
2482 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002483 goto done;
2484 }
2485
Johan Hedberg1707c602013-03-15 17:07:15 -05002486 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002487 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002488 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002489
Brian Gix5fe57d92011-12-21 16:12:13 -08002490 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002491 err = cmd_complete(sk, hdev->id, mgmt_op,
2492 MGMT_STATUS_SUCCESS, addr,
2493 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002494 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002495 err = cmd_complete(sk, hdev->id, mgmt_op,
2496 MGMT_STATUS_FAILED, addr,
2497 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002498
Brian Gix47c15e22011-11-16 13:53:14 -08002499 goto done;
2500 }
2501
Johan Hedberg1707c602013-03-15 17:07:15 -05002502 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002503 if (!cmd) {
2504 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002505 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002506 }
2507
Brian Gix0df4c182011-11-16 13:53:13 -08002508 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002509 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2510 struct hci_cp_user_passkey_reply cp;
2511
Johan Hedberg1707c602013-03-15 17:07:15 -05002512 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002513 cp.passkey = passkey;
2514 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2515 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002516 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2517 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002518
Johan Hedberga664b5b2011-02-19 12:06:02 -03002519 if (err < 0)
2520 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002521
Brian Gix0df4c182011-11-16 13:53:13 -08002522done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002523 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002524 return err;
2525}
2526
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302527static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2528 void *data, u16 len)
2529{
2530 struct mgmt_cp_pin_code_neg_reply *cp = data;
2531
2532 BT_DBG("");
2533
Johan Hedberg1707c602013-03-15 17:07:15 -05002534 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302535 MGMT_OP_PIN_CODE_NEG_REPLY,
2536 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2537}
2538
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002539static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2540 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002541{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002542 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002543
2544 BT_DBG("");
2545
2546 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002547 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002548 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002549
Johan Hedberg1707c602013-03-15 17:07:15 -05002550 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002551 MGMT_OP_USER_CONFIRM_REPLY,
2552 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002553}
2554
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002555static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002556 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002557{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002558 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002559
2560 BT_DBG("");
2561
Johan Hedberg1707c602013-03-15 17:07:15 -05002562 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002563 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2564 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002565}
2566
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002567static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2568 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002569{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002570 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002571
2572 BT_DBG("");
2573
Johan Hedberg1707c602013-03-15 17:07:15 -05002574 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002575 MGMT_OP_USER_PASSKEY_REPLY,
2576 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002577}
2578
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002579static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002580 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002581{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002582 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002583
2584 BT_DBG("");
2585
Johan Hedberg1707c602013-03-15 17:07:15 -05002586 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002587 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2588 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002589}
2590
Johan Hedberg13928972013-03-15 17:07:00 -05002591static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002592{
Johan Hedberg13928972013-03-15 17:07:00 -05002593 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002594 struct hci_cp_write_local_name cp;
2595
Johan Hedberg13928972013-03-15 17:07:00 -05002596 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002597
Johan Hedberg890ea892013-03-15 17:06:52 -05002598 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002599}
2600
Johan Hedberg13928972013-03-15 17:07:00 -05002601static void set_name_complete(struct hci_dev *hdev, u8 status)
2602{
2603 struct mgmt_cp_set_local_name *cp;
2604 struct pending_cmd *cmd;
2605
2606 BT_DBG("status 0x%02x", status);
2607
2608 hci_dev_lock(hdev);
2609
2610 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2611 if (!cmd)
2612 goto unlock;
2613
2614 cp = cmd->param;
2615
2616 if (status)
2617 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2618 mgmt_status(status));
2619 else
2620 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2621 cp, sizeof(*cp));
2622
2623 mgmt_pending_remove(cmd);
2624
2625unlock:
2626 hci_dev_unlock(hdev);
2627}
2628
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002629static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002630 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002631{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002632 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002633 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002634 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002635 int err;
2636
2637 BT_DBG("");
2638
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002639 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002640
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002641 /* If the old values are the same as the new ones just return a
2642 * direct command complete event.
2643 */
2644 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2645 !memcmp(hdev->short_name, cp->short_name,
2646 sizeof(hdev->short_name))) {
2647 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2648 data, len);
2649 goto failed;
2650 }
2651
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002652 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002653
Johan Hedbergb5235a62012-02-21 14:32:24 +02002654 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002655 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002656
2657 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002658 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002659 if (err < 0)
2660 goto failed;
2661
2662 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002663 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002664
Johan Hedbergb5235a62012-02-21 14:32:24 +02002665 goto failed;
2666 }
2667
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002668 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002669 if (!cmd) {
2670 err = -ENOMEM;
2671 goto failed;
2672 }
2673
Johan Hedberg13928972013-03-15 17:07:00 -05002674 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2675
Johan Hedberg890ea892013-03-15 17:06:52 -05002676 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002677
2678 if (lmp_bredr_capable(hdev)) {
2679 update_name(&req);
2680 update_eir(&req);
2681 }
2682
2683 if (lmp_le_capable(hdev))
2684 hci_update_ad(&req);
2685
Johan Hedberg13928972013-03-15 17:07:00 -05002686 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002687 if (err < 0)
2688 mgmt_pending_remove(cmd);
2689
2690failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002691 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002692 return err;
2693}
2694
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002695static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002696 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002697{
Szymon Jancc35938b2011-03-22 13:12:21 +01002698 struct pending_cmd *cmd;
2699 int err;
2700
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002701 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002702
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002703 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002704
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002705 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002706 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002707 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002708 goto unlock;
2709 }
2710
Andre Guedes9a1a1992012-07-24 15:03:48 -03002711 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002712 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002713 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002714 goto unlock;
2715 }
2716
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002717 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002718 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002719 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002720 goto unlock;
2721 }
2722
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002723 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002724 if (!cmd) {
2725 err = -ENOMEM;
2726 goto unlock;
2727 }
2728
2729 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2730 if (err < 0)
2731 mgmt_pending_remove(cmd);
2732
2733unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002734 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002735 return err;
2736}
2737
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002738static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002739 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002740{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002741 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002742 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002743 int err;
2744
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002745 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002746
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002747 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002748
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002749 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002750 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002751 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002752 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002753 else
Szymon Janca6785be2012-12-13 15:11:21 +01002754 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002755
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002756 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002757 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002758
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002759 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002760 return err;
2761}
2762
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002763static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002764 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002765{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002766 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002767 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002768 int err;
2769
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002770 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002771
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002772 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002773
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002774 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002775 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002776 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002777 else
Szymon Janca6785be2012-12-13 15:11:21 +01002778 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002779
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002780 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002781 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002782
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002783 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002784 return err;
2785}
2786
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002787static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2788{
2789 struct pending_cmd *cmd;
2790 u8 type;
2791 int err;
2792
2793 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2794
2795 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2796 if (!cmd)
2797 return -ENOENT;
2798
2799 type = hdev->discovery.type;
2800
2801 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2802 &type, sizeof(type));
2803 mgmt_pending_remove(cmd);
2804
2805 return err;
2806}
2807
Andre Guedes7c307722013-04-30 15:29:28 -03002808static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2809{
2810 BT_DBG("status %d", status);
2811
2812 if (status) {
2813 hci_dev_lock(hdev);
2814 mgmt_start_discovery_failed(hdev, status);
2815 hci_dev_unlock(hdev);
2816 return;
2817 }
2818
2819 hci_dev_lock(hdev);
2820 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2821 hci_dev_unlock(hdev);
2822
2823 switch (hdev->discovery.type) {
2824 case DISCOV_TYPE_LE:
2825 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002826 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002827 break;
2828
2829 case DISCOV_TYPE_INTERLEAVED:
2830 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002831 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002832 break;
2833
2834 case DISCOV_TYPE_BREDR:
2835 break;
2836
2837 default:
2838 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2839 }
2840}
2841
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002842static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002843 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002844{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002845 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002846 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002847 struct hci_cp_le_set_scan_param param_cp;
2848 struct hci_cp_le_set_scan_enable enable_cp;
2849 struct hci_cp_inquiry inq_cp;
2850 struct hci_request req;
2851 /* General inquiry access code (GIAC) */
2852 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002853 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002854 int err;
2855
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002856 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002858 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002859
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002860 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002861 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002862 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002863 goto failed;
2864 }
2865
Andre Guedes642be6c2012-03-21 00:03:37 -03002866 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2867 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2868 MGMT_STATUS_BUSY);
2869 goto failed;
2870 }
2871
Johan Hedbergff9ef572012-01-04 14:23:45 +02002872 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002873 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002874 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002875 goto failed;
2876 }
2877
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002878 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002879 if (!cmd) {
2880 err = -ENOMEM;
2881 goto failed;
2882 }
2883
Andre Guedes4aab14e2012-02-17 20:39:36 -03002884 hdev->discovery.type = cp->type;
2885
Andre Guedes7c307722013-04-30 15:29:28 -03002886 hci_req_init(&req, hdev);
2887
Andre Guedes4aab14e2012-02-17 20:39:36 -03002888 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002889 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002890 status = mgmt_bredr_support(hdev);
2891 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002892 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002893 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002894 mgmt_pending_remove(cmd);
2895 goto failed;
2896 }
2897
Andre Guedes7c307722013-04-30 15:29:28 -03002898 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2899 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2900 MGMT_STATUS_BUSY);
2901 mgmt_pending_remove(cmd);
2902 goto failed;
2903 }
2904
2905 hci_inquiry_cache_flush(hdev);
2906
2907 memset(&inq_cp, 0, sizeof(inq_cp));
2908 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002909 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002910 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002911 break;
2912
2913 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002914 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002915 status = mgmt_le_support(hdev);
2916 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002917 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002918 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002919 mgmt_pending_remove(cmd);
2920 goto failed;
2921 }
2922
Andre Guedes7c307722013-04-30 15:29:28 -03002923 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002924 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002925 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2926 MGMT_STATUS_NOT_SUPPORTED);
2927 mgmt_pending_remove(cmd);
2928 goto failed;
2929 }
2930
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002931 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002932 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2933 MGMT_STATUS_REJECTED);
2934 mgmt_pending_remove(cmd);
2935 goto failed;
2936 }
2937
2938 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2939 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2940 MGMT_STATUS_BUSY);
2941 mgmt_pending_remove(cmd);
2942 goto failed;
2943 }
2944
2945 memset(&param_cp, 0, sizeof(param_cp));
2946 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002947 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2948 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002949 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2950 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2951 else
2952 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002953 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2954 &param_cp);
2955
2956 memset(&enable_cp, 0, sizeof(enable_cp));
2957 enable_cp.enable = LE_SCAN_ENABLE;
2958 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2959 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2960 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002961 break;
2962
Andre Guedesf39799f2012-02-17 20:39:35 -03002963 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002964 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2965 MGMT_STATUS_INVALID_PARAMS);
2966 mgmt_pending_remove(cmd);
2967 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002968 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002969
Andre Guedes7c307722013-04-30 15:29:28 -03002970 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002971 if (err < 0)
2972 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002973 else
2974 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002975
2976failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002977 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002978 return err;
2979}
2980
Andre Guedes1183fdc2013-04-30 15:29:35 -03002981static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2982{
2983 struct pending_cmd *cmd;
2984 int err;
2985
2986 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2987 if (!cmd)
2988 return -ENOENT;
2989
2990 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2991 &hdev->discovery.type, sizeof(hdev->discovery.type));
2992 mgmt_pending_remove(cmd);
2993
2994 return err;
2995}
2996
Andre Guedes0e05bba2013-04-30 15:29:33 -03002997static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2998{
2999 BT_DBG("status %d", status);
3000
3001 hci_dev_lock(hdev);
3002
3003 if (status) {
3004 mgmt_stop_discovery_failed(hdev, status);
3005 goto unlock;
3006 }
3007
3008 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3009
3010unlock:
3011 hci_dev_unlock(hdev);
3012}
3013
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003014static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003015 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003016{
Johan Hedbergd9306502012-02-20 23:25:18 +02003017 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003018 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003019 struct hci_cp_remote_name_req_cancel cp;
3020 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003021 struct hci_request req;
3022 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003023 int err;
3024
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003025 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003026
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003027 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003028
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003029 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003030 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003031 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3032 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003033 goto unlock;
3034 }
3035
3036 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003037 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003038 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3039 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003040 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003041 }
3042
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003043 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003044 if (!cmd) {
3045 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003046 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003047 }
3048
Andre Guedes0e05bba2013-04-30 15:29:33 -03003049 hci_req_init(&req, hdev);
3050
Andre Guedese0d9727e2012-03-20 15:15:36 -03003051 switch (hdev->discovery.state) {
3052 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003053 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3054 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3055 } else {
3056 cancel_delayed_work(&hdev->le_scan_disable);
3057
3058 memset(&enable_cp, 0, sizeof(enable_cp));
3059 enable_cp.enable = LE_SCAN_DISABLE;
3060 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3061 sizeof(enable_cp), &enable_cp);
3062 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003063
Andre Guedese0d9727e2012-03-20 15:15:36 -03003064 break;
3065
3066 case DISCOVERY_RESOLVING:
3067 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003068 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003069 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003070 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003071 err = cmd_complete(sk, hdev->id,
3072 MGMT_OP_STOP_DISCOVERY, 0,
3073 &mgmt_cp->type,
3074 sizeof(mgmt_cp->type));
3075 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3076 goto unlock;
3077 }
3078
3079 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003080 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3081 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003082
3083 break;
3084
3085 default:
3086 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003087
3088 mgmt_pending_remove(cmd);
3089 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3090 MGMT_STATUS_FAILED, &mgmt_cp->type,
3091 sizeof(mgmt_cp->type));
3092 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003093 }
3094
Andre Guedes0e05bba2013-04-30 15:29:33 -03003095 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003096 if (err < 0)
3097 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003098 else
3099 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003100
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003101unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003102 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003103 return err;
3104}
3105
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003106static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003107 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003108{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003109 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003110 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003111 int err;
3112
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003113 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003114
Johan Hedberg561aafb2012-01-04 13:31:59 +02003115 hci_dev_lock(hdev);
3116
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003117 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003118 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003119 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003120 goto failed;
3121 }
3122
Johan Hedberga198e7b2012-02-17 14:27:06 +02003123 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003124 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003125 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003126 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003127 goto failed;
3128 }
3129
3130 if (cp->name_known) {
3131 e->name_state = NAME_KNOWN;
3132 list_del(&e->list);
3133 } else {
3134 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003135 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003136 }
3137
Johan Hedberge3846622013-01-09 15:29:33 +02003138 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3139 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003140
3141failed:
3142 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003143 return err;
3144}
3145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003146static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003147 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003148{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003149 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003150 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003151 int err;
3152
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003153 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003154
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003155 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003156 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3157 MGMT_STATUS_INVALID_PARAMS,
3158 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003159
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003160 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003161
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003162 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003163 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003164 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003165 else
Szymon Janca6785be2012-12-13 15:11:21 +01003166 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003167
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003168 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003169 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003170
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003171 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003172
3173 return err;
3174}
3175
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003176static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003177 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003178{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003179 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003180 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003181 int err;
3182
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003183 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003184
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003185 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003186 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3187 MGMT_STATUS_INVALID_PARAMS,
3188 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003189
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003190 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003191
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003192 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003193 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003194 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003195 else
Szymon Janca6785be2012-12-13 15:11:21 +01003196 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003198 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003199 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003200
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003201 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003202
3203 return err;
3204}
3205
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003206static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3207 u16 len)
3208{
3209 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003210 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003211 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003212 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003213
3214 BT_DBG("%s", hdev->name);
3215
Szymon Jancc72d4b82012-03-16 16:02:57 +01003216 source = __le16_to_cpu(cp->source);
3217
3218 if (source > 0x0002)
3219 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3220 MGMT_STATUS_INVALID_PARAMS);
3221
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003222 hci_dev_lock(hdev);
3223
Szymon Jancc72d4b82012-03-16 16:02:57 +01003224 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003225 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3226 hdev->devid_product = __le16_to_cpu(cp->product);
3227 hdev->devid_version = __le16_to_cpu(cp->version);
3228
3229 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3230
Johan Hedberg890ea892013-03-15 17:06:52 -05003231 hci_req_init(&req, hdev);
3232 update_eir(&req);
3233 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003234
3235 hci_dev_unlock(hdev);
3236
3237 return err;
3238}
3239
Johan Hedberg4375f102013-09-25 13:26:10 +03003240static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3241{
3242 struct cmd_lookup match = { NULL, hdev };
3243
3244 if (status) {
3245 u8 mgmt_err = mgmt_status(status);
3246
3247 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3248 cmd_status_rsp, &mgmt_err);
3249 return;
3250 }
3251
3252 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3253 &match);
3254
3255 new_settings(hdev, match.sk);
3256
3257 if (match.sk)
3258 sock_put(match.sk);
3259}
3260
Marcel Holtmann21b51872013-10-10 09:47:53 -07003261static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3262 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003263{
3264 struct mgmt_mode *cp = data;
3265 struct pending_cmd *cmd;
3266 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003267 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003268 int err;
3269
3270 BT_DBG("request for %s", hdev->name);
3271
Johan Hedberge6fe7982013-10-02 15:45:22 +03003272 status = mgmt_le_support(hdev);
3273 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003274 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003275 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003276
3277 if (cp->val != 0x00 && cp->val != 0x01)
3278 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3279 MGMT_STATUS_INVALID_PARAMS);
3280
3281 hci_dev_lock(hdev);
3282
3283 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003284 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003285
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003286 /* The following conditions are ones which mean that we should
3287 * not do any HCI communication but directly send a mgmt
3288 * response to user space (after toggling the flag if
3289 * necessary).
3290 */
3291 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003292 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003293 bool changed = false;
3294
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003295 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3296 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003297 changed = true;
3298 }
3299
3300 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3301 if (err < 0)
3302 goto unlock;
3303
3304 if (changed)
3305 err = new_settings(hdev, sk);
3306
3307 goto unlock;
3308 }
3309
3310 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3311 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3312 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3313 MGMT_STATUS_BUSY);
3314 goto unlock;
3315 }
3316
3317 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3318 if (!cmd) {
3319 err = -ENOMEM;
3320 goto unlock;
3321 }
3322
3323 hci_req_init(&req, hdev);
3324
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003325 if (val)
3326 enable_advertising(&req);
3327 else
3328 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003329
3330 err = hci_req_run(&req, set_advertising_complete);
3331 if (err < 0)
3332 mgmt_pending_remove(cmd);
3333
3334unlock:
3335 hci_dev_unlock(hdev);
3336 return err;
3337}
3338
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003339static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3340 void *data, u16 len)
3341{
3342 struct mgmt_cp_set_static_address *cp = data;
3343 int err;
3344
3345 BT_DBG("%s", hdev->name);
3346
Marcel Holtmann62af4442013-10-02 22:10:32 -07003347 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003348 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003349 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003350
3351 if (hdev_is_powered(hdev))
3352 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3353 MGMT_STATUS_REJECTED);
3354
3355 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3356 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3357 return cmd_status(sk, hdev->id,
3358 MGMT_OP_SET_STATIC_ADDRESS,
3359 MGMT_STATUS_INVALID_PARAMS);
3360
3361 /* Two most significant bits shall be set */
3362 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3363 return cmd_status(sk, hdev->id,
3364 MGMT_OP_SET_STATIC_ADDRESS,
3365 MGMT_STATUS_INVALID_PARAMS);
3366 }
3367
3368 hci_dev_lock(hdev);
3369
3370 bacpy(&hdev->static_addr, &cp->bdaddr);
3371
3372 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3373
3374 hci_dev_unlock(hdev);
3375
3376 return err;
3377}
3378
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003379static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3380 void *data, u16 len)
3381{
3382 struct mgmt_cp_set_scan_params *cp = data;
3383 __u16 interval, window;
3384 int err;
3385
3386 BT_DBG("%s", hdev->name);
3387
3388 if (!lmp_le_capable(hdev))
3389 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3390 MGMT_STATUS_NOT_SUPPORTED);
3391
3392 interval = __le16_to_cpu(cp->interval);
3393
3394 if (interval < 0x0004 || interval > 0x4000)
3395 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3396 MGMT_STATUS_INVALID_PARAMS);
3397
3398 window = __le16_to_cpu(cp->window);
3399
3400 if (window < 0x0004 || window > 0x4000)
3401 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3402 MGMT_STATUS_INVALID_PARAMS);
3403
3404 hci_dev_lock(hdev);
3405
3406 hdev->le_scan_interval = interval;
3407 hdev->le_scan_window = window;
3408
3409 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3410
3411 hci_dev_unlock(hdev);
3412
3413 return err;
3414}
3415
Johan Hedberg33e38b32013-03-15 17:07:05 -05003416static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3417{
3418 struct pending_cmd *cmd;
3419
3420 BT_DBG("status 0x%02x", status);
3421
3422 hci_dev_lock(hdev);
3423
3424 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3425 if (!cmd)
3426 goto unlock;
3427
3428 if (status) {
3429 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3430 mgmt_status(status));
3431 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003432 struct mgmt_mode *cp = cmd->param;
3433
3434 if (cp->val)
3435 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3436 else
3437 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3438
Johan Hedberg33e38b32013-03-15 17:07:05 -05003439 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3440 new_settings(hdev, cmd->sk);
3441 }
3442
3443 mgmt_pending_remove(cmd);
3444
3445unlock:
3446 hci_dev_unlock(hdev);
3447}
3448
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003449static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003450 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003451{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003452 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003453 struct pending_cmd *cmd;
3454 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003455 int err;
3456
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003457 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003458
Johan Hedberg56f87902013-10-02 13:43:13 +03003459 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3460 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003461 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3462 MGMT_STATUS_NOT_SUPPORTED);
3463
Johan Hedberga7e80f22013-01-09 16:05:19 +02003464 if (cp->val != 0x00 && cp->val != 0x01)
3465 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3466 MGMT_STATUS_INVALID_PARAMS);
3467
Johan Hedberg5400c042012-02-21 16:40:33 +02003468 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003469 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003470 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003471
3472 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003473 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003474 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003475
3476 hci_dev_lock(hdev);
3477
Johan Hedberg05cbf292013-03-15 17:07:07 -05003478 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3479 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3480 MGMT_STATUS_BUSY);
3481 goto unlock;
3482 }
3483
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003484 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3485 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3486 hdev);
3487 goto unlock;
3488 }
3489
Johan Hedberg33e38b32013-03-15 17:07:05 -05003490 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3491 data, len);
3492 if (!cmd) {
3493 err = -ENOMEM;
3494 goto unlock;
3495 }
3496
3497 hci_req_init(&req, hdev);
3498
Johan Hedberg406d7802013-03-15 17:07:09 -05003499 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003500
3501 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003502 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003503 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003504 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003505 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003506 }
3507
Johan Hedberg33e38b32013-03-15 17:07:05 -05003508unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003509 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003510
Antti Julkuf6422ec2011-06-22 13:11:56 +03003511 return err;
3512}
3513
Johan Hedberg0663ca22013-10-02 13:43:14 +03003514static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3515{
3516 struct pending_cmd *cmd;
3517
3518 BT_DBG("status 0x%02x", status);
3519
3520 hci_dev_lock(hdev);
3521
3522 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3523 if (!cmd)
3524 goto unlock;
3525
3526 if (status) {
3527 u8 mgmt_err = mgmt_status(status);
3528
3529 /* We need to restore the flag if related HCI commands
3530 * failed.
3531 */
3532 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3533
3534 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3535 } else {
3536 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3537 new_settings(hdev, cmd->sk);
3538 }
3539
3540 mgmt_pending_remove(cmd);
3541
3542unlock:
3543 hci_dev_unlock(hdev);
3544}
3545
3546static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3547{
3548 struct mgmt_mode *cp = data;
3549 struct pending_cmd *cmd;
3550 struct hci_request req;
3551 int err;
3552
3553 BT_DBG("request for %s", hdev->name);
3554
3555 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3556 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3557 MGMT_STATUS_NOT_SUPPORTED);
3558
3559 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3560 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3561 MGMT_STATUS_REJECTED);
3562
3563 if (cp->val != 0x00 && cp->val != 0x01)
3564 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3565 MGMT_STATUS_INVALID_PARAMS);
3566
3567 hci_dev_lock(hdev);
3568
3569 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3570 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3571 goto unlock;
3572 }
3573
3574 if (!hdev_is_powered(hdev)) {
3575 if (!cp->val) {
3576 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3577 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3578 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3579 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3580 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3581 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3582 }
3583
3584 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3585
3586 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3587 if (err < 0)
3588 goto unlock;
3589
3590 err = new_settings(hdev, sk);
3591 goto unlock;
3592 }
3593
3594 /* Reject disabling when powered on */
3595 if (!cp->val) {
3596 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3597 MGMT_STATUS_REJECTED);
3598 goto unlock;
3599 }
3600
3601 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3602 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3603 MGMT_STATUS_BUSY);
3604 goto unlock;
3605 }
3606
3607 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3608 if (!cmd) {
3609 err = -ENOMEM;
3610 goto unlock;
3611 }
3612
3613 /* We need to flip the bit already here so that hci_update_ad
3614 * generates the correct flags.
3615 */
3616 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3617
3618 hci_req_init(&req, hdev);
3619 hci_update_ad(&req);
3620 err = hci_req_run(&req, set_bredr_complete);
3621 if (err < 0)
3622 mgmt_pending_remove(cmd);
3623
3624unlock:
3625 hci_dev_unlock(hdev);
3626 return err;
3627}
3628
Johan Hedberg3f706b72013-01-20 14:27:16 +02003629static bool ltk_is_valid(struct mgmt_ltk_info *key)
3630{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003631 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3632 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003633 if (key->master != 0x00 && key->master != 0x01)
3634 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003635 if (!bdaddr_type_is_le(key->addr.type))
3636 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003637 return true;
3638}
3639
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003640static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003641 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003642{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003643 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3644 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003645 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003646
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003647 BT_DBG("request for %s", hdev->name);
3648
3649 if (!lmp_le_capable(hdev))
3650 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3651 MGMT_STATUS_NOT_SUPPORTED);
3652
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003653 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003654
3655 expected_len = sizeof(*cp) + key_count *
3656 sizeof(struct mgmt_ltk_info);
3657 if (expected_len != len) {
3658 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003659 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003660 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003661 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003662 }
3663
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003664 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003665
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003666 for (i = 0; i < key_count; i++) {
3667 struct mgmt_ltk_info *key = &cp->keys[i];
3668
Johan Hedberg3f706b72013-01-20 14:27:16 +02003669 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003670 return cmd_status(sk, hdev->id,
3671 MGMT_OP_LOAD_LONG_TERM_KEYS,
3672 MGMT_STATUS_INVALID_PARAMS);
3673 }
3674
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003675 hci_dev_lock(hdev);
3676
3677 hci_smp_ltks_clear(hdev);
3678
3679 for (i = 0; i < key_count; i++) {
3680 struct mgmt_ltk_info *key = &cp->keys[i];
3681 u8 type;
3682
3683 if (key->master)
3684 type = HCI_SMP_LTK;
3685 else
3686 type = HCI_SMP_LTK_SLAVE;
3687
Hemant Gupta4596fde52012-04-16 14:57:40 +05303688 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003689 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003690 type, 0, key->authenticated, key->val,
3691 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003692 }
3693
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003694 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3695 NULL, 0);
3696
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003697 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003698
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003699 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003700}
3701
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003702static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003703 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3704 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003705 bool var_len;
3706 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003707} mgmt_handlers[] = {
3708 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003709 { read_version, false, MGMT_READ_VERSION_SIZE },
3710 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3711 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3712 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3713 { set_powered, false, MGMT_SETTING_SIZE },
3714 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3715 { set_connectable, false, MGMT_SETTING_SIZE },
3716 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3717 { set_pairable, false, MGMT_SETTING_SIZE },
3718 { set_link_security, false, MGMT_SETTING_SIZE },
3719 { set_ssp, false, MGMT_SETTING_SIZE },
3720 { set_hs, false, MGMT_SETTING_SIZE },
3721 { set_le, false, MGMT_SETTING_SIZE },
3722 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3723 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3724 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3725 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3726 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3727 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3728 { disconnect, false, MGMT_DISCONNECT_SIZE },
3729 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3730 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3731 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3732 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3733 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3734 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3735 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3736 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3737 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3738 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3739 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3740 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3741 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3742 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3743 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3744 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3745 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3746 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3747 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003748 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003749 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003750 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003751 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003752 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003753};
3754
3755
Johan Hedberg03811012010-12-08 00:21:06 +02003756int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3757{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003758 void *buf;
3759 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003760 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003761 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003762 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003763 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003764 int err;
3765
3766 BT_DBG("got %zu bytes", msglen);
3767
3768 if (msglen < sizeof(*hdr))
3769 return -EINVAL;
3770
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003771 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003772 if (!buf)
3773 return -ENOMEM;
3774
3775 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3776 err = -EFAULT;
3777 goto done;
3778 }
3779
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003780 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003781 opcode = __le16_to_cpu(hdr->opcode);
3782 index = __le16_to_cpu(hdr->index);
3783 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003784
3785 if (len != msglen - sizeof(*hdr)) {
3786 err = -EINVAL;
3787 goto done;
3788 }
3789
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003790 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003791 hdev = hci_dev_get(index);
3792 if (!hdev) {
3793 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003794 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003795 goto done;
3796 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003797
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02003798 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
3799 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003800 err = cmd_status(sk, index, opcode,
3801 MGMT_STATUS_INVALID_INDEX);
3802 goto done;
3803 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003804 }
3805
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003806 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003807 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003808 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003809 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003810 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003811 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003812 }
3813
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003814 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003815 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003816 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003817 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003818 goto done;
3819 }
3820
Johan Hedbergbe22b542012-03-01 22:24:41 +02003821 handler = &mgmt_handlers[opcode];
3822
3823 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003824 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003825 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003826 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003827 goto done;
3828 }
3829
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003830 if (hdev)
3831 mgmt_init_hdev(sk, hdev);
3832
3833 cp = buf + sizeof(*hdr);
3834
Johan Hedbergbe22b542012-03-01 22:24:41 +02003835 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003836 if (err < 0)
3837 goto done;
3838
Johan Hedberg03811012010-12-08 00:21:06 +02003839 err = msglen;
3840
3841done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003842 if (hdev)
3843 hci_dev_put(hdev);
3844
Johan Hedberg03811012010-12-08 00:21:06 +02003845 kfree(buf);
3846 return err;
3847}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003848
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003849void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003850{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003851 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003852 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003853
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003854 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003855}
3856
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003857void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003858{
Johan Hedberg5f159032012-03-02 03:13:19 +02003859 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003860
Marcel Holtmann1514b892013-10-06 08:25:01 -07003861 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003862 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003863
Johan Hedberg744cf192011-11-08 20:40:14 +02003864 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003865
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003866 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003867}
3868
Johan Hedberg890ea892013-03-15 17:06:52 -05003869static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003870{
Johan Hedberg890ea892013-03-15 17:06:52 -05003871 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003872 u8 scan = 0;
3873
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003874 /* Ensure that fast connectable is disabled. This function will
3875 * not do anything if the page scan parameters are already what
3876 * they should be.
3877 */
3878 write_fast_connectable(req, false);
3879
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003880 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3881 scan |= SCAN_PAGE;
3882 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3883 scan |= SCAN_INQUIRY;
3884
Johan Hedberg890ea892013-03-15 17:06:52 -05003885 if (scan)
3886 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003887}
3888
Johan Hedberg229ab392013-03-15 17:06:53 -05003889static void powered_complete(struct hci_dev *hdev, u8 status)
3890{
3891 struct cmd_lookup match = { NULL, hdev };
3892
3893 BT_DBG("status 0x%02x", status);
3894
3895 hci_dev_lock(hdev);
3896
3897 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3898
3899 new_settings(hdev, match.sk);
3900
3901 hci_dev_unlock(hdev);
3902
3903 if (match.sk)
3904 sock_put(match.sk);
3905}
3906
Johan Hedberg70da6242013-03-15 17:06:51 -05003907static int powered_update_hci(struct hci_dev *hdev)
3908{
Johan Hedberg890ea892013-03-15 17:06:52 -05003909 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003910 u8 link_sec;
3911
Johan Hedberg890ea892013-03-15 17:06:52 -05003912 hci_req_init(&req, hdev);
3913
Johan Hedberg70da6242013-03-15 17:06:51 -05003914 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3915 !lmp_host_ssp_capable(hdev)) {
3916 u8 ssp = 1;
3917
Johan Hedberg890ea892013-03-15 17:06:52 -05003918 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003919 }
3920
Johan Hedbergc73eee92013-04-19 18:35:21 +03003921 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3922 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003923 struct hci_cp_write_le_host_supported cp;
3924
3925 cp.le = 1;
3926 cp.simul = lmp_le_br_capable(hdev);
3927
3928 /* Check first if we already have the right
3929 * host state (host features set)
3930 */
3931 if (cp.le != lmp_host_le_capable(hdev) ||
3932 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003933 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3934 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003935
3936 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3937 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003938 }
3939
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003940 if (lmp_le_capable(hdev)) {
3941 /* Set random address to static address if configured */
3942 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3943 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3944 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003945
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003946 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3947 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003948 }
3949
Johan Hedberg70da6242013-03-15 17:06:51 -05003950 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3951 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003952 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3953 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003954
3955 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003956 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3957 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003958 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003959 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003960 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003961 }
3962
Johan Hedberg229ab392013-03-15 17:06:53 -05003963 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003964}
3965
Johan Hedberg744cf192011-11-08 20:40:14 +02003966int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003967{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003968 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003969 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3970 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003971 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003972
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003973 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3974 return 0;
3975
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003976 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003977 if (powered_update_hci(hdev) == 0)
3978 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003979
Johan Hedberg229ab392013-03-15 17:06:53 -05003980 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3981 &match);
3982 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003983 }
3984
Johan Hedberg229ab392013-03-15 17:06:53 -05003985 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3986 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3987
3988 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3989 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3990 zero_cod, sizeof(zero_cod), NULL);
3991
3992new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003993 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003994
3995 if (match.sk)
3996 sock_put(match.sk);
3997
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003998 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003999}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004000
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004001void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004002{
4003 struct pending_cmd *cmd;
4004 u8 status;
4005
4006 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4007 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004008 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004009
4010 if (err == -ERFKILL)
4011 status = MGMT_STATUS_RFKILLED;
4012 else
4013 status = MGMT_STATUS_FAILED;
4014
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004015 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004016
4017 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004018}
4019
Johan Hedberg744cf192011-11-08 20:40:14 +02004020int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004021{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004022 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004023 bool changed = false;
4024 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004025
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004026 if (discoverable) {
4027 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4028 changed = true;
4029 } else {
4030 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4031 changed = true;
4032 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004033
Johan Hedberged9b5f22012-02-21 20:47:06 +02004034 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004035 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004036
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004037 if (changed)
4038 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004039
Johan Hedberg73f22f62010-12-29 16:00:25 +02004040 if (match.sk)
4041 sock_put(match.sk);
4042
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004043 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004044}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004045
Johan Hedberg744cf192011-11-08 20:40:14 +02004046int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004047{
Johan Hedberg2b76f452013-03-15 17:07:04 -05004048 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004049 bool changed = false;
4050 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004051
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004052 if (connectable) {
4053 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4054 changed = true;
4055 } else {
4056 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4057 changed = true;
4058 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004059
Johan Hedberg2b76f452013-03-15 17:07:04 -05004060 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004061
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004062 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05004063 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004064
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004065 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004066}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004067
Johan Hedberg744cf192011-11-08 20:40:14 +02004068int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004069{
Johan Hedbergca69b792011-11-11 18:10:00 +02004070 u8 mgmt_err = mgmt_status(status);
4071
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004072 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004073 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004074 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004075
4076 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004077 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004078 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004079
4080 return 0;
4081}
4082
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004083int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4084 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004085{
Johan Hedberg86742e12011-11-07 23:13:38 +02004086 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004087
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004088 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004089
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004090 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004091 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004092 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004093 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004094 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004095 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004096
Johan Hedberg744cf192011-11-08 20:40:14 +02004097 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004098}
Johan Hedbergf7520542011-01-20 12:34:39 +02004099
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004100int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4101{
4102 struct mgmt_ev_new_long_term_key ev;
4103
4104 memset(&ev, 0, sizeof(ev));
4105
4106 ev.store_hint = persistent;
4107 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004108 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004109 ev.key.authenticated = key->authenticated;
4110 ev.key.enc_size = key->enc_size;
4111 ev.key.ediv = key->ediv;
4112
4113 if (key->type == HCI_SMP_LTK)
4114 ev.key.master = 1;
4115
4116 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4117 memcpy(ev.key.val, key->val, sizeof(key->val));
4118
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004119 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4120 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004121}
4122
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004123void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4124 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4125 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004126{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004127 char buf[512];
4128 struct mgmt_ev_device_connected *ev = (void *) buf;
4129 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004130
Johan Hedbergb644ba32012-01-17 21:48:47 +02004131 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004132 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004133
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004134 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004135
Johan Hedbergb644ba32012-01-17 21:48:47 +02004136 if (name_len > 0)
4137 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004138 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004139
4140 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004141 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004142 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004143
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004144 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004145
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004146 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4147 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004148}
4149
Johan Hedberg8962ee72011-01-20 12:40:27 +02004150static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4151{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004152 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004153 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004154 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004155
Johan Hedberg88c3df12012-02-09 14:27:38 +02004156 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4157 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004158
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004159 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004160 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004161
4162 *sk = cmd->sk;
4163 sock_hold(*sk);
4164
Johan Hedberga664b5b2011-02-19 12:06:02 -03004165 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004166}
4167
Johan Hedberg124f6e32012-02-09 13:50:12 +02004168static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004169{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004170 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004171 struct mgmt_cp_unpair_device *cp = cmd->param;
4172 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004173
4174 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004175 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4176 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004177
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004178 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4179
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004180 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004181
4182 mgmt_pending_remove(cmd);
4183}
4184
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004185void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4186 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004187{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004188 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004189 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004190
Johan Hedberg744cf192011-11-08 20:40:14 +02004191 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004192
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004193 bacpy(&ev.addr.bdaddr, bdaddr);
4194 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4195 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004196
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004197 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004198
4199 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004200 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004201
Johan Hedberg124f6e32012-02-09 13:50:12 +02004202 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004203 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004204}
4205
Marcel Holtmann78929242013-10-06 23:55:47 -07004206void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4207 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004208{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004209 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004210 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004211
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004212 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4213 hdev);
4214
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004215 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004216 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004217 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004218
Johan Hedberg88c3df12012-02-09 14:27:38 +02004219 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004220 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004221
Marcel Holtmann78929242013-10-06 23:55:47 -07004222 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4223 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004224
Johan Hedberga664b5b2011-02-19 12:06:02 -03004225 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004226}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004227
Marcel Holtmann445608d2013-10-06 23:55:48 -07004228void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4229 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004230{
4231 struct mgmt_ev_connect_failed ev;
4232
Johan Hedberg4c659c32011-11-07 23:13:39 +02004233 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004234 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004235 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004236
Marcel Holtmann445608d2013-10-06 23:55:48 -07004237 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004238}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004239
Johan Hedberg744cf192011-11-08 20:40:14 +02004240int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004241{
4242 struct mgmt_ev_pin_code_request ev;
4243
Johan Hedbergd8457692012-02-17 14:24:57 +02004244 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004245 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004246 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004247
Johan Hedberg744cf192011-11-08 20:40:14 +02004248 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004249 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004250}
4251
Johan Hedberg744cf192011-11-08 20:40:14 +02004252int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004253 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004254{
4255 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004256 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004257 int err;
4258
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004259 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004260 if (!cmd)
4261 return -ENOENT;
4262
Johan Hedbergd8457692012-02-17 14:24:57 +02004263 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004264 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004265
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004266 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004267 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004268
Johan Hedberga664b5b2011-02-19 12:06:02 -03004269 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004270
4271 return err;
4272}
4273
Johan Hedberg744cf192011-11-08 20:40:14 +02004274int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004275 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004276{
4277 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004278 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004279 int err;
4280
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004281 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004282 if (!cmd)
4283 return -ENOENT;
4284
Johan Hedbergd8457692012-02-17 14:24:57 +02004285 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004286 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004287
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004288 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004289 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004290
Johan Hedberga664b5b2011-02-19 12:06:02 -03004291 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004292
4293 return err;
4294}
Johan Hedberga5c29682011-02-19 12:05:57 -03004295
Johan Hedberg744cf192011-11-08 20:40:14 +02004296int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004297 u8 link_type, u8 addr_type, __le32 value,
4298 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004299{
4300 struct mgmt_ev_user_confirm_request ev;
4301
Johan Hedberg744cf192011-11-08 20:40:14 +02004302 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004303
Johan Hedberg272d90d2012-02-09 15:26:12 +02004304 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004305 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004306 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004307 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004308
Johan Hedberg744cf192011-11-08 20:40:14 +02004309 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004310 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004311}
4312
Johan Hedberg272d90d2012-02-09 15:26:12 +02004313int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004314 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004315{
4316 struct mgmt_ev_user_passkey_request ev;
4317
4318 BT_DBG("%s", hdev->name);
4319
Johan Hedberg272d90d2012-02-09 15:26:12 +02004320 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004321 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004322
4323 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004324 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004325}
4326
Brian Gix0df4c182011-11-16 13:53:13 -08004327static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004328 u8 link_type, u8 addr_type, u8 status,
4329 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004330{
4331 struct pending_cmd *cmd;
4332 struct mgmt_rp_user_confirm_reply rp;
4333 int err;
4334
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004335 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004336 if (!cmd)
4337 return -ENOENT;
4338
Johan Hedberg272d90d2012-02-09 15:26:12 +02004339 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004340 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004341 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004342 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004343
Johan Hedberga664b5b2011-02-19 12:06:02 -03004344 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004345
4346 return err;
4347}
4348
Johan Hedberg744cf192011-11-08 20:40:14 +02004349int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004350 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004351{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004352 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004353 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004354}
4355
Johan Hedberg272d90d2012-02-09 15:26:12 +02004356int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004357 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004358{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004359 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004360 status,
4361 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004362}
Johan Hedberg2a611692011-02-19 12:06:00 -03004363
Brian Gix604086b2011-11-23 08:28:33 -08004364int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004365 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004366{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004367 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004368 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004369}
4370
Johan Hedberg272d90d2012-02-09 15:26:12 +02004371int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004372 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004373{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004374 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004375 status,
4376 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004377}
4378
Johan Hedberg92a25252012-09-06 18:39:26 +03004379int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4380 u8 link_type, u8 addr_type, u32 passkey,
4381 u8 entered)
4382{
4383 struct mgmt_ev_passkey_notify ev;
4384
4385 BT_DBG("%s", hdev->name);
4386
4387 bacpy(&ev.addr.bdaddr, bdaddr);
4388 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4389 ev.passkey = __cpu_to_le32(passkey);
4390 ev.entered = entered;
4391
4392 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4393}
4394
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004395int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004396 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004397{
4398 struct mgmt_ev_auth_failed ev;
4399
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004400 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004401 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004402 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004403
Johan Hedberg744cf192011-11-08 20:40:14 +02004404 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004405}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004406
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004407int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4408{
4409 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004410 bool changed = false;
4411 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004412
4413 if (status) {
4414 u8 mgmt_err = mgmt_status(status);
4415 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004416 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004417 return 0;
4418 }
4419
Johan Hedberg47990ea2012-02-22 11:58:37 +02004420 if (test_bit(HCI_AUTH, &hdev->flags)) {
4421 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4422 changed = true;
4423 } else {
4424 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4425 changed = true;
4426 }
4427
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004428 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004429 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004430
Johan Hedberg47990ea2012-02-22 11:58:37 +02004431 if (changed)
4432 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004433
4434 if (match.sk)
4435 sock_put(match.sk);
4436
4437 return err;
4438}
4439
Johan Hedberg890ea892013-03-15 17:06:52 -05004440static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004441{
Johan Hedberg890ea892013-03-15 17:06:52 -05004442 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004443 struct hci_cp_write_eir cp;
4444
Johan Hedberg976eb202012-10-24 21:12:01 +03004445 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004446 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004447
Johan Hedbergc80da272012-02-22 15:38:48 +02004448 memset(hdev->eir, 0, sizeof(hdev->eir));
4449
Johan Hedbergcacaf522012-02-21 00:52:42 +02004450 memset(&cp, 0, sizeof(cp));
4451
Johan Hedberg890ea892013-03-15 17:06:52 -05004452 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004453}
4454
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004455int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004456{
4457 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004458 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004459 bool changed = false;
4460 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004461
4462 if (status) {
4463 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004464
4465 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004466 &hdev->dev_flags)) {
4467 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004468 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004469 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004470
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004471 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4472 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004473
4474 return err;
4475 }
4476
4477 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004478 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004479 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004480 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4481 if (!changed)
4482 changed = test_and_clear_bit(HCI_HS_ENABLED,
4483 &hdev->dev_flags);
4484 else
4485 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004486 }
4487
4488 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4489
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004490 if (changed)
4491 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004492
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004493 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004494 sock_put(match.sk);
4495
Johan Hedberg890ea892013-03-15 17:06:52 -05004496 hci_req_init(&req, hdev);
4497
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004498 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004499 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004500 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004501 clear_eir(&req);
4502
4503 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004504
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004505 return err;
4506}
4507
Johan Hedberg92da6092013-03-15 17:06:55 -05004508static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004509{
4510 struct cmd_lookup *match = data;
4511
Johan Hedberg90e70452012-02-23 23:09:40 +02004512 if (match->sk == NULL) {
4513 match->sk = cmd->sk;
4514 sock_hold(match->sk);
4515 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004516}
4517
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004518int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004519 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004520{
Johan Hedberg90e70452012-02-23 23:09:40 +02004521 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4522 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004523
Johan Hedberg92da6092013-03-15 17:06:55 -05004524 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4525 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4526 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004527
4528 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004529 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4530 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004531
4532 if (match.sk)
4533 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004534
4535 return err;
4536}
4537
Johan Hedberg744cf192011-11-08 20:40:14 +02004538int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004539{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004540 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004541 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004542
Johan Hedberg13928972013-03-15 17:07:00 -05004543 if (status)
4544 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004545
4546 memset(&ev, 0, sizeof(ev));
4547 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004548 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004549
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004550 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004551 if (!cmd) {
4552 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004553
Johan Hedberg13928972013-03-15 17:07:00 -05004554 /* If this is a HCI command related to powering on the
4555 * HCI dev don't send any mgmt signals.
4556 */
4557 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4558 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004559 }
4560
Johan Hedberg13928972013-03-15 17:07:00 -05004561 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4562 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004563}
Szymon Jancc35938b2011-03-22 13:12:21 +01004564
Johan Hedberg744cf192011-11-08 20:40:14 +02004565int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004566 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004567{
4568 struct pending_cmd *cmd;
4569 int err;
4570
Johan Hedberg744cf192011-11-08 20:40:14 +02004571 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004572
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004573 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004574 if (!cmd)
4575 return -ENOENT;
4576
4577 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004578 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4579 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004580 } else {
4581 struct mgmt_rp_read_local_oob_data rp;
4582
4583 memcpy(rp.hash, hash, sizeof(rp.hash));
4584 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4585
Johan Hedberg744cf192011-11-08 20:40:14 +02004586 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004587 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4588 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004589 }
4590
4591 mgmt_pending_remove(cmd);
4592
4593 return err;
4594}
Johan Hedberge17acd42011-03-30 23:57:16 +03004595
Marcel Holtmann901801b2013-10-06 23:55:51 -07004596void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4597 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4598 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004599{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004600 char buf[512];
4601 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004602 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004603
Andre Guedes12602d02013-04-30 15:29:40 -03004604 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004605 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004606
Johan Hedberg1dc06092012-01-15 21:01:23 +02004607 /* Leave 5 bytes for a potential CoD field */
4608 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004609 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004610
Johan Hedberg1dc06092012-01-15 21:01:23 +02004611 memset(buf, 0, sizeof(buf));
4612
Johan Hedberge319d2e2012-01-15 19:51:59 +02004613 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004614 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004615 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004616 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304617 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004618 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304619 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004620
Johan Hedberg1dc06092012-01-15 21:01:23 +02004621 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004622 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004623
Johan Hedberg1dc06092012-01-15 21:01:23 +02004624 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4625 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004626 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004627
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004628 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004629 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004630
Marcel Holtmann901801b2013-10-06 23:55:51 -07004631 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004632}
Johan Hedberga88a9652011-03-30 13:18:12 +03004633
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004634void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4635 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004636{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004637 struct mgmt_ev_device_found *ev;
4638 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4639 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004640
Johan Hedbergb644ba32012-01-17 21:48:47 +02004641 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004642
Johan Hedbergb644ba32012-01-17 21:48:47 +02004643 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004644
Johan Hedbergb644ba32012-01-17 21:48:47 +02004645 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004646 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004647 ev->rssi = rssi;
4648
4649 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004650 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004651
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004652 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004653
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004654 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004655}
Johan Hedberg314b2382011-04-27 10:29:57 -04004656
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004657void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004658{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004659 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004660 struct pending_cmd *cmd;
4661
Andre Guedes343fb142011-11-22 17:14:19 -03004662 BT_DBG("%s discovering %u", hdev->name, discovering);
4663
Johan Hedberg164a6e72011-11-01 17:06:44 +02004664 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004665 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004666 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004667 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004668
4669 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004670 u8 type = hdev->discovery.type;
4671
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004672 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4673 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004674 mgmt_pending_remove(cmd);
4675 }
4676
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004677 memset(&ev, 0, sizeof(ev));
4678 ev.type = hdev->discovery.type;
4679 ev.discovering = discovering;
4680
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004681 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004682}
Antti Julku5e762442011-08-25 16:48:02 +03004683
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004684int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004685{
4686 struct pending_cmd *cmd;
4687 struct mgmt_ev_device_blocked ev;
4688
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004689 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004690
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004691 bacpy(&ev.addr.bdaddr, bdaddr);
4692 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004693
Johan Hedberg744cf192011-11-08 20:40:14 +02004694 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004695 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004696}
4697
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004698int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004699{
4700 struct pending_cmd *cmd;
4701 struct mgmt_ev_device_unblocked ev;
4702
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004703 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004704
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004705 bacpy(&ev.addr.bdaddr, bdaddr);
4706 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004707
Johan Hedberg744cf192011-11-08 20:40:14 +02004708 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004709 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004710}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004711
4712static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4713{
4714 BT_DBG("%s status %u", hdev->name, status);
4715
4716 /* Clear the advertising mgmt setting if we failed to re-enable it */
4717 if (status) {
4718 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004719 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004720 }
4721}
4722
4723void mgmt_reenable_advertising(struct hci_dev *hdev)
4724{
4725 struct hci_request req;
4726
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004727 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004728 return;
4729
4730 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4731 return;
4732
4733 hci_req_init(&req, hdev);
4734 enable_advertising(&req);
4735
4736 /* If this fails we have no option but to let user space know
4737 * that we've disabled advertising.
4738 */
4739 if (hci_req_run(&req, adv_enable_complete) < 0) {
4740 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004741 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004742 }
4743}