blob: cfd8d448c25b77f18d7406e7c821e5fd4f791b5d [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070033
34#include "smp.h"
Johan Hedberg03811012010-12-08 00:21:06 +020035
Johan Hedberg2da9c552012-02-17 14:39:28 +020036#define MGMT_VERSION 1
Marcel Holtmann9ab8cf32013-10-02 05:18:31 -070037#define MGMT_REVISION 4
Johan Hedberg02d98122010-12-13 21:07:04 +020038
Johan Hedberge70bb2e2012-02-13 16:59:33 +020039static const u16 mgmt_commands[] = {
40 MGMT_OP_READ_INDEX_LIST,
41 MGMT_OP_READ_INFO,
42 MGMT_OP_SET_POWERED,
43 MGMT_OP_SET_DISCOVERABLE,
44 MGMT_OP_SET_CONNECTABLE,
45 MGMT_OP_SET_FAST_CONNECTABLE,
46 MGMT_OP_SET_PAIRABLE,
47 MGMT_OP_SET_LINK_SECURITY,
48 MGMT_OP_SET_SSP,
49 MGMT_OP_SET_HS,
50 MGMT_OP_SET_LE,
51 MGMT_OP_SET_DEV_CLASS,
52 MGMT_OP_SET_LOCAL_NAME,
53 MGMT_OP_ADD_UUID,
54 MGMT_OP_REMOVE_UUID,
55 MGMT_OP_LOAD_LINK_KEYS,
56 MGMT_OP_LOAD_LONG_TERM_KEYS,
57 MGMT_OP_DISCONNECT,
58 MGMT_OP_GET_CONNECTIONS,
59 MGMT_OP_PIN_CODE_REPLY,
60 MGMT_OP_PIN_CODE_NEG_REPLY,
61 MGMT_OP_SET_IO_CAPABILITY,
62 MGMT_OP_PAIR_DEVICE,
63 MGMT_OP_CANCEL_PAIR_DEVICE,
64 MGMT_OP_UNPAIR_DEVICE,
65 MGMT_OP_USER_CONFIRM_REPLY,
66 MGMT_OP_USER_CONFIRM_NEG_REPLY,
67 MGMT_OP_USER_PASSKEY_REPLY,
68 MGMT_OP_USER_PASSKEY_NEG_REPLY,
69 MGMT_OP_READ_LOCAL_OOB_DATA,
70 MGMT_OP_ADD_REMOTE_OOB_DATA,
71 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
72 MGMT_OP_START_DISCOVERY,
73 MGMT_OP_STOP_DISCOVERY,
74 MGMT_OP_CONFIRM_NAME,
75 MGMT_OP_BLOCK_DEVICE,
76 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070077 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030078 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030079 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070080 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070081 MGMT_OP_SET_SCAN_PARAMS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020082};
83
84static const u16 mgmt_events[] = {
85 MGMT_EV_CONTROLLER_ERROR,
86 MGMT_EV_INDEX_ADDED,
87 MGMT_EV_INDEX_REMOVED,
88 MGMT_EV_NEW_SETTINGS,
89 MGMT_EV_CLASS_OF_DEV_CHANGED,
90 MGMT_EV_LOCAL_NAME_CHANGED,
91 MGMT_EV_NEW_LINK_KEY,
92 MGMT_EV_NEW_LONG_TERM_KEY,
93 MGMT_EV_DEVICE_CONNECTED,
94 MGMT_EV_DEVICE_DISCONNECTED,
95 MGMT_EV_CONNECT_FAILED,
96 MGMT_EV_PIN_CODE_REQUEST,
97 MGMT_EV_USER_CONFIRM_REQUEST,
98 MGMT_EV_USER_PASSKEY_REQUEST,
99 MGMT_EV_AUTH_FAILED,
100 MGMT_EV_DEVICE_FOUND,
101 MGMT_EV_DISCOVERING,
102 MGMT_EV_DEVICE_BLOCKED,
103 MGMT_EV_DEVICE_UNBLOCKED,
104 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300105 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200106};
107
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800108#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200109
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200110#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
111 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
112
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200113struct pending_cmd {
114 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200115 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100117 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300119 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200120};
121
Johan Hedbergca69b792011-11-11 18:10:00 +0200122/* HCI to MGMT error code conversion table */
123static u8 mgmt_status_table[] = {
124 MGMT_STATUS_SUCCESS,
125 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
126 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
127 MGMT_STATUS_FAILED, /* Hardware Failure */
128 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
129 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
130 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
131 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
132 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
133 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
134 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
135 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
136 MGMT_STATUS_BUSY, /* Command Disallowed */
137 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
138 MGMT_STATUS_REJECTED, /* Rejected Security */
139 MGMT_STATUS_REJECTED, /* Rejected Personal */
140 MGMT_STATUS_TIMEOUT, /* Host Timeout */
141 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
142 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
143 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
144 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
145 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
146 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
147 MGMT_STATUS_BUSY, /* Repeated Attempts */
148 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
149 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
150 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
151 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
152 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
153 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
154 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
155 MGMT_STATUS_FAILED, /* Unspecified Error */
156 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
157 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
158 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
159 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
160 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
161 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
162 MGMT_STATUS_FAILED, /* Unit Link Key Used */
163 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
164 MGMT_STATUS_TIMEOUT, /* Instant Passed */
165 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
166 MGMT_STATUS_FAILED, /* Transaction Collision */
167 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
168 MGMT_STATUS_REJECTED, /* QoS Rejected */
169 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
170 MGMT_STATUS_REJECTED, /* Insufficient Security */
171 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
172 MGMT_STATUS_BUSY, /* Role Switch Pending */
173 MGMT_STATUS_FAILED, /* Slot Violation */
174 MGMT_STATUS_FAILED, /* Role Switch Failed */
175 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
176 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
177 MGMT_STATUS_BUSY, /* Host Busy Pairing */
178 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
179 MGMT_STATUS_BUSY, /* Controller Busy */
180 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
181 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
182 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
183 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
184 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
185};
186
187static u8 mgmt_status(u8 hci_status)
188{
189 if (hci_status < ARRAY_SIZE(mgmt_status_table))
190 return mgmt_status_table[hci_status];
191
192 return MGMT_STATUS_FAILED;
193}
194
Szymon Janc4e51eae2011-02-25 19:05:48 +0100195static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200196{
197 struct sk_buff *skb;
198 struct mgmt_hdr *hdr;
199 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300200 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200201
Szymon Janc34eb5252011-02-28 14:10:08 +0100202 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200203
Andre Guedes790eff42012-06-07 19:05:46 -0300204 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200205 if (!skb)
206 return -ENOMEM;
207
208 hdr = (void *) skb_put(skb, sizeof(*hdr));
209
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530210 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100211 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212 hdr->len = cpu_to_le16(sizeof(*ev));
213
214 ev = (void *) skb_put(skb, sizeof(*ev));
215 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200216 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200217
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300218 err = sock_queue_rcv_skb(sk, skb);
219 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200220 kfree_skb(skb);
221
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300222 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223}
224
Johan Hedbergaee9b212012-02-18 15:07:59 +0200225static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300226 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200227{
228 struct sk_buff *skb;
229 struct mgmt_hdr *hdr;
230 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300231 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200232
233 BT_DBG("sock %p", sk);
234
Andre Guedes790eff42012-06-07 19:05:46 -0300235 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200236 if (!skb)
237 return -ENOMEM;
238
239 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200240
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530241 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100242 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200243 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200244
Johan Hedberga38528f2011-01-22 06:46:43 +0200245 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200246 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200247 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100248
249 if (rp)
250 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300252 err = sock_queue_rcv_skb(sk, skb);
253 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200254 kfree_skb(skb);
255
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100256 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200257}
258
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300259static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
260 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200261{
262 struct mgmt_rp_read_version rp;
263
264 BT_DBG("sock %p", sk);
265
266 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200267 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200268
Johan Hedbergaee9b212012-02-18 15:07:59 +0200269 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300270 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200271}
272
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
274 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200275{
276 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200277 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
278 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200279 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200280 size_t rp_size;
281 int i, err;
282
283 BT_DBG("sock %p", sk);
284
285 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
286
287 rp = kmalloc(rp_size, GFP_KERNEL);
288 if (!rp)
289 return -ENOMEM;
290
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200291 rp->num_commands = __constant_cpu_to_le16(num_commands);
292 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200293
294 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
295 put_unaligned_le16(mgmt_commands[i], opcode);
296
297 for (i = 0; i < num_events; i++, opcode++)
298 put_unaligned_le16(mgmt_events[i], opcode);
299
Johan Hedbergaee9b212012-02-18 15:07:59 +0200300 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300301 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200302 kfree(rp);
303
304 return err;
305}
306
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300307static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
308 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200309{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200310 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200311 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200312 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300314 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315
316 BT_DBG("sock %p", sk);
317
318 read_lock(&hci_dev_list_lock);
319
320 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300321 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700322 if (d->dev_type == HCI_BREDR)
323 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324 }
325
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 rp_len = sizeof(*rp) + (2 * count);
327 rp = kmalloc(rp_len, GFP_ATOMIC);
328 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100329 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100331 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200332
Johan Hedberg476e44c2012-10-19 20:10:46 +0300333 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200334 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200335 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200336 continue;
337
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700338 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
339 continue;
340
Marcel Holtmann1514b892013-10-06 08:25:01 -0700341 if (d->dev_type == HCI_BREDR) {
342 rp->index[count++] = cpu_to_le16(d->id);
343 BT_DBG("Added hci%u", d->id);
344 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345 }
346
Johan Hedberg476e44c2012-10-19 20:10:46 +0300347 rp->num_controllers = cpu_to_le16(count);
348 rp_len = sizeof(*rp) + (2 * count);
349
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 read_unlock(&hci_dev_list_lock);
351
Johan Hedbergaee9b212012-02-18 15:07:59 +0200352 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300353 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
Johan Hedberga38528f2011-01-22 06:46:43 +0200355 kfree(rp);
356
357 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358}
359
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200360static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200361{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200366
Andre Guedesed3fa312012-07-24 15:03:46 -0300367 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300368 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500369 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
370 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300371 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 settings |= MGMT_SETTING_BREDR;
373 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700374
375 if (lmp_ssp_capable(hdev)) {
376 settings |= MGMT_SETTING_SSP;
377 settings |= MGMT_SETTING_HS;
378 }
Marcel Holtmann848566b2013-10-01 22:59:22 -0700379 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300381 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200382 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300383 settings |= MGMT_SETTING_ADVERTISING;
384 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200385
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200386 return settings;
387}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200388
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389static u32 get_current_settings(struct hci_dev *hdev)
390{
391 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200392
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200393 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100394 settings |= MGMT_SETTING_POWERED;
395
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200396 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200397 settings |= MGMT_SETTING_CONNECTABLE;
398
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500399 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
400 settings |= MGMT_SETTING_FAST_CONNECTABLE;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_DISCOVERABLE;
404
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200405 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_PAIRABLE;
407
Johan Hedberg56f87902013-10-02 13:43:13 +0300408 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_BREDR;
410
Johan Hedberg06199cf2012-02-22 16:37:11 +0200411 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200413
Johan Hedberg47990ea2012-02-22 11:58:37 +0200414 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200416
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200417 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200419
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200420 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
421 settings |= MGMT_SETTING_HS;
422
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200423 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300424 settings |= MGMT_SETTING_ADVERTISING;
425
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200426 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200427}
428
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300429#define PNP_INFO_SVCLASS_ID 0x1200
430
Johan Hedberg213202e2013-01-27 00:31:33 +0200431static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
432{
433 u8 *ptr = data, *uuids_start = NULL;
434 struct bt_uuid *uuid;
435
436 if (len < 4)
437 return ptr;
438
439 list_for_each_entry(uuid, &hdev->uuids, list) {
440 u16 uuid16;
441
442 if (uuid->size != 16)
443 continue;
444
445 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
446 if (uuid16 < 0x1100)
447 continue;
448
449 if (uuid16 == PNP_INFO_SVCLASS_ID)
450 continue;
451
452 if (!uuids_start) {
453 uuids_start = ptr;
454 uuids_start[0] = 1;
455 uuids_start[1] = EIR_UUID16_ALL;
456 ptr += 2;
457 }
458
459 /* Stop if not enough space to put next UUID */
460 if ((ptr - data) + sizeof(u16) > len) {
461 uuids_start[1] = EIR_UUID16_SOME;
462 break;
463 }
464
465 *ptr++ = (uuid16 & 0x00ff);
466 *ptr++ = (uuid16 & 0xff00) >> 8;
467 uuids_start[0] += sizeof(uuid16);
468 }
469
470 return ptr;
471}
472
Johan Hedbergcdf19632013-01-27 00:31:34 +0200473static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
474{
475 u8 *ptr = data, *uuids_start = NULL;
476 struct bt_uuid *uuid;
477
478 if (len < 6)
479 return ptr;
480
481 list_for_each_entry(uuid, &hdev->uuids, list) {
482 if (uuid->size != 32)
483 continue;
484
485 if (!uuids_start) {
486 uuids_start = ptr;
487 uuids_start[0] = 1;
488 uuids_start[1] = EIR_UUID32_ALL;
489 ptr += 2;
490 }
491
492 /* Stop if not enough space to put next UUID */
493 if ((ptr - data) + sizeof(u32) > len) {
494 uuids_start[1] = EIR_UUID32_SOME;
495 break;
496 }
497
498 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
499 ptr += sizeof(u32);
500 uuids_start[0] += sizeof(u32);
501 }
502
503 return ptr;
504}
505
Johan Hedbergc00d5752013-01-27 00:31:35 +0200506static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
507{
508 u8 *ptr = data, *uuids_start = NULL;
509 struct bt_uuid *uuid;
510
511 if (len < 18)
512 return ptr;
513
514 list_for_each_entry(uuid, &hdev->uuids, list) {
515 if (uuid->size != 128)
516 continue;
517
518 if (!uuids_start) {
519 uuids_start = ptr;
520 uuids_start[0] = 1;
521 uuids_start[1] = EIR_UUID128_ALL;
522 ptr += 2;
523 }
524
525 /* Stop if not enough space to put next UUID */
526 if ((ptr - data) + 16 > len) {
527 uuids_start[1] = EIR_UUID128_SOME;
528 break;
529 }
530
531 memcpy(ptr, uuid->uuid, 16);
532 ptr += 16;
533 uuids_start[0] += 16;
534 }
535
536 return ptr;
537}
538
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 Hedbergaee9b212012-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 Hedbergeec8d2b2010-12-16 10:17:38 +02001147 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1148 if (!cmd) {
1149 err = -ENOMEM;
1150 goto failed;
1151 }
1152
Johan Hedberg2b76f452013-03-15 17:07:04 -05001153 hci_req_init(&req, hdev);
1154
Johan Hedberg9b742462013-10-14 16:20:03 +03001155 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1156 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
1157
1158 if (cp->val) {
1159 scan = SCAN_PAGE;
1160 } else {
1161 scan = 0;
1162
1163 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1164 hdev->discov_timeout > 0)
1165 cancel_delayed_work(&hdev->discov_off);
1166 }
1167
1168 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1169 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001170
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001171 /* If we're going from non-connectable to connectable or
1172 * vice-versa when fast connectable is enabled ensure that fast
1173 * connectable gets disabled. write_fast_connectable won't do
1174 * anything if the page scan parameters are already what they
1175 * should be.
1176 */
1177 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001178 write_fast_connectable(&req, false);
1179
Johan Hedberg2b76f452013-03-15 17:07:04 -05001180 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001181 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001182 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001183 if (err == -ENODATA)
1184 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1185 hdev);
1186 goto failed;
1187 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001188
1189failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001190 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001191 return err;
1192}
1193
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001194static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001195 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001196{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001197 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001198 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001199 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001200
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001201 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001202
Johan Hedberga7e80f22013-01-09 16:05:19 +02001203 if (cp->val != 0x00 && cp->val != 0x01)
1204 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1205 MGMT_STATUS_INVALID_PARAMS);
1206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001207 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001208
1209 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001210 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001211 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001212 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001213
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001214 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001215 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001216 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001217
Marcel Holtmann55594352013-10-06 16:11:57 -07001218 if (changed)
1219 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001220
Marcel Holtmann55594352013-10-06 16:11:57 -07001221unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001222 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001223 return err;
1224}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001225
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001226static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1227 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001228{
1229 struct mgmt_mode *cp = data;
1230 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001231 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001232 int err;
1233
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001234 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001235
Johan Hedberge6fe7982013-10-02 15:45:22 +03001236 status = mgmt_bredr_support(hdev);
1237 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001238 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001239 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001240
Johan Hedberga7e80f22013-01-09 16:05:19 +02001241 if (cp->val != 0x00 && cp->val != 0x01)
1242 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1243 MGMT_STATUS_INVALID_PARAMS);
1244
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001245 hci_dev_lock(hdev);
1246
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001247 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001248 bool changed = false;
1249
1250 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001251 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001252 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1253 changed = true;
1254 }
1255
1256 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1257 if (err < 0)
1258 goto failed;
1259
1260 if (changed)
1261 err = new_settings(hdev, sk);
1262
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001263 goto failed;
1264 }
1265
1266 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001267 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001268 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001269 goto failed;
1270 }
1271
1272 val = !!cp->val;
1273
1274 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1275 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1276 goto failed;
1277 }
1278
1279 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1280 if (!cmd) {
1281 err = -ENOMEM;
1282 goto failed;
1283 }
1284
1285 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1286 if (err < 0) {
1287 mgmt_pending_remove(cmd);
1288 goto failed;
1289 }
1290
1291failed:
1292 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001293 return err;
1294}
1295
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001296static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001297{
1298 struct mgmt_mode *cp = data;
1299 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001300 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001301 int err;
1302
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001303 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001304
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001305 status = mgmt_bredr_support(hdev);
1306 if (status)
1307 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1308
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001309 if (!lmp_ssp_capable(hdev))
1310 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1311 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001312
Johan Hedberga7e80f22013-01-09 16:05:19 +02001313 if (cp->val != 0x00 && cp->val != 0x01)
1314 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1315 MGMT_STATUS_INVALID_PARAMS);
1316
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001317 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001318
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001319 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001320 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001321
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001322 if (cp->val) {
1323 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1324 &hdev->dev_flags);
1325 } else {
1326 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1327 &hdev->dev_flags);
1328 if (!changed)
1329 changed = test_and_clear_bit(HCI_HS_ENABLED,
1330 &hdev->dev_flags);
1331 else
1332 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001333 }
1334
1335 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1336 if (err < 0)
1337 goto failed;
1338
1339 if (changed)
1340 err = new_settings(hdev, sk);
1341
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001342 goto failed;
1343 }
1344
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001345 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1346 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001347 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1348 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001349 goto failed;
1350 }
1351
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001352 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001353 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1354 goto failed;
1355 }
1356
1357 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1358 if (!cmd) {
1359 err = -ENOMEM;
1360 goto failed;
1361 }
1362
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001363 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001364 if (err < 0) {
1365 mgmt_pending_remove(cmd);
1366 goto failed;
1367 }
1368
1369failed:
1370 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001371 return err;
1372}
1373
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001374static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001375{
1376 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001377 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001378 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001379 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001380
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001381 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001382
Johan Hedberge6fe7982013-10-02 15:45:22 +03001383 status = mgmt_bredr_support(hdev);
1384 if (status)
1385 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001386
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001387 if (!lmp_ssp_capable(hdev))
1388 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1389 MGMT_STATUS_NOT_SUPPORTED);
1390
1391 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1392 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1393 MGMT_STATUS_REJECTED);
1394
Johan Hedberga7e80f22013-01-09 16:05:19 +02001395 if (cp->val != 0x00 && cp->val != 0x01)
1396 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1397 MGMT_STATUS_INVALID_PARAMS);
1398
Marcel Holtmannee392692013-10-01 22:59:23 -07001399 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001400
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001401 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001402 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001403 } else {
1404 if (hdev_is_powered(hdev)) {
1405 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1406 MGMT_STATUS_REJECTED);
1407 goto unlock;
1408 }
1409
Marcel Holtmannee392692013-10-01 22:59:23 -07001410 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001411 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001412
1413 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1414 if (err < 0)
1415 goto unlock;
1416
1417 if (changed)
1418 err = new_settings(hdev, sk);
1419
1420unlock:
1421 hci_dev_unlock(hdev);
1422 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001423}
1424
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001425static void enable_advertising(struct hci_request *req)
1426{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001427 struct hci_dev *hdev = req->hdev;
1428 struct hci_cp_le_set_adv_param cp;
1429 u8 enable = 0x01;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001430
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001431 memset(&cp, 0, sizeof(cp));
1432 cp.min_interval = __constant_cpu_to_le16(0x0800);
1433 cp.max_interval = __constant_cpu_to_le16(0x0800);
1434 cp.type = LE_ADV_IND;
1435 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1436 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1437 else
1438 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1439 cp.channel_map = 0x07;
1440
1441 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1442
1443 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001444}
1445
1446static void disable_advertising(struct hci_request *req)
1447{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001448 u8 enable = 0x00;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001449
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001450 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001451}
1452
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001453static void le_enable_complete(struct hci_dev *hdev, u8 status)
1454{
1455 struct cmd_lookup match = { NULL, hdev };
1456
1457 if (status) {
1458 u8 mgmt_err = mgmt_status(status);
1459
1460 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1461 &mgmt_err);
1462 return;
1463 }
1464
1465 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1466
1467 new_settings(hdev, match.sk);
1468
1469 if (match.sk)
1470 sock_put(match.sk);
1471}
1472
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001473static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001474{
1475 struct mgmt_mode *cp = data;
1476 struct hci_cp_write_le_host_supported hci_cp;
1477 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001478 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001479 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001480 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001481
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001482 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001483
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001484 if (!lmp_le_capable(hdev))
1485 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1486 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001487
Johan Hedberga7e80f22013-01-09 16:05:19 +02001488 if (cp->val != 0x00 && cp->val != 0x01)
1489 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1490 MGMT_STATUS_INVALID_PARAMS);
1491
Johan Hedbergc73eee92013-04-19 18:35:21 +03001492 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001493 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001494 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1495 MGMT_STATUS_REJECTED);
1496
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001497 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001498
1499 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001500 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001501
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001502 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001503 bool changed = false;
1504
1505 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1506 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1507 changed = true;
1508 }
1509
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001510 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1511 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001512 changed = true;
1513 }
1514
Johan Hedberg06199cf2012-02-22 16:37:11 +02001515 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1516 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001517 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001518
1519 if (changed)
1520 err = new_settings(hdev, sk);
1521
Johan Hedberg1de028c2012-02-29 19:55:35 -08001522 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001523 }
1524
Johan Hedberg4375f102013-09-25 13:26:10 +03001525 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1526 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001527 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001528 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001529 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001530 }
1531
1532 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1533 if (!cmd) {
1534 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001535 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001536 }
1537
1538 memset(&hci_cp, 0, sizeof(hci_cp));
1539
1540 if (val) {
1541 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001542 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001543 }
1544
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001545 hci_req_init(&req, hdev);
1546
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001547 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1548 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001549
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001550 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1551 &hci_cp);
1552
1553 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301554 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001555 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001556
Johan Hedberg1de028c2012-02-29 19:55:35 -08001557unlock:
1558 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001559 return err;
1560}
1561
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001562/* This is a helper function to test for pending mgmt commands that can
1563 * cause CoD or EIR HCI commands. We can only allow one such pending
1564 * mgmt command at a time since otherwise we cannot easily track what
1565 * the current values are, will be, and based on that calculate if a new
1566 * HCI command needs to be sent and if yes with what value.
1567 */
1568static bool pending_eir_or_class(struct hci_dev *hdev)
1569{
1570 struct pending_cmd *cmd;
1571
1572 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1573 switch (cmd->opcode) {
1574 case MGMT_OP_ADD_UUID:
1575 case MGMT_OP_REMOVE_UUID:
1576 case MGMT_OP_SET_DEV_CLASS:
1577 case MGMT_OP_SET_POWERED:
1578 return true;
1579 }
1580 }
1581
1582 return false;
1583}
1584
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001585static const u8 bluetooth_base_uuid[] = {
1586 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1587 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1588};
1589
1590static u8 get_uuid_size(const u8 *uuid)
1591{
1592 u32 val;
1593
1594 if (memcmp(uuid, bluetooth_base_uuid, 12))
1595 return 128;
1596
1597 val = get_unaligned_le32(&uuid[12]);
1598 if (val > 0xffff)
1599 return 32;
1600
1601 return 16;
1602}
1603
Johan Hedberg92da6092013-03-15 17:06:55 -05001604static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1605{
1606 struct pending_cmd *cmd;
1607
1608 hci_dev_lock(hdev);
1609
1610 cmd = mgmt_pending_find(mgmt_op, hdev);
1611 if (!cmd)
1612 goto unlock;
1613
1614 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1615 hdev->dev_class, 3);
1616
1617 mgmt_pending_remove(cmd);
1618
1619unlock:
1620 hci_dev_unlock(hdev);
1621}
1622
1623static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1624{
1625 BT_DBG("status 0x%02x", status);
1626
1627 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1628}
1629
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001630static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001631{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001632 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001633 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001634 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001635 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001636 int err;
1637
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001638 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001639
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001640 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001641
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001642 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001643 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001644 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001645 goto failed;
1646 }
1647
Andre Guedes92c4c202012-06-07 19:05:44 -03001648 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001649 if (!uuid) {
1650 err = -ENOMEM;
1651 goto failed;
1652 }
1653
1654 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001655 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001656 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001657
Johan Hedbergde66aa62013-01-27 00:31:27 +02001658 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001659
Johan Hedberg890ea892013-03-15 17:06:52 -05001660 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001661
Johan Hedberg890ea892013-03-15 17:06:52 -05001662 update_class(&req);
1663 update_eir(&req);
1664
Johan Hedberg92da6092013-03-15 17:06:55 -05001665 err = hci_req_run(&req, add_uuid_complete);
1666 if (err < 0) {
1667 if (err != -ENODATA)
1668 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001669
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001670 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001671 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001672 goto failed;
1673 }
1674
1675 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001676 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001677 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001678 goto failed;
1679 }
1680
1681 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001682
1683failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001684 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001685 return err;
1686}
1687
Johan Hedberg24b78d02012-02-23 23:24:30 +02001688static bool enable_service_cache(struct hci_dev *hdev)
1689{
1690 if (!hdev_is_powered(hdev))
1691 return false;
1692
1693 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001694 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1695 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001696 return true;
1697 }
1698
1699 return false;
1700}
1701
Johan Hedberg92da6092013-03-15 17:06:55 -05001702static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1703{
1704 BT_DBG("status 0x%02x", status);
1705
1706 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1707}
1708
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001709static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001710 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001711{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001712 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001713 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001714 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001715 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 -05001716 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001717 int err, found;
1718
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001719 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001720
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001721 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001722
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001723 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001724 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001725 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001726 goto unlock;
1727 }
1728
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001729 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1730 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001731
Johan Hedberg24b78d02012-02-23 23:24:30 +02001732 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001733 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001734 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001735 goto unlock;
1736 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001737
Johan Hedberg9246a862012-02-23 21:33:16 +02001738 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001739 }
1740
1741 found = 0;
1742
Johan Hedberg056341c2013-01-27 00:31:30 +02001743 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001744 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1745 continue;
1746
1747 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001748 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001749 found++;
1750 }
1751
1752 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001753 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001754 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001755 goto unlock;
1756 }
1757
Johan Hedberg9246a862012-02-23 21:33:16 +02001758update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001759 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001760
Johan Hedberg890ea892013-03-15 17:06:52 -05001761 update_class(&req);
1762 update_eir(&req);
1763
Johan Hedberg92da6092013-03-15 17:06:55 -05001764 err = hci_req_run(&req, remove_uuid_complete);
1765 if (err < 0) {
1766 if (err != -ENODATA)
1767 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001768
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001769 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001770 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001771 goto unlock;
1772 }
1773
1774 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001775 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001776 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001777 goto unlock;
1778 }
1779
1780 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001781
1782unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001783 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001784 return err;
1785}
1786
Johan Hedberg92da6092013-03-15 17:06:55 -05001787static void set_class_complete(struct hci_dev *hdev, u8 status)
1788{
1789 BT_DBG("status 0x%02x", status);
1790
1791 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1792}
1793
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001794static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001795 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001796{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001797 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001798 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001799 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001800 int err;
1801
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001802 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001803
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001804 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001805 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1806 MGMT_STATUS_NOT_SUPPORTED);
1807
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001808 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001809
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001810 if (pending_eir_or_class(hdev)) {
1811 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1812 MGMT_STATUS_BUSY);
1813 goto unlock;
1814 }
1815
1816 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1817 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1818 MGMT_STATUS_INVALID_PARAMS);
1819 goto unlock;
1820 }
1821
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001822 hdev->major_class = cp->major;
1823 hdev->minor_class = cp->minor;
1824
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001825 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001826 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001827 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001828 goto unlock;
1829 }
1830
Johan Hedberg890ea892013-03-15 17:06:52 -05001831 hci_req_init(&req, hdev);
1832
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001833 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001834 hci_dev_unlock(hdev);
1835 cancel_delayed_work_sync(&hdev->service_cache);
1836 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001837 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001838 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001839
Johan Hedberg890ea892013-03-15 17:06:52 -05001840 update_class(&req);
1841
Johan Hedberg92da6092013-03-15 17:06:55 -05001842 err = hci_req_run(&req, set_class_complete);
1843 if (err < 0) {
1844 if (err != -ENODATA)
1845 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001846
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001847 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001848 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001849 goto unlock;
1850 }
1851
1852 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001853 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001854 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001855 goto unlock;
1856 }
1857
1858 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001859
Johan Hedbergb5235a62012-02-21 14:32:24 +02001860unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001861 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001862 return err;
1863}
1864
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001865static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001866 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001867{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001868 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001869 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001870 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001871
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001872 BT_DBG("request for %s", hdev->name);
1873
1874 if (!lmp_bredr_capable(hdev))
1875 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1876 MGMT_STATUS_NOT_SUPPORTED);
1877
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001878 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001879
Johan Hedberg86742e12011-11-07 23:13:38 +02001880 expected_len = sizeof(*cp) + key_count *
1881 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001882 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001883 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001884 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001885 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001886 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001887 }
1888
Johan Hedberg4ae14302013-01-20 14:27:13 +02001889 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1890 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1891 MGMT_STATUS_INVALID_PARAMS);
1892
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001893 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001894 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001895
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001896 for (i = 0; i < key_count; i++) {
1897 struct mgmt_link_key_info *key = &cp->keys[i];
1898
1899 if (key->addr.type != BDADDR_BREDR)
1900 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1901 MGMT_STATUS_INVALID_PARAMS);
1902 }
1903
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001904 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001905
1906 hci_link_keys_clear(hdev);
1907
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001908 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001909 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001910 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001911 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001912
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001913 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001914 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001915
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001916 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001917 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001918 }
1919
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001920 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001921
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001922 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001923
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001924 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001925}
1926
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001927static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001928 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001929{
1930 struct mgmt_ev_device_unpaired ev;
1931
1932 bacpy(&ev.addr.bdaddr, bdaddr);
1933 ev.addr.type = addr_type;
1934
1935 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001936 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001937}
1938
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001939static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001940 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001941{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001942 struct mgmt_cp_unpair_device *cp = data;
1943 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001944 struct hci_cp_disconnect dc;
1945 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001946 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001947 int err;
1948
Johan Hedberga8a1d192011-11-10 15:54:38 +02001949 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001950 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1951 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001952
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001953 if (!bdaddr_type_is_valid(cp->addr.type))
1954 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1955 MGMT_STATUS_INVALID_PARAMS,
1956 &rp, sizeof(rp));
1957
Johan Hedberg118da702013-01-20 14:27:20 +02001958 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1959 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1960 MGMT_STATUS_INVALID_PARAMS,
1961 &rp, sizeof(rp));
1962
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001963 hci_dev_lock(hdev);
1964
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001965 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001966 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001967 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001968 goto unlock;
1969 }
1970
Andre Guedes591f47f2012-04-24 21:02:49 -03001971 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001972 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1973 else
1974 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001975
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001976 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001977 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001978 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001979 goto unlock;
1980 }
1981
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001982 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001983 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001984 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001985 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001986 else
1987 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001988 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001989 } else {
1990 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001991 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001992
Johan Hedberga8a1d192011-11-10 15:54:38 +02001993 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001994 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001995 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001996 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001997 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001998 }
1999
Johan Hedberg124f6e32012-02-09 13:50:12 +02002000 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002001 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002002 if (!cmd) {
2003 err = -ENOMEM;
2004 goto unlock;
2005 }
2006
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002007 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002008 dc.reason = 0x13; /* Remote User Terminated Connection */
2009 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2010 if (err < 0)
2011 mgmt_pending_remove(cmd);
2012
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002013unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002014 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002015 return err;
2016}
2017
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002018static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002019 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002020{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002021 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002022 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002023 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002024 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002025 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002026 int err;
2027
2028 BT_DBG("");
2029
Johan Hedberg06a63b12013-01-20 14:27:21 +02002030 memset(&rp, 0, sizeof(rp));
2031 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2032 rp.addr.type = cp->addr.type;
2033
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002034 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002035 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2036 MGMT_STATUS_INVALID_PARAMS,
2037 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002038
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002039 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002040
2041 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002042 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2043 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002044 goto failed;
2045 }
2046
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002047 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002048 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2049 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002050 goto failed;
2051 }
2052
Andre Guedes591f47f2012-04-24 21:02:49 -03002053 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002054 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2055 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002056 else
2057 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002058
Vishal Agarwalf9607272012-06-13 05:32:43 +05302059 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002060 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2061 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002062 goto failed;
2063 }
2064
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002065 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002066 if (!cmd) {
2067 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002068 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002069 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002070
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002071 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002072 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002073
2074 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2075 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002076 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002077
2078failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002079 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002080 return err;
2081}
2082
Andre Guedes57c14772012-04-24 21:02:50 -03002083static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002084{
2085 switch (link_type) {
2086 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002087 switch (addr_type) {
2088 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002089 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002090
Johan Hedberg48264f02011-11-09 13:58:58 +02002091 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002092 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002093 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002094 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002095
Johan Hedberg4c659c32011-11-07 23:13:39 +02002096 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002097 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002098 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002099 }
2100}
2101
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002102static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2103 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002104{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002105 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002106 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002107 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002108 int err;
2109 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002110
2111 BT_DBG("");
2112
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002113 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002114
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002115 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002116 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002117 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002118 goto unlock;
2119 }
2120
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002121 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002122 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2123 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002124 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002125 }
2126
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002127 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002128 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002129 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002130 err = -ENOMEM;
2131 goto unlock;
2132 }
2133
Johan Hedberg2784eb42011-01-21 13:56:35 +02002134 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002135 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002136 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2137 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002138 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002139 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002140 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002141 continue;
2142 i++;
2143 }
2144
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002145 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002146
Johan Hedberg4c659c32011-11-07 23:13:39 +02002147 /* Recalculate length in case of filtered SCO connections, etc */
2148 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002149
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002150 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002151 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002152
Johan Hedberga38528f2011-01-22 06:46:43 +02002153 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002154
2155unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002156 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002157 return err;
2158}
2159
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002160static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002161 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002162{
2163 struct pending_cmd *cmd;
2164 int err;
2165
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002166 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002167 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002168 if (!cmd)
2169 return -ENOMEM;
2170
Johan Hedbergd8457692012-02-17 14:24:57 +02002171 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002172 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002173 if (err < 0)
2174 mgmt_pending_remove(cmd);
2175
2176 return err;
2177}
2178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002179static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002180 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002181{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002182 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002183 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002184 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002185 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002186 int err;
2187
2188 BT_DBG("");
2189
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002190 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002191
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002192 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002193 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002194 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002195 goto failed;
2196 }
2197
Johan Hedbergd8457692012-02-17 14:24:57 +02002198 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002199 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002200 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002201 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002202 goto failed;
2203 }
2204
2205 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002206 struct mgmt_cp_pin_code_neg_reply ncp;
2207
2208 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002209
2210 BT_ERR("PIN code is not 16 bytes long");
2211
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002212 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002213 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002214 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002215 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002216
2217 goto failed;
2218 }
2219
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002220 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002221 if (!cmd) {
2222 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002223 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002224 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002225
Johan Hedbergd8457692012-02-17 14:24:57 +02002226 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002227 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002228 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002229
2230 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2231 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002232 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002233
2234failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002235 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002236 return err;
2237}
2238
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002239static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2240 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002241{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002242 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002243
2244 BT_DBG("");
2245
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002246 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002247
2248 hdev->io_capability = cp->io_capability;
2249
2250 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002251 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002252
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002253 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002254
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002255 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2256 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002257}
2258
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002259static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002260{
2261 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002262 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002263
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002264 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002265 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2266 continue;
2267
Johan Hedberge9a416b2011-02-19 12:05:56 -03002268 if (cmd->user_data != conn)
2269 continue;
2270
2271 return cmd;
2272 }
2273
2274 return NULL;
2275}
2276
2277static void pairing_complete(struct pending_cmd *cmd, u8 status)
2278{
2279 struct mgmt_rp_pair_device rp;
2280 struct hci_conn *conn = cmd->user_data;
2281
Johan Hedbergba4e5642011-11-11 00:07:34 +02002282 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002283 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002284
Johan Hedbergaee9b212012-02-18 15:07:59 +02002285 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002286 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002287
2288 /* So we don't get further callbacks for this connection */
2289 conn->connect_cfm_cb = NULL;
2290 conn->security_cfm_cb = NULL;
2291 conn->disconn_cfm_cb = NULL;
2292
David Herrmann76a68ba2013-04-06 20:28:37 +02002293 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002294
Johan Hedberga664b5b2011-02-19 12:06:02 -03002295 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002296}
2297
2298static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2299{
2300 struct pending_cmd *cmd;
2301
2302 BT_DBG("status %u", status);
2303
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002304 cmd = find_pairing(conn);
2305 if (!cmd)
2306 BT_DBG("Unable to find a pending command");
2307 else
Johan Hedberge2113262012-02-18 15:20:03 +02002308 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002309}
2310
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302311static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2312{
2313 struct pending_cmd *cmd;
2314
2315 BT_DBG("status %u", status);
2316
2317 if (!status)
2318 return;
2319
2320 cmd = find_pairing(conn);
2321 if (!cmd)
2322 BT_DBG("Unable to find a pending command");
2323 else
2324 pairing_complete(cmd, mgmt_status(status));
2325}
2326
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002327static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002328 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002329{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002330 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002331 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002332 struct pending_cmd *cmd;
2333 u8 sec_level, auth_type;
2334 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002335 int err;
2336
2337 BT_DBG("");
2338
Szymon Jancf950a30e2013-01-18 12:48:07 +01002339 memset(&rp, 0, sizeof(rp));
2340 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2341 rp.addr.type = cp->addr.type;
2342
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002343 if (!bdaddr_type_is_valid(cp->addr.type))
2344 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2345 MGMT_STATUS_INVALID_PARAMS,
2346 &rp, sizeof(rp));
2347
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002348 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002349
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002350 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002351 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2352 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002353 goto unlock;
2354 }
2355
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002356 sec_level = BT_SECURITY_MEDIUM;
2357 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002358 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002359 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002360 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002361
Andre Guedes591f47f2012-04-24 21:02:49 -03002362 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002363 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2364 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002365 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002366 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2367 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002368
Ville Tervo30e76272011-02-22 16:10:53 -03002369 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002370 int status;
2371
2372 if (PTR_ERR(conn) == -EBUSY)
2373 status = MGMT_STATUS_BUSY;
2374 else
2375 status = MGMT_STATUS_CONNECT_FAILED;
2376
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002377 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002378 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002379 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002380 goto unlock;
2381 }
2382
2383 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002384 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002385 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002386 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002387 goto unlock;
2388 }
2389
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002390 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002391 if (!cmd) {
2392 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002393 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002394 goto unlock;
2395 }
2396
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002397 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002398 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002399 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302400 else
2401 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002402
Johan Hedberge9a416b2011-02-19 12:05:56 -03002403 conn->security_cfm_cb = pairing_complete_cb;
2404 conn->disconn_cfm_cb = pairing_complete_cb;
2405 conn->io_capability = cp->io_cap;
2406 cmd->user_data = conn;
2407
2408 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002409 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002410 pairing_complete(cmd, 0);
2411
2412 err = 0;
2413
2414unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002415 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002416 return err;
2417}
2418
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002419static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2420 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002421{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002422 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002423 struct pending_cmd *cmd;
2424 struct hci_conn *conn;
2425 int err;
2426
2427 BT_DBG("");
2428
Johan Hedberg28424702012-02-02 04:02:29 +02002429 hci_dev_lock(hdev);
2430
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002431 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002432 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002433 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002434 goto unlock;
2435 }
2436
Johan Hedberg28424702012-02-02 04:02:29 +02002437 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2438 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002439 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002440 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002441 goto unlock;
2442 }
2443
2444 conn = cmd->user_data;
2445
2446 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002447 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002448 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002449 goto unlock;
2450 }
2451
2452 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2453
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002454 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002455 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002456unlock:
2457 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002458 return err;
2459}
2460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002461static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002462 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002463 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002464{
Johan Hedberga5c29682011-02-19 12:05:57 -03002465 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002466 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002467 int err;
2468
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002469 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002470
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002471 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002472 err = cmd_complete(sk, hdev->id, mgmt_op,
2473 MGMT_STATUS_NOT_POWERED, addr,
2474 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002475 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002476 }
2477
Johan Hedberg1707c602013-03-15 17:07:15 -05002478 if (addr->type == BDADDR_BREDR)
2479 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002480 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002481 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002482
Johan Hedberg272d90d2012-02-09 15:26:12 +02002483 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002484 err = cmd_complete(sk, hdev->id, mgmt_op,
2485 MGMT_STATUS_NOT_CONNECTED, addr,
2486 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002487 goto done;
2488 }
2489
Johan Hedberg1707c602013-03-15 17:07:15 -05002490 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002491 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002492 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002493
Brian Gix5fe57d92011-12-21 16:12:13 -08002494 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002495 err = cmd_complete(sk, hdev->id, mgmt_op,
2496 MGMT_STATUS_SUCCESS, addr,
2497 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002498 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002499 err = cmd_complete(sk, hdev->id, mgmt_op,
2500 MGMT_STATUS_FAILED, addr,
2501 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002502
Brian Gix47c15e22011-11-16 13:53:14 -08002503 goto done;
2504 }
2505
Johan Hedberg1707c602013-03-15 17:07:15 -05002506 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002507 if (!cmd) {
2508 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002509 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002510 }
2511
Brian Gix0df4c182011-11-16 13:53:13 -08002512 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002513 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2514 struct hci_cp_user_passkey_reply cp;
2515
Johan Hedberg1707c602013-03-15 17:07:15 -05002516 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002517 cp.passkey = passkey;
2518 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2519 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002520 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2521 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002522
Johan Hedberga664b5b2011-02-19 12:06:02 -03002523 if (err < 0)
2524 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002525
Brian Gix0df4c182011-11-16 13:53:13 -08002526done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002527 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002528 return err;
2529}
2530
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302531static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2532 void *data, u16 len)
2533{
2534 struct mgmt_cp_pin_code_neg_reply *cp = data;
2535
2536 BT_DBG("");
2537
Johan Hedberg1707c602013-03-15 17:07:15 -05002538 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302539 MGMT_OP_PIN_CODE_NEG_REPLY,
2540 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2541}
2542
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002543static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2544 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002545{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002546 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002547
2548 BT_DBG("");
2549
2550 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002551 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002552 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002553
Johan Hedberg1707c602013-03-15 17:07:15 -05002554 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002555 MGMT_OP_USER_CONFIRM_REPLY,
2556 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002557}
2558
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002559static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002560 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002561{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002562 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002563
2564 BT_DBG("");
2565
Johan Hedberg1707c602013-03-15 17:07:15 -05002566 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002567 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2568 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002569}
2570
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002571static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2572 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002573{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002574 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002575
2576 BT_DBG("");
2577
Johan Hedberg1707c602013-03-15 17:07:15 -05002578 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002579 MGMT_OP_USER_PASSKEY_REPLY,
2580 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002581}
2582
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002583static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002584 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002585{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002586 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002587
2588 BT_DBG("");
2589
Johan Hedberg1707c602013-03-15 17:07:15 -05002590 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002591 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2592 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002593}
2594
Johan Hedberg13928972013-03-15 17:07:00 -05002595static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002596{
Johan Hedberg13928972013-03-15 17:07:00 -05002597 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002598 struct hci_cp_write_local_name cp;
2599
Johan Hedberg13928972013-03-15 17:07:00 -05002600 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002601
Johan Hedberg890ea892013-03-15 17:06:52 -05002602 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002603}
2604
Johan Hedberg13928972013-03-15 17:07:00 -05002605static void set_name_complete(struct hci_dev *hdev, u8 status)
2606{
2607 struct mgmt_cp_set_local_name *cp;
2608 struct pending_cmd *cmd;
2609
2610 BT_DBG("status 0x%02x", status);
2611
2612 hci_dev_lock(hdev);
2613
2614 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2615 if (!cmd)
2616 goto unlock;
2617
2618 cp = cmd->param;
2619
2620 if (status)
2621 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2622 mgmt_status(status));
2623 else
2624 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2625 cp, sizeof(*cp));
2626
2627 mgmt_pending_remove(cmd);
2628
2629unlock:
2630 hci_dev_unlock(hdev);
2631}
2632
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002633static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002634 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002635{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002636 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002637 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002638 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002639 int err;
2640
2641 BT_DBG("");
2642
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002643 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002644
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002645 /* If the old values are the same as the new ones just return a
2646 * direct command complete event.
2647 */
2648 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2649 !memcmp(hdev->short_name, cp->short_name,
2650 sizeof(hdev->short_name))) {
2651 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2652 data, len);
2653 goto failed;
2654 }
2655
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002656 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002657
Johan Hedbergb5235a62012-02-21 14:32:24 +02002658 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002659 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002660
2661 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002662 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002663 if (err < 0)
2664 goto failed;
2665
2666 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002667 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002668
Johan Hedbergb5235a62012-02-21 14:32:24 +02002669 goto failed;
2670 }
2671
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002672 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002673 if (!cmd) {
2674 err = -ENOMEM;
2675 goto failed;
2676 }
2677
Johan Hedberg13928972013-03-15 17:07:00 -05002678 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2679
Johan Hedberg890ea892013-03-15 17:06:52 -05002680 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002681
2682 if (lmp_bredr_capable(hdev)) {
2683 update_name(&req);
2684 update_eir(&req);
2685 }
2686
2687 if (lmp_le_capable(hdev))
2688 hci_update_ad(&req);
2689
Johan Hedberg13928972013-03-15 17:07:00 -05002690 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002691 if (err < 0)
2692 mgmt_pending_remove(cmd);
2693
2694failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002695 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002696 return err;
2697}
2698
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002699static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002700 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002701{
Szymon Jancc35938b2011-03-22 13:12:21 +01002702 struct pending_cmd *cmd;
2703 int err;
2704
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002705 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002706
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002707 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002708
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002709 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002710 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002711 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002712 goto unlock;
2713 }
2714
Andre Guedes9a1a1992012-07-24 15:03:48 -03002715 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002716 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002717 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002718 goto unlock;
2719 }
2720
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002721 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002722 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002723 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002724 goto unlock;
2725 }
2726
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002727 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002728 if (!cmd) {
2729 err = -ENOMEM;
2730 goto unlock;
2731 }
2732
2733 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2734 if (err < 0)
2735 mgmt_pending_remove(cmd);
2736
2737unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002738 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002739 return err;
2740}
2741
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002742static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002743 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002744{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002745 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002746 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002747 int err;
2748
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002749 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002750
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002751 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002752
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002753 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002754 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002755 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002756 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002757 else
Szymon Janca6785be2012-12-13 15:11:21 +01002758 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002759
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002760 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002761 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002762
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002763 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002764 return err;
2765}
2766
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002767static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002768 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002769{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002770 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002771 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002772 int err;
2773
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002774 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002775
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002776 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002777
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002778 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002779 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002780 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002781 else
Szymon Janca6785be2012-12-13 15:11:21 +01002782 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002783
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002784 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002785 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002786
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002787 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002788 return err;
2789}
2790
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002791static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2792{
2793 struct pending_cmd *cmd;
2794 u8 type;
2795 int err;
2796
2797 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2798
2799 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2800 if (!cmd)
2801 return -ENOENT;
2802
2803 type = hdev->discovery.type;
2804
2805 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2806 &type, sizeof(type));
2807 mgmt_pending_remove(cmd);
2808
2809 return err;
2810}
2811
Andre Guedes7c307722013-04-30 15:29:28 -03002812static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2813{
2814 BT_DBG("status %d", status);
2815
2816 if (status) {
2817 hci_dev_lock(hdev);
2818 mgmt_start_discovery_failed(hdev, status);
2819 hci_dev_unlock(hdev);
2820 return;
2821 }
2822
2823 hci_dev_lock(hdev);
2824 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2825 hci_dev_unlock(hdev);
2826
2827 switch (hdev->discovery.type) {
2828 case DISCOV_TYPE_LE:
2829 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002830 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002831 break;
2832
2833 case DISCOV_TYPE_INTERLEAVED:
2834 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002835 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002836 break;
2837
2838 case DISCOV_TYPE_BREDR:
2839 break;
2840
2841 default:
2842 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2843 }
2844}
2845
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002846static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002847 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002848{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002849 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002850 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002851 struct hci_cp_le_set_scan_param param_cp;
2852 struct hci_cp_le_set_scan_enable enable_cp;
2853 struct hci_cp_inquiry inq_cp;
2854 struct hci_request req;
2855 /* General inquiry access code (GIAC) */
2856 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002857 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002858 int err;
2859
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002860 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002861
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002862 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002863
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002864 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002865 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002866 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002867 goto failed;
2868 }
2869
Andre Guedes642be6c2012-03-21 00:03:37 -03002870 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2871 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2872 MGMT_STATUS_BUSY);
2873 goto failed;
2874 }
2875
Johan Hedbergff9ef572012-01-04 14:23:45 +02002876 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002877 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002878 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002879 goto failed;
2880 }
2881
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002882 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002883 if (!cmd) {
2884 err = -ENOMEM;
2885 goto failed;
2886 }
2887
Andre Guedes4aab14e2012-02-17 20:39:36 -03002888 hdev->discovery.type = cp->type;
2889
Andre Guedes7c307722013-04-30 15:29:28 -03002890 hci_req_init(&req, hdev);
2891
Andre Guedes4aab14e2012-02-17 20:39:36 -03002892 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002893 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002894 status = mgmt_bredr_support(hdev);
2895 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002896 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002897 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002898 mgmt_pending_remove(cmd);
2899 goto failed;
2900 }
2901
Andre Guedes7c307722013-04-30 15:29:28 -03002902 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2903 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2904 MGMT_STATUS_BUSY);
2905 mgmt_pending_remove(cmd);
2906 goto failed;
2907 }
2908
2909 hci_inquiry_cache_flush(hdev);
2910
2911 memset(&inq_cp, 0, sizeof(inq_cp));
2912 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002913 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002914 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002915 break;
2916
2917 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002918 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002919 status = mgmt_le_support(hdev);
2920 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002921 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002922 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002923 mgmt_pending_remove(cmd);
2924 goto failed;
2925 }
2926
Andre Guedes7c307722013-04-30 15:29:28 -03002927 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002928 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002929 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2930 MGMT_STATUS_NOT_SUPPORTED);
2931 mgmt_pending_remove(cmd);
2932 goto failed;
2933 }
2934
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002935 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002936 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2937 MGMT_STATUS_REJECTED);
2938 mgmt_pending_remove(cmd);
2939 goto failed;
2940 }
2941
2942 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2943 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2944 MGMT_STATUS_BUSY);
2945 mgmt_pending_remove(cmd);
2946 goto failed;
2947 }
2948
2949 memset(&param_cp, 0, sizeof(param_cp));
2950 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002951 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2952 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002953 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2954 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2955 else
2956 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002957 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2958 &param_cp);
2959
2960 memset(&enable_cp, 0, sizeof(enable_cp));
2961 enable_cp.enable = LE_SCAN_ENABLE;
2962 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2963 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2964 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002965 break;
2966
Andre Guedesf39799f2012-02-17 20:39:35 -03002967 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002968 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2969 MGMT_STATUS_INVALID_PARAMS);
2970 mgmt_pending_remove(cmd);
2971 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002972 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002973
Andre Guedes7c307722013-04-30 15:29:28 -03002974 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002975 if (err < 0)
2976 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002977 else
2978 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002979
2980failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002981 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002982 return err;
2983}
2984
Andre Guedes1183fdc2013-04-30 15:29:35 -03002985static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2986{
2987 struct pending_cmd *cmd;
2988 int err;
2989
2990 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2991 if (!cmd)
2992 return -ENOENT;
2993
2994 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2995 &hdev->discovery.type, sizeof(hdev->discovery.type));
2996 mgmt_pending_remove(cmd);
2997
2998 return err;
2999}
3000
Andre Guedes0e05bba2013-04-30 15:29:33 -03003001static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3002{
3003 BT_DBG("status %d", status);
3004
3005 hci_dev_lock(hdev);
3006
3007 if (status) {
3008 mgmt_stop_discovery_failed(hdev, status);
3009 goto unlock;
3010 }
3011
3012 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3013
3014unlock:
3015 hci_dev_unlock(hdev);
3016}
3017
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003018static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003019 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003020{
Johan Hedbergd9306502012-02-20 23:25:18 +02003021 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003022 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003023 struct hci_cp_remote_name_req_cancel cp;
3024 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003025 struct hci_request req;
3026 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003027 int err;
3028
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003029 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003030
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003031 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003032
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003033 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003034 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003035 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3036 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003037 goto unlock;
3038 }
3039
3040 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003041 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003042 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3043 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003044 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003045 }
3046
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003047 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003048 if (!cmd) {
3049 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003050 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003051 }
3052
Andre Guedes0e05bba2013-04-30 15:29:33 -03003053 hci_req_init(&req, hdev);
3054
Andre Guedese0d9727e2012-03-20 15:15:36 -03003055 switch (hdev->discovery.state) {
3056 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003057 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3058 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3059 } else {
3060 cancel_delayed_work(&hdev->le_scan_disable);
3061
3062 memset(&enable_cp, 0, sizeof(enable_cp));
3063 enable_cp.enable = LE_SCAN_DISABLE;
3064 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3065 sizeof(enable_cp), &enable_cp);
3066 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003067
Andre Guedese0d9727e2012-03-20 15:15:36 -03003068 break;
3069
3070 case DISCOVERY_RESOLVING:
3071 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003072 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003073 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003074 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003075 err = cmd_complete(sk, hdev->id,
3076 MGMT_OP_STOP_DISCOVERY, 0,
3077 &mgmt_cp->type,
3078 sizeof(mgmt_cp->type));
3079 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3080 goto unlock;
3081 }
3082
3083 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003084 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3085 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003086
3087 break;
3088
3089 default:
3090 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003091
3092 mgmt_pending_remove(cmd);
3093 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3094 MGMT_STATUS_FAILED, &mgmt_cp->type,
3095 sizeof(mgmt_cp->type));
3096 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003097 }
3098
Andre Guedes0e05bba2013-04-30 15:29:33 -03003099 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003100 if (err < 0)
3101 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003102 else
3103 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003104
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003105unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003106 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003107 return err;
3108}
3109
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003110static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003111 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003112{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003113 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003114 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003115 int err;
3116
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003117 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003118
Johan Hedberg561aafb2012-01-04 13:31:59 +02003119 hci_dev_lock(hdev);
3120
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003121 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003122 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003123 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003124 goto failed;
3125 }
3126
Johan Hedberga198e7b2012-02-17 14:27:06 +02003127 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003128 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003129 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003130 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003131 goto failed;
3132 }
3133
3134 if (cp->name_known) {
3135 e->name_state = NAME_KNOWN;
3136 list_del(&e->list);
3137 } else {
3138 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003139 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003140 }
3141
Johan Hedberge3846622013-01-09 15:29:33 +02003142 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3143 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003144
3145failed:
3146 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003147 return err;
3148}
3149
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003150static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003151 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003152{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003153 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003154 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003155 int err;
3156
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003157 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003158
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003159 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003160 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3161 MGMT_STATUS_INVALID_PARAMS,
3162 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003163
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003164 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003165
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003166 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003167 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003168 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003169 else
Szymon Janca6785be2012-12-13 15:11:21 +01003170 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003172 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003173 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003174
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003175 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003176
3177 return err;
3178}
3179
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003180static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003181 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003182{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003183 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003184 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003185 int err;
3186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003187 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003188
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003189 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003190 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3191 MGMT_STATUS_INVALID_PARAMS,
3192 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003193
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003194 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003195
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003196 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003197 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003198 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003199 else
Szymon Janca6785be2012-12-13 15:11:21 +01003200 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003201
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003202 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003203 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003204
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003205 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003206
3207 return err;
3208}
3209
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003210static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3211 u16 len)
3212{
3213 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003214 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003215 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003216 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003217
3218 BT_DBG("%s", hdev->name);
3219
Szymon Jancc72d4b82012-03-16 16:02:57 +01003220 source = __le16_to_cpu(cp->source);
3221
3222 if (source > 0x0002)
3223 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3224 MGMT_STATUS_INVALID_PARAMS);
3225
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003226 hci_dev_lock(hdev);
3227
Szymon Jancc72d4b82012-03-16 16:02:57 +01003228 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003229 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3230 hdev->devid_product = __le16_to_cpu(cp->product);
3231 hdev->devid_version = __le16_to_cpu(cp->version);
3232
3233 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3234
Johan Hedberg890ea892013-03-15 17:06:52 -05003235 hci_req_init(&req, hdev);
3236 update_eir(&req);
3237 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003238
3239 hci_dev_unlock(hdev);
3240
3241 return err;
3242}
3243
Johan Hedberg4375f102013-09-25 13:26:10 +03003244static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3245{
3246 struct cmd_lookup match = { NULL, hdev };
3247
3248 if (status) {
3249 u8 mgmt_err = mgmt_status(status);
3250
3251 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3252 cmd_status_rsp, &mgmt_err);
3253 return;
3254 }
3255
3256 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3257 &match);
3258
3259 new_settings(hdev, match.sk);
3260
3261 if (match.sk)
3262 sock_put(match.sk);
3263}
3264
Marcel Holtmann21b51872013-10-10 09:47:53 -07003265static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3266 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003267{
3268 struct mgmt_mode *cp = data;
3269 struct pending_cmd *cmd;
3270 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003271 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003272 int err;
3273
3274 BT_DBG("request for %s", hdev->name);
3275
Johan Hedberge6fe7982013-10-02 15:45:22 +03003276 status = mgmt_le_support(hdev);
3277 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003278 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003279 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003280
3281 if (cp->val != 0x00 && cp->val != 0x01)
3282 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3283 MGMT_STATUS_INVALID_PARAMS);
3284
3285 hci_dev_lock(hdev);
3286
3287 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003288 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003289
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003290 /* The following conditions are ones which mean that we should
3291 * not do any HCI communication but directly send a mgmt
3292 * response to user space (after toggling the flag if
3293 * necessary).
3294 */
3295 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003296 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003297 bool changed = false;
3298
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003299 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3300 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003301 changed = true;
3302 }
3303
3304 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3305 if (err < 0)
3306 goto unlock;
3307
3308 if (changed)
3309 err = new_settings(hdev, sk);
3310
3311 goto unlock;
3312 }
3313
3314 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3315 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3316 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3317 MGMT_STATUS_BUSY);
3318 goto unlock;
3319 }
3320
3321 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3322 if (!cmd) {
3323 err = -ENOMEM;
3324 goto unlock;
3325 }
3326
3327 hci_req_init(&req, hdev);
3328
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003329 if (val)
3330 enable_advertising(&req);
3331 else
3332 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003333
3334 err = hci_req_run(&req, set_advertising_complete);
3335 if (err < 0)
3336 mgmt_pending_remove(cmd);
3337
3338unlock:
3339 hci_dev_unlock(hdev);
3340 return err;
3341}
3342
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003343static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3344 void *data, u16 len)
3345{
3346 struct mgmt_cp_set_static_address *cp = data;
3347 int err;
3348
3349 BT_DBG("%s", hdev->name);
3350
Marcel Holtmann62af4442013-10-02 22:10:32 -07003351 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003352 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003353 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003354
3355 if (hdev_is_powered(hdev))
3356 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3357 MGMT_STATUS_REJECTED);
3358
3359 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3360 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3361 return cmd_status(sk, hdev->id,
3362 MGMT_OP_SET_STATIC_ADDRESS,
3363 MGMT_STATUS_INVALID_PARAMS);
3364
3365 /* Two most significant bits shall be set */
3366 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3367 return cmd_status(sk, hdev->id,
3368 MGMT_OP_SET_STATIC_ADDRESS,
3369 MGMT_STATUS_INVALID_PARAMS);
3370 }
3371
3372 hci_dev_lock(hdev);
3373
3374 bacpy(&hdev->static_addr, &cp->bdaddr);
3375
3376 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3377
3378 hci_dev_unlock(hdev);
3379
3380 return err;
3381}
3382
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003383static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3384 void *data, u16 len)
3385{
3386 struct mgmt_cp_set_scan_params *cp = data;
3387 __u16 interval, window;
3388 int err;
3389
3390 BT_DBG("%s", hdev->name);
3391
3392 if (!lmp_le_capable(hdev))
3393 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3394 MGMT_STATUS_NOT_SUPPORTED);
3395
3396 interval = __le16_to_cpu(cp->interval);
3397
3398 if (interval < 0x0004 || interval > 0x4000)
3399 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3400 MGMT_STATUS_INVALID_PARAMS);
3401
3402 window = __le16_to_cpu(cp->window);
3403
3404 if (window < 0x0004 || window > 0x4000)
3405 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3406 MGMT_STATUS_INVALID_PARAMS);
3407
3408 hci_dev_lock(hdev);
3409
3410 hdev->le_scan_interval = interval;
3411 hdev->le_scan_window = window;
3412
3413 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3414
3415 hci_dev_unlock(hdev);
3416
3417 return err;
3418}
3419
Johan Hedberg33e38b32013-03-15 17:07:05 -05003420static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3421{
3422 struct pending_cmd *cmd;
3423
3424 BT_DBG("status 0x%02x", status);
3425
3426 hci_dev_lock(hdev);
3427
3428 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3429 if (!cmd)
3430 goto unlock;
3431
3432 if (status) {
3433 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3434 mgmt_status(status));
3435 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003436 struct mgmt_mode *cp = cmd->param;
3437
3438 if (cp->val)
3439 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3440 else
3441 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3442
Johan Hedberg33e38b32013-03-15 17:07:05 -05003443 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3444 new_settings(hdev, cmd->sk);
3445 }
3446
3447 mgmt_pending_remove(cmd);
3448
3449unlock:
3450 hci_dev_unlock(hdev);
3451}
3452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003453static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003454 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003455{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003456 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003457 struct pending_cmd *cmd;
3458 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003459 int err;
3460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003461 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003462
Johan Hedberg56f87902013-10-02 13:43:13 +03003463 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3464 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003465 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3466 MGMT_STATUS_NOT_SUPPORTED);
3467
Johan Hedberga7e80f22013-01-09 16:05:19 +02003468 if (cp->val != 0x00 && cp->val != 0x01)
3469 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3470 MGMT_STATUS_INVALID_PARAMS);
3471
Johan Hedberg5400c042012-02-21 16:40:33 +02003472 if (!hdev_is_powered(hdev))
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_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003475
3476 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003477 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003478 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003479
3480 hci_dev_lock(hdev);
3481
Johan Hedberg05cbf292013-03-15 17:07:07 -05003482 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3483 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3484 MGMT_STATUS_BUSY);
3485 goto unlock;
3486 }
3487
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003488 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3489 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3490 hdev);
3491 goto unlock;
3492 }
3493
Johan Hedberg33e38b32013-03-15 17:07:05 -05003494 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3495 data, len);
3496 if (!cmd) {
3497 err = -ENOMEM;
3498 goto unlock;
3499 }
3500
3501 hci_req_init(&req, hdev);
3502
Johan Hedberg406d7802013-03-15 17:07:09 -05003503 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003504
3505 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003506 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003507 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003508 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003509 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003510 }
3511
Johan Hedberg33e38b32013-03-15 17:07:05 -05003512unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003513 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003514
Antti Julkuf6422ec2011-06-22 13:11:56 +03003515 return err;
3516}
3517
Johan Hedberg0663ca22013-10-02 13:43:14 +03003518static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3519{
3520 struct pending_cmd *cmd;
3521
3522 BT_DBG("status 0x%02x", status);
3523
3524 hci_dev_lock(hdev);
3525
3526 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3527 if (!cmd)
3528 goto unlock;
3529
3530 if (status) {
3531 u8 mgmt_err = mgmt_status(status);
3532
3533 /* We need to restore the flag if related HCI commands
3534 * failed.
3535 */
3536 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3537
3538 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3539 } else {
3540 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3541 new_settings(hdev, cmd->sk);
3542 }
3543
3544 mgmt_pending_remove(cmd);
3545
3546unlock:
3547 hci_dev_unlock(hdev);
3548}
3549
3550static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3551{
3552 struct mgmt_mode *cp = data;
3553 struct pending_cmd *cmd;
3554 struct hci_request req;
3555 int err;
3556
3557 BT_DBG("request for %s", hdev->name);
3558
3559 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3560 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3561 MGMT_STATUS_NOT_SUPPORTED);
3562
3563 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3564 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3565 MGMT_STATUS_REJECTED);
3566
3567 if (cp->val != 0x00 && cp->val != 0x01)
3568 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3569 MGMT_STATUS_INVALID_PARAMS);
3570
3571 hci_dev_lock(hdev);
3572
3573 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3574 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3575 goto unlock;
3576 }
3577
3578 if (!hdev_is_powered(hdev)) {
3579 if (!cp->val) {
3580 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3581 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3582 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3583 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3584 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3585 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3586 }
3587
3588 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3589
3590 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3591 if (err < 0)
3592 goto unlock;
3593
3594 err = new_settings(hdev, sk);
3595 goto unlock;
3596 }
3597
3598 /* Reject disabling when powered on */
3599 if (!cp->val) {
3600 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3601 MGMT_STATUS_REJECTED);
3602 goto unlock;
3603 }
3604
3605 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3606 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3607 MGMT_STATUS_BUSY);
3608 goto unlock;
3609 }
3610
3611 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3612 if (!cmd) {
3613 err = -ENOMEM;
3614 goto unlock;
3615 }
3616
3617 /* We need to flip the bit already here so that hci_update_ad
3618 * generates the correct flags.
3619 */
3620 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3621
3622 hci_req_init(&req, hdev);
3623 hci_update_ad(&req);
3624 err = hci_req_run(&req, set_bredr_complete);
3625 if (err < 0)
3626 mgmt_pending_remove(cmd);
3627
3628unlock:
3629 hci_dev_unlock(hdev);
3630 return err;
3631}
3632
Johan Hedberg3f706b72013-01-20 14:27:16 +02003633static bool ltk_is_valid(struct mgmt_ltk_info *key)
3634{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003635 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3636 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003637 if (key->master != 0x00 && key->master != 0x01)
3638 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003639 if (!bdaddr_type_is_le(key->addr.type))
3640 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003641 return true;
3642}
3643
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003644static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003645 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003646{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003647 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3648 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003649 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003650
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003651 BT_DBG("request for %s", hdev->name);
3652
3653 if (!lmp_le_capable(hdev))
3654 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3655 MGMT_STATUS_NOT_SUPPORTED);
3656
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003657 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003658
3659 expected_len = sizeof(*cp) + key_count *
3660 sizeof(struct mgmt_ltk_info);
3661 if (expected_len != len) {
3662 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003663 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003664 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003665 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003666 }
3667
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003668 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003669
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003670 for (i = 0; i < key_count; i++) {
3671 struct mgmt_ltk_info *key = &cp->keys[i];
3672
Johan Hedberg3f706b72013-01-20 14:27:16 +02003673 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003674 return cmd_status(sk, hdev->id,
3675 MGMT_OP_LOAD_LONG_TERM_KEYS,
3676 MGMT_STATUS_INVALID_PARAMS);
3677 }
3678
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003679 hci_dev_lock(hdev);
3680
3681 hci_smp_ltks_clear(hdev);
3682
3683 for (i = 0; i < key_count; i++) {
3684 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003685 u8 type, addr_type;
3686
3687 if (key->addr.type == BDADDR_LE_PUBLIC)
3688 addr_type = ADDR_LE_DEV_PUBLIC;
3689 else
3690 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003691
3692 if (key->master)
3693 type = HCI_SMP_LTK;
3694 else
3695 type = HCI_SMP_LTK_SLAVE;
3696
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003697 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003698 type, 0, key->authenticated, key->val,
3699 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003700 }
3701
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003702 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3703 NULL, 0);
3704
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003705 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003706
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003707 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003708}
3709
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003710static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003711 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3712 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003713 bool var_len;
3714 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003715} mgmt_handlers[] = {
3716 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003717 { read_version, false, MGMT_READ_VERSION_SIZE },
3718 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3719 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3720 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3721 { set_powered, false, MGMT_SETTING_SIZE },
3722 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3723 { set_connectable, false, MGMT_SETTING_SIZE },
3724 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3725 { set_pairable, false, MGMT_SETTING_SIZE },
3726 { set_link_security, false, MGMT_SETTING_SIZE },
3727 { set_ssp, false, MGMT_SETTING_SIZE },
3728 { set_hs, false, MGMT_SETTING_SIZE },
3729 { set_le, false, MGMT_SETTING_SIZE },
3730 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3731 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3732 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3733 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3734 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3735 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3736 { disconnect, false, MGMT_DISCONNECT_SIZE },
3737 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3738 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3739 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3740 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3741 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3742 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3743 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3744 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3745 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3746 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3747 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3748 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3749 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3750 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3751 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3752 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3753 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3754 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3755 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003756 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003757 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003758 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003759 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003760 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003761};
3762
3763
Johan Hedberg03811012010-12-08 00:21:06 +02003764int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3765{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003766 void *buf;
3767 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003768 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003769 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003770 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003771 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003772 int err;
3773
3774 BT_DBG("got %zu bytes", msglen);
3775
3776 if (msglen < sizeof(*hdr))
3777 return -EINVAL;
3778
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003779 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003780 if (!buf)
3781 return -ENOMEM;
3782
3783 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3784 err = -EFAULT;
3785 goto done;
3786 }
3787
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003788 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003789 opcode = __le16_to_cpu(hdr->opcode);
3790 index = __le16_to_cpu(hdr->index);
3791 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003792
3793 if (len != msglen - sizeof(*hdr)) {
3794 err = -EINVAL;
3795 goto done;
3796 }
3797
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003798 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003799 hdev = hci_dev_get(index);
3800 if (!hdev) {
3801 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003802 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003803 goto done;
3804 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003805
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02003806 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
3807 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003808 err = cmd_status(sk, index, opcode,
3809 MGMT_STATUS_INVALID_INDEX);
3810 goto done;
3811 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003812 }
3813
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003814 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003815 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003816 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003817 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003818 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003819 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003820 }
3821
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003822 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003823 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003824 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003825 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003826 goto done;
3827 }
3828
Johan Hedbergbe22b542012-03-01 22:24:41 +02003829 handler = &mgmt_handlers[opcode];
3830
3831 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003832 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003833 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003834 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003835 goto done;
3836 }
3837
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003838 if (hdev)
3839 mgmt_init_hdev(sk, hdev);
3840
3841 cp = buf + sizeof(*hdr);
3842
Johan Hedbergbe22b542012-03-01 22:24:41 +02003843 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003844 if (err < 0)
3845 goto done;
3846
Johan Hedberg03811012010-12-08 00:21:06 +02003847 err = msglen;
3848
3849done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003850 if (hdev)
3851 hci_dev_put(hdev);
3852
Johan Hedberg03811012010-12-08 00:21:06 +02003853 kfree(buf);
3854 return err;
3855}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003856
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003857void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003858{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003859 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003860 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003861
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003862 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003863}
3864
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003865void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003866{
Johan Hedberg5f159032012-03-02 03:13:19 +02003867 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003868
Marcel Holtmann1514b892013-10-06 08:25:01 -07003869 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003870 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003871
Johan Hedberg744cf192011-11-08 20:40:14 +02003872 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003873
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003874 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003875}
3876
Johan Hedberg890ea892013-03-15 17:06:52 -05003877static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003878{
Johan Hedberg890ea892013-03-15 17:06:52 -05003879 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003880 u8 scan = 0;
3881
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003882 /* Ensure that fast connectable is disabled. This function will
3883 * not do anything if the page scan parameters are already what
3884 * they should be.
3885 */
3886 write_fast_connectable(req, false);
3887
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003888 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3889 scan |= SCAN_PAGE;
3890 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3891 scan |= SCAN_INQUIRY;
3892
Johan Hedberg890ea892013-03-15 17:06:52 -05003893 if (scan)
3894 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003895}
3896
Johan Hedberg229ab392013-03-15 17:06:53 -05003897static void powered_complete(struct hci_dev *hdev, u8 status)
3898{
3899 struct cmd_lookup match = { NULL, hdev };
3900
3901 BT_DBG("status 0x%02x", status);
3902
3903 hci_dev_lock(hdev);
3904
3905 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3906
3907 new_settings(hdev, match.sk);
3908
3909 hci_dev_unlock(hdev);
3910
3911 if (match.sk)
3912 sock_put(match.sk);
3913}
3914
Johan Hedberg70da6242013-03-15 17:06:51 -05003915static int powered_update_hci(struct hci_dev *hdev)
3916{
Johan Hedberg890ea892013-03-15 17:06:52 -05003917 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003918 u8 link_sec;
3919
Johan Hedberg890ea892013-03-15 17:06:52 -05003920 hci_req_init(&req, hdev);
3921
Johan Hedberg70da6242013-03-15 17:06:51 -05003922 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3923 !lmp_host_ssp_capable(hdev)) {
3924 u8 ssp = 1;
3925
Johan Hedberg890ea892013-03-15 17:06:52 -05003926 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003927 }
3928
Johan Hedbergc73eee92013-04-19 18:35:21 +03003929 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3930 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003931 struct hci_cp_write_le_host_supported cp;
3932
3933 cp.le = 1;
3934 cp.simul = lmp_le_br_capable(hdev);
3935
3936 /* Check first if we already have the right
3937 * host state (host features set)
3938 */
3939 if (cp.le != lmp_host_le_capable(hdev) ||
3940 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003941 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3942 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003943
3944 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3945 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003946 }
3947
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003948 if (lmp_le_capable(hdev)) {
3949 /* Set random address to static address if configured */
3950 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3951 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3952 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003953
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003954 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3955 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003956 }
3957
Johan Hedberg70da6242013-03-15 17:06:51 -05003958 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3959 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003960 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3961 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003962
3963 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003964 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3965 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003966 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003967 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003968 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003969 }
3970
Johan Hedberg229ab392013-03-15 17:06:53 -05003971 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003972}
3973
Johan Hedberg744cf192011-11-08 20:40:14 +02003974int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003975{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003976 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003977 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3978 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003979 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003980
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003981 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3982 return 0;
3983
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003984 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003985 if (powered_update_hci(hdev) == 0)
3986 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003987
Johan Hedberg229ab392013-03-15 17:06:53 -05003988 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3989 &match);
3990 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003991 }
3992
Johan Hedberg229ab392013-03-15 17:06:53 -05003993 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3994 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3995
3996 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3997 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3998 zero_cod, sizeof(zero_cod), NULL);
3999
4000new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004001 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004002
4003 if (match.sk)
4004 sock_put(match.sk);
4005
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004006 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004007}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004008
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004009void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004010{
4011 struct pending_cmd *cmd;
4012 u8 status;
4013
4014 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4015 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004016 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004017
4018 if (err == -ERFKILL)
4019 status = MGMT_STATUS_RFKILLED;
4020 else
4021 status = MGMT_STATUS_FAILED;
4022
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004023 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004024
4025 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004026}
4027
Johan Hedberg744cf192011-11-08 20:40:14 +02004028int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004029{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004030 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004031 bool changed = false;
4032 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004033
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004034 if (discoverable) {
4035 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4036 changed = true;
4037 } else {
4038 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4039 changed = true;
4040 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004041
Johan Hedberged9b5f22012-02-21 20:47:06 +02004042 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004043 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004044
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004045 if (changed)
4046 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004047
Johan Hedberg73f22f62010-12-29 16:00:25 +02004048 if (match.sk)
4049 sock_put(match.sk);
4050
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004051 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004052}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004053
Johan Hedberg744cf192011-11-08 20:40:14 +02004054int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004055{
Johan Hedberg2b76f452013-03-15 17:07:04 -05004056 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004057 bool changed = false;
4058 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004059
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004060 if (connectable) {
4061 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4062 changed = true;
4063 } else {
4064 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4065 changed = true;
4066 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004067
Johan Hedberg2b76f452013-03-15 17:07:04 -05004068 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004069
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004070 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05004071 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004072
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004073 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004074}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004075
Johan Hedberg744cf192011-11-08 20:40:14 +02004076int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004077{
Johan Hedbergca69b792011-11-11 18:10:00 +02004078 u8 mgmt_err = mgmt_status(status);
4079
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004080 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004081 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004082 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004083
4084 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004085 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004086 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004087
4088 return 0;
4089}
4090
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004091int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4092 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004093{
Johan Hedberg86742e12011-11-07 23:13:38 +02004094 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004095
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004096 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004097
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004098 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004099 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004100 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004101 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004102 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004103 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004104
Johan Hedberg744cf192011-11-08 20:40:14 +02004105 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004106}
Johan Hedbergf7520542011-01-20 12:34:39 +02004107
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004108int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4109{
4110 struct mgmt_ev_new_long_term_key ev;
4111
4112 memset(&ev, 0, sizeof(ev));
4113
4114 ev.store_hint = persistent;
4115 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004116 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004117 ev.key.authenticated = key->authenticated;
4118 ev.key.enc_size = key->enc_size;
4119 ev.key.ediv = key->ediv;
4120
4121 if (key->type == HCI_SMP_LTK)
4122 ev.key.master = 1;
4123
4124 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4125 memcpy(ev.key.val, key->val, sizeof(key->val));
4126
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004127 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4128 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004129}
4130
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004131void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4132 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4133 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004134{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004135 char buf[512];
4136 struct mgmt_ev_device_connected *ev = (void *) buf;
4137 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004138
Johan Hedbergb644ba32012-01-17 21:48:47 +02004139 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004140 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004141
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004142 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004143
Johan Hedbergb644ba32012-01-17 21:48:47 +02004144 if (name_len > 0)
4145 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004146 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004147
4148 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004149 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004150 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004151
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004152 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004153
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004154 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4155 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004156}
4157
Johan Hedberg8962ee72011-01-20 12:40:27 +02004158static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4159{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004160 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004161 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004162 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004163
Johan Hedberg88c3df12012-02-09 14:27:38 +02004164 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4165 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004166
Johan Hedbergaee9b212012-02-18 15:07:59 +02004167 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004168 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004169
4170 *sk = cmd->sk;
4171 sock_hold(*sk);
4172
Johan Hedberga664b5b2011-02-19 12:06:02 -03004173 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004174}
4175
Johan Hedberg124f6e32012-02-09 13:50:12 +02004176static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004177{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004178 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004179 struct mgmt_cp_unpair_device *cp = cmd->param;
4180 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004181
4182 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004183 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4184 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004185
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004186 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4187
Johan Hedbergaee9b212012-02-18 15:07:59 +02004188 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004189
4190 mgmt_pending_remove(cmd);
4191}
4192
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004193void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4194 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004195{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004196 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004197 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004198
Johan Hedberg744cf192011-11-08 20:40:14 +02004199 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004200
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004201 bacpy(&ev.addr.bdaddr, bdaddr);
4202 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4203 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004204
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004205 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004206
4207 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004208 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004209
Johan Hedberg124f6e32012-02-09 13:50:12 +02004210 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004211 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004212}
4213
Marcel Holtmann78929242013-10-06 23:55:47 -07004214void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4215 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004216{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004217 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004218 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004219
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004220 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4221 hdev);
4222
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004223 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004224 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004225 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004226
Johan Hedberg88c3df12012-02-09 14:27:38 +02004227 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004228 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004229
Marcel Holtmann78929242013-10-06 23:55:47 -07004230 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4231 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004232
Johan Hedberga664b5b2011-02-19 12:06:02 -03004233 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004234}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004235
Marcel Holtmann445608d2013-10-06 23:55:48 -07004236void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4237 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004238{
4239 struct mgmt_ev_connect_failed ev;
4240
Johan Hedberg4c659c32011-11-07 23:13:39 +02004241 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004242 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004243 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004244
Marcel Holtmann445608d2013-10-06 23:55:48 -07004245 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004246}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004247
Johan Hedberg744cf192011-11-08 20:40:14 +02004248int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004249{
4250 struct mgmt_ev_pin_code_request ev;
4251
Johan Hedbergd8457692012-02-17 14:24:57 +02004252 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004253 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004254 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004255
Johan Hedberg744cf192011-11-08 20:40:14 +02004256 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004257 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004258}
4259
Johan Hedberg744cf192011-11-08 20:40:14 +02004260int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004261 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004262{
4263 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004264 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004265 int err;
4266
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004267 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004268 if (!cmd)
4269 return -ENOENT;
4270
Johan Hedbergd8457692012-02-17 14:24:57 +02004271 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004272 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004273
Johan Hedbergaee9b212012-02-18 15:07:59 +02004274 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004275 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004276
Johan Hedberga664b5b2011-02-19 12:06:02 -03004277 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004278
4279 return err;
4280}
4281
Johan Hedberg744cf192011-11-08 20:40:14 +02004282int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004283 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004284{
4285 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004286 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004287 int err;
4288
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004289 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004290 if (!cmd)
4291 return -ENOENT;
4292
Johan Hedbergd8457692012-02-17 14:24:57 +02004293 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004294 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004295
Johan Hedbergaee9b212012-02-18 15:07:59 +02004296 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004297 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004298
Johan Hedberga664b5b2011-02-19 12:06:02 -03004299 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004300
4301 return err;
4302}
Johan Hedberga5c29682011-02-19 12:05:57 -03004303
Johan Hedberg744cf192011-11-08 20:40:14 +02004304int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004305 u8 link_type, u8 addr_type, __le32 value,
4306 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004307{
4308 struct mgmt_ev_user_confirm_request ev;
4309
Johan Hedberg744cf192011-11-08 20:40:14 +02004310 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004311
Johan Hedberg272d90d2012-02-09 15:26:12 +02004312 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004313 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004314 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004315 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004316
Johan Hedberg744cf192011-11-08 20:40:14 +02004317 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004318 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004319}
4320
Johan Hedberg272d90d2012-02-09 15:26:12 +02004321int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004322 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004323{
4324 struct mgmt_ev_user_passkey_request ev;
4325
4326 BT_DBG("%s", hdev->name);
4327
Johan Hedberg272d90d2012-02-09 15:26:12 +02004328 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004329 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004330
4331 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004332 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004333}
4334
Brian Gix0df4c182011-11-16 13:53:13 -08004335static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004336 u8 link_type, u8 addr_type, u8 status,
4337 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004338{
4339 struct pending_cmd *cmd;
4340 struct mgmt_rp_user_confirm_reply rp;
4341 int err;
4342
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004343 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004344 if (!cmd)
4345 return -ENOENT;
4346
Johan Hedberg272d90d2012-02-09 15:26:12 +02004347 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004348 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004349 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004350 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004351
Johan Hedberga664b5b2011-02-19 12:06:02 -03004352 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004353
4354 return err;
4355}
4356
Johan Hedberg744cf192011-11-08 20:40:14 +02004357int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004358 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004359{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004360 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004361 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004362}
4363
Johan Hedberg272d90d2012-02-09 15:26:12 +02004364int mgmt_user_confirm_neg_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)
Johan Hedberga5c29682011-02-19 12:05:57 -03004366{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004367 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004368 status,
4369 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004370}
Johan Hedberg2a611692011-02-19 12:06:00 -03004371
Brian Gix604086b2011-11-23 08:28:33 -08004372int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004373 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004374{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004375 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004376 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004377}
4378
Johan Hedberg272d90d2012-02-09 15:26:12 +02004379int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004380 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004381{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004382 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004383 status,
4384 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004385}
4386
Johan Hedberg92a25252012-09-06 18:39:26 +03004387int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4388 u8 link_type, u8 addr_type, u32 passkey,
4389 u8 entered)
4390{
4391 struct mgmt_ev_passkey_notify ev;
4392
4393 BT_DBG("%s", hdev->name);
4394
4395 bacpy(&ev.addr.bdaddr, bdaddr);
4396 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4397 ev.passkey = __cpu_to_le32(passkey);
4398 ev.entered = entered;
4399
4400 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4401}
4402
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004403int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004404 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004405{
4406 struct mgmt_ev_auth_failed ev;
4407
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004408 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004409 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004410 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004411
Johan Hedberg744cf192011-11-08 20:40:14 +02004412 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004413}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004414
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004415int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4416{
4417 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004418 bool changed = false;
4419 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004420
4421 if (status) {
4422 u8 mgmt_err = mgmt_status(status);
4423 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004424 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004425 return 0;
4426 }
4427
Johan Hedberg47990ea2012-02-22 11:58:37 +02004428 if (test_bit(HCI_AUTH, &hdev->flags)) {
4429 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4430 changed = true;
4431 } else {
4432 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4433 changed = true;
4434 }
4435
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004436 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004437 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004438
Johan Hedberg47990ea2012-02-22 11:58:37 +02004439 if (changed)
4440 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004441
4442 if (match.sk)
4443 sock_put(match.sk);
4444
4445 return err;
4446}
4447
Johan Hedberg890ea892013-03-15 17:06:52 -05004448static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004449{
Johan Hedberg890ea892013-03-15 17:06:52 -05004450 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004451 struct hci_cp_write_eir cp;
4452
Johan Hedberg976eb202012-10-24 21:12:01 +03004453 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004454 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004455
Johan Hedbergc80da272012-02-22 15:38:48 +02004456 memset(hdev->eir, 0, sizeof(hdev->eir));
4457
Johan Hedbergcacaf522012-02-21 00:52:42 +02004458 memset(&cp, 0, sizeof(cp));
4459
Johan Hedberg890ea892013-03-15 17:06:52 -05004460 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004461}
4462
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004463int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004464{
4465 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004466 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004467 bool changed = false;
4468 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004469
4470 if (status) {
4471 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004472
4473 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004474 &hdev->dev_flags)) {
4475 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004476 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004477 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004478
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004479 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4480 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004481
4482 return err;
4483 }
4484
4485 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004486 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004487 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004488 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4489 if (!changed)
4490 changed = test_and_clear_bit(HCI_HS_ENABLED,
4491 &hdev->dev_flags);
4492 else
4493 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004494 }
4495
4496 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4497
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004498 if (changed)
4499 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004500
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004501 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004502 sock_put(match.sk);
4503
Johan Hedberg890ea892013-03-15 17:06:52 -05004504 hci_req_init(&req, hdev);
4505
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004506 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004507 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004508 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004509 clear_eir(&req);
4510
4511 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004512
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004513 return err;
4514}
4515
Johan Hedberg92da6092013-03-15 17:06:55 -05004516static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004517{
4518 struct cmd_lookup *match = data;
4519
Johan Hedberg90e70452012-02-23 23:09:40 +02004520 if (match->sk == NULL) {
4521 match->sk = cmd->sk;
4522 sock_hold(match->sk);
4523 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004524}
4525
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004526int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004527 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004528{
Johan Hedberg90e70452012-02-23 23:09:40 +02004529 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4530 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004531
Johan Hedberg92da6092013-03-15 17:06:55 -05004532 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4533 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4534 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004535
4536 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004537 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4538 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004539
4540 if (match.sk)
4541 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004542
4543 return err;
4544}
4545
Johan Hedberg744cf192011-11-08 20:40:14 +02004546int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004547{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004548 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004549 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004550
Johan Hedberg13928972013-03-15 17:07:00 -05004551 if (status)
4552 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004553
4554 memset(&ev, 0, sizeof(ev));
4555 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004556 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004557
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004558 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004559 if (!cmd) {
4560 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004561
Johan Hedberg13928972013-03-15 17:07:00 -05004562 /* If this is a HCI command related to powering on the
4563 * HCI dev don't send any mgmt signals.
4564 */
4565 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4566 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004567 }
4568
Johan Hedberg13928972013-03-15 17:07:00 -05004569 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4570 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004571}
Szymon Jancc35938b2011-03-22 13:12:21 +01004572
Johan Hedberg744cf192011-11-08 20:40:14 +02004573int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004574 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004575{
4576 struct pending_cmd *cmd;
4577 int err;
4578
Johan Hedberg744cf192011-11-08 20:40:14 +02004579 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004580
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004581 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004582 if (!cmd)
4583 return -ENOENT;
4584
4585 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004586 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4587 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004588 } else {
4589 struct mgmt_rp_read_local_oob_data rp;
4590
4591 memcpy(rp.hash, hash, sizeof(rp.hash));
4592 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4593
Johan Hedberg744cf192011-11-08 20:40:14 +02004594 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004595 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4596 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004597 }
4598
4599 mgmt_pending_remove(cmd);
4600
4601 return err;
4602}
Johan Hedberge17acd42011-03-30 23:57:16 +03004603
Marcel Holtmann901801b2013-10-06 23:55:51 -07004604void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4605 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4606 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004607{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004608 char buf[512];
4609 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004610 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004611
Andre Guedes12602d02013-04-30 15:29:40 -03004612 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004613 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004614
Johan Hedberg1dc06092012-01-15 21:01:23 +02004615 /* Leave 5 bytes for a potential CoD field */
4616 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004617 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004618
Johan Hedberg1dc06092012-01-15 21:01:23 +02004619 memset(buf, 0, sizeof(buf));
4620
Johan Hedberge319d2e2012-01-15 19:51:59 +02004621 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004622 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004623 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004624 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304625 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004626 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304627 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004628
Johan Hedberg1dc06092012-01-15 21:01:23 +02004629 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004630 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004631
Johan Hedberg1dc06092012-01-15 21:01:23 +02004632 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4633 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004634 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004635
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004636 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004637 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004638
Marcel Holtmann901801b2013-10-06 23:55:51 -07004639 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004640}
Johan Hedberga88a9652011-03-30 13:18:12 +03004641
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004642void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4643 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004644{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004645 struct mgmt_ev_device_found *ev;
4646 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4647 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004648
Johan Hedbergb644ba32012-01-17 21:48:47 +02004649 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004650
Johan Hedbergb644ba32012-01-17 21:48:47 +02004651 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004652
Johan Hedbergb644ba32012-01-17 21:48:47 +02004653 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004654 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004655 ev->rssi = rssi;
4656
4657 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004658 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004659
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004660 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004661
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004662 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004663}
Johan Hedberg314b2382011-04-27 10:29:57 -04004664
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004665void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004666{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004667 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004668 struct pending_cmd *cmd;
4669
Andre Guedes343fb142011-11-22 17:14:19 -03004670 BT_DBG("%s discovering %u", hdev->name, discovering);
4671
Johan Hedberg164a6e72011-11-01 17:06:44 +02004672 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004673 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004674 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004675 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004676
4677 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004678 u8 type = hdev->discovery.type;
4679
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004680 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4681 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004682 mgmt_pending_remove(cmd);
4683 }
4684
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004685 memset(&ev, 0, sizeof(ev));
4686 ev.type = hdev->discovery.type;
4687 ev.discovering = discovering;
4688
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004689 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004690}
Antti Julku5e762442011-08-25 16:48:02 +03004691
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004692int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004693{
4694 struct pending_cmd *cmd;
4695 struct mgmt_ev_device_blocked ev;
4696
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004697 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004698
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004699 bacpy(&ev.addr.bdaddr, bdaddr);
4700 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004701
Johan Hedberg744cf192011-11-08 20:40:14 +02004702 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004703 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004704}
4705
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004706int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004707{
4708 struct pending_cmd *cmd;
4709 struct mgmt_ev_device_unblocked ev;
4710
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004711 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004712
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004713 bacpy(&ev.addr.bdaddr, bdaddr);
4714 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004715
Johan Hedberg744cf192011-11-08 20:40:14 +02004716 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004717 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004718}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004719
4720static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4721{
4722 BT_DBG("%s status %u", hdev->name, status);
4723
4724 /* Clear the advertising mgmt setting if we failed to re-enable it */
4725 if (status) {
4726 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004727 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004728 }
4729}
4730
4731void mgmt_reenable_advertising(struct hci_dev *hdev)
4732{
4733 struct hci_request req;
4734
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004735 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004736 return;
4737
4738 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4739 return;
4740
4741 hci_req_init(&req, hdev);
4742 enable_advertising(&req);
4743
4744 /* If this fails we have no option but to let user space know
4745 * that we've disabled advertising.
4746 */
4747 if (hci_req_run(&req, adv_enable_complete) < 0) {
4748 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004749 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004750 }
4751}