blob: a5c015cadd552a338ada19bc59b3007ce8def012 [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 Hedberg84bde9d2012-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 Hedberg84bde9d2012-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;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001078 struct mgmt_mode *cp;
1079 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001080
1081 BT_DBG("status 0x%02x", status);
1082
1083 hci_dev_lock(hdev);
1084
1085 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1086 if (!cmd)
1087 goto unlock;
1088
Johan Hedberg37438c12013-10-14 16:20:05 +03001089 if (status) {
1090 u8 mgmt_err = mgmt_status(status);
1091 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1092 goto remove_cmd;
1093 }
1094
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001095 cp = cmd->param;
1096 if (cp->val)
1097 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1098 else
1099 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1100
Johan Hedberg2b76f452013-03-15 17:07:04 -05001101 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1102
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001103 if (changed)
1104 new_settings(hdev, cmd->sk);
1105
Johan Hedberg37438c12013-10-14 16:20:05 +03001106remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001107 mgmt_pending_remove(cmd);
1108
1109unlock:
1110 hci_dev_unlock(hdev);
1111}
1112
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001113static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001114 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001115{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001116 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001117 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001118 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001119 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001120 int err;
1121
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001122 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001123
Johan Hedberge6fe7982013-10-02 15:45:22 +03001124 status = mgmt_bredr_support(hdev);
1125 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001126 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001127 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001128
Johan Hedberga7e80f22013-01-09 16:05:19 +02001129 if (cp->val != 0x00 && cp->val != 0x01)
1130 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1131 MGMT_STATUS_INVALID_PARAMS);
1132
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001133 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001134
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001135 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001136 bool changed = false;
1137
1138 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1139 changed = true;
1140
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001141 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001142 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001143 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001144 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1145 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1146 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001147
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001148 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001149 if (err < 0)
1150 goto failed;
1151
1152 if (changed)
1153 err = new_settings(hdev, sk);
1154
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001155 goto failed;
1156 }
1157
1158 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001159 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001160 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001161 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001162 goto failed;
1163 }
1164
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001165 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1166 if (!cmd) {
1167 err = -ENOMEM;
1168 goto failed;
1169 }
1170
Johan Hedberg2b76f452013-03-15 17:07:04 -05001171 hci_req_init(&req, hdev);
1172
Johan Hedberg9b742462013-10-14 16:20:03 +03001173 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1174 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
1175
1176 if (cp->val) {
1177 scan = SCAN_PAGE;
1178 } else {
1179 scan = 0;
1180
1181 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1182 hdev->discov_timeout > 0)
1183 cancel_delayed_work(&hdev->discov_off);
1184 }
1185
1186 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1187 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001188
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001189 /* If we're going from non-connectable to connectable or
1190 * vice-versa when fast connectable is enabled ensure that fast
1191 * connectable gets disabled. write_fast_connectable won't do
1192 * anything if the page scan parameters are already what they
1193 * should be.
1194 */
1195 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001196 write_fast_connectable(&req, false);
1197
Johan Hedberg2b76f452013-03-15 17:07:04 -05001198 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001199 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001200 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001201 if (err == -ENODATA)
1202 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1203 hdev);
1204 goto failed;
1205 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001206
1207failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001208 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001209 return err;
1210}
1211
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001212static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001213 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001214{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001215 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001216 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001217 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001218
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001219 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001220
Johan Hedberga7e80f22013-01-09 16:05:19 +02001221 if (cp->val != 0x00 && cp->val != 0x01)
1222 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1223 MGMT_STATUS_INVALID_PARAMS);
1224
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001225 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001226
1227 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001228 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001229 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001230 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001231
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001232 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001233 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001234 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001235
Marcel Holtmann55594352013-10-06 16:11:57 -07001236 if (changed)
1237 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001238
Marcel Holtmann55594352013-10-06 16:11:57 -07001239unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001240 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001241 return err;
1242}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001243
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001244static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1245 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001246{
1247 struct mgmt_mode *cp = data;
1248 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001249 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001250 int err;
1251
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001252 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001253
Johan Hedberge6fe7982013-10-02 15:45:22 +03001254 status = mgmt_bredr_support(hdev);
1255 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001256 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001257 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001258
Johan Hedberga7e80f22013-01-09 16:05:19 +02001259 if (cp->val != 0x00 && cp->val != 0x01)
1260 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1261 MGMT_STATUS_INVALID_PARAMS);
1262
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001263 hci_dev_lock(hdev);
1264
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001265 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001266 bool changed = false;
1267
1268 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001269 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001270 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1271 changed = true;
1272 }
1273
1274 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1275 if (err < 0)
1276 goto failed;
1277
1278 if (changed)
1279 err = new_settings(hdev, sk);
1280
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001281 goto failed;
1282 }
1283
1284 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001285 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001286 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001287 goto failed;
1288 }
1289
1290 val = !!cp->val;
1291
1292 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1293 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1294 goto failed;
1295 }
1296
1297 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1298 if (!cmd) {
1299 err = -ENOMEM;
1300 goto failed;
1301 }
1302
1303 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1304 if (err < 0) {
1305 mgmt_pending_remove(cmd);
1306 goto failed;
1307 }
1308
1309failed:
1310 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001311 return err;
1312}
1313
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001314static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001315{
1316 struct mgmt_mode *cp = data;
1317 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001318 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001319 int err;
1320
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001321 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001322
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001323 status = mgmt_bredr_support(hdev);
1324 if (status)
1325 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1326
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001327 if (!lmp_ssp_capable(hdev))
1328 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1329 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001330
Johan Hedberga7e80f22013-01-09 16:05:19 +02001331 if (cp->val != 0x00 && cp->val != 0x01)
1332 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1333 MGMT_STATUS_INVALID_PARAMS);
1334
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001335 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001336
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001337 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001338 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001339
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001340 if (cp->val) {
1341 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1342 &hdev->dev_flags);
1343 } else {
1344 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1345 &hdev->dev_flags);
1346 if (!changed)
1347 changed = test_and_clear_bit(HCI_HS_ENABLED,
1348 &hdev->dev_flags);
1349 else
1350 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001351 }
1352
1353 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1354 if (err < 0)
1355 goto failed;
1356
1357 if (changed)
1358 err = new_settings(hdev, sk);
1359
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001360 goto failed;
1361 }
1362
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001363 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1364 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001365 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1366 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001367 goto failed;
1368 }
1369
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001370 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001371 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1372 goto failed;
1373 }
1374
1375 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1376 if (!cmd) {
1377 err = -ENOMEM;
1378 goto failed;
1379 }
1380
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001381 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001382 if (err < 0) {
1383 mgmt_pending_remove(cmd);
1384 goto failed;
1385 }
1386
1387failed:
1388 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001389 return err;
1390}
1391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001392static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001393{
1394 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001395 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001396 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001397 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001398
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001399 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001400
Johan Hedberge6fe7982013-10-02 15:45:22 +03001401 status = mgmt_bredr_support(hdev);
1402 if (status)
1403 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001404
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001405 if (!lmp_ssp_capable(hdev))
1406 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1407 MGMT_STATUS_NOT_SUPPORTED);
1408
1409 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1410 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1411 MGMT_STATUS_REJECTED);
1412
Johan Hedberga7e80f22013-01-09 16:05:19 +02001413 if (cp->val != 0x00 && cp->val != 0x01)
1414 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1415 MGMT_STATUS_INVALID_PARAMS);
1416
Marcel Holtmannee392692013-10-01 22:59:23 -07001417 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001418
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001419 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001420 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001421 } else {
1422 if (hdev_is_powered(hdev)) {
1423 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1424 MGMT_STATUS_REJECTED);
1425 goto unlock;
1426 }
1427
Marcel Holtmannee392692013-10-01 22:59:23 -07001428 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001429 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001430
1431 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1432 if (err < 0)
1433 goto unlock;
1434
1435 if (changed)
1436 err = new_settings(hdev, sk);
1437
1438unlock:
1439 hci_dev_unlock(hdev);
1440 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001441}
1442
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001443static void enable_advertising(struct hci_request *req)
1444{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001445 struct hci_dev *hdev = req->hdev;
1446 struct hci_cp_le_set_adv_param cp;
1447 u8 enable = 0x01;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001448
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001449 memset(&cp, 0, sizeof(cp));
1450 cp.min_interval = __constant_cpu_to_le16(0x0800);
1451 cp.max_interval = __constant_cpu_to_le16(0x0800);
1452 cp.type = LE_ADV_IND;
1453 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1454 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1455 else
1456 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1457 cp.channel_map = 0x07;
1458
1459 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1460
1461 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001462}
1463
1464static void disable_advertising(struct hci_request *req)
1465{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001466 u8 enable = 0x00;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001467
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001468 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001469}
1470
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001471static void le_enable_complete(struct hci_dev *hdev, u8 status)
1472{
1473 struct cmd_lookup match = { NULL, hdev };
1474
1475 if (status) {
1476 u8 mgmt_err = mgmt_status(status);
1477
1478 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1479 &mgmt_err);
1480 return;
1481 }
1482
1483 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1484
1485 new_settings(hdev, match.sk);
1486
1487 if (match.sk)
1488 sock_put(match.sk);
1489}
1490
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001491static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001492{
1493 struct mgmt_mode *cp = data;
1494 struct hci_cp_write_le_host_supported hci_cp;
1495 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001496 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001497 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001498 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001499
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001500 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001501
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001502 if (!lmp_le_capable(hdev))
1503 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1504 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001505
Johan Hedberga7e80f22013-01-09 16:05:19 +02001506 if (cp->val != 0x00 && cp->val != 0x01)
1507 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1508 MGMT_STATUS_INVALID_PARAMS);
1509
Johan Hedbergc73eee92013-04-19 18:35:21 +03001510 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001511 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001512 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1513 MGMT_STATUS_REJECTED);
1514
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001515 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001516
1517 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001518 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001519
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001520 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001521 bool changed = false;
1522
1523 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1524 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1525 changed = true;
1526 }
1527
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001528 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1529 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001530 changed = true;
1531 }
1532
Johan Hedberg06199cf2012-02-22 16:37:11 +02001533 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1534 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001535 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001536
1537 if (changed)
1538 err = new_settings(hdev, sk);
1539
Johan Hedberg1de028c2012-02-29 19:55:35 -08001540 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001541 }
1542
Johan Hedberg4375f102013-09-25 13:26:10 +03001543 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1544 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001545 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001546 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001547 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001548 }
1549
1550 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1551 if (!cmd) {
1552 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001553 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001554 }
1555
1556 memset(&hci_cp, 0, sizeof(hci_cp));
1557
1558 if (val) {
1559 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001560 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001561 }
1562
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001563 hci_req_init(&req, hdev);
1564
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001565 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1566 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001567
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001568 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1569 &hci_cp);
1570
1571 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301572 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001573 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001574
Johan Hedberg1de028c2012-02-29 19:55:35 -08001575unlock:
1576 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001577 return err;
1578}
1579
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001580/* This is a helper function to test for pending mgmt commands that can
1581 * cause CoD or EIR HCI commands. We can only allow one such pending
1582 * mgmt command at a time since otherwise we cannot easily track what
1583 * the current values are, will be, and based on that calculate if a new
1584 * HCI command needs to be sent and if yes with what value.
1585 */
1586static bool pending_eir_or_class(struct hci_dev *hdev)
1587{
1588 struct pending_cmd *cmd;
1589
1590 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1591 switch (cmd->opcode) {
1592 case MGMT_OP_ADD_UUID:
1593 case MGMT_OP_REMOVE_UUID:
1594 case MGMT_OP_SET_DEV_CLASS:
1595 case MGMT_OP_SET_POWERED:
1596 return true;
1597 }
1598 }
1599
1600 return false;
1601}
1602
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001603static const u8 bluetooth_base_uuid[] = {
1604 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1605 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1606};
1607
1608static u8 get_uuid_size(const u8 *uuid)
1609{
1610 u32 val;
1611
1612 if (memcmp(uuid, bluetooth_base_uuid, 12))
1613 return 128;
1614
1615 val = get_unaligned_le32(&uuid[12]);
1616 if (val > 0xffff)
1617 return 32;
1618
1619 return 16;
1620}
1621
Johan Hedberg92da6092013-03-15 17:06:55 -05001622static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1623{
1624 struct pending_cmd *cmd;
1625
1626 hci_dev_lock(hdev);
1627
1628 cmd = mgmt_pending_find(mgmt_op, hdev);
1629 if (!cmd)
1630 goto unlock;
1631
1632 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1633 hdev->dev_class, 3);
1634
1635 mgmt_pending_remove(cmd);
1636
1637unlock:
1638 hci_dev_unlock(hdev);
1639}
1640
1641static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1642{
1643 BT_DBG("status 0x%02x", status);
1644
1645 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1646}
1647
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001648static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001649{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001650 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001651 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001652 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001653 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001654 int err;
1655
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001656 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001657
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001658 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001659
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001660 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001661 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001662 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001663 goto failed;
1664 }
1665
Andre Guedes92c4c202012-06-07 19:05:44 -03001666 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001667 if (!uuid) {
1668 err = -ENOMEM;
1669 goto failed;
1670 }
1671
1672 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001673 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001674 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001675
Johan Hedbergde66aa62013-01-27 00:31:27 +02001676 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001677
Johan Hedberg890ea892013-03-15 17:06:52 -05001678 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001679
Johan Hedberg890ea892013-03-15 17:06:52 -05001680 update_class(&req);
1681 update_eir(&req);
1682
Johan Hedberg92da6092013-03-15 17:06:55 -05001683 err = hci_req_run(&req, add_uuid_complete);
1684 if (err < 0) {
1685 if (err != -ENODATA)
1686 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001687
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001688 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001689 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001690 goto failed;
1691 }
1692
1693 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001694 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001695 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001696 goto failed;
1697 }
1698
1699 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001700
1701failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001702 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001703 return err;
1704}
1705
Johan Hedberg24b78d02012-02-23 23:24:30 +02001706static bool enable_service_cache(struct hci_dev *hdev)
1707{
1708 if (!hdev_is_powered(hdev))
1709 return false;
1710
1711 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001712 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1713 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001714 return true;
1715 }
1716
1717 return false;
1718}
1719
Johan Hedberg92da6092013-03-15 17:06:55 -05001720static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1721{
1722 BT_DBG("status 0x%02x", status);
1723
1724 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1725}
1726
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001727static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001728 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001729{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001730 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001731 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001732 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001733 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 -05001734 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001735 int err, found;
1736
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001737 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001738
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001739 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001740
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001741 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001742 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001743 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001744 goto unlock;
1745 }
1746
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001747 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1748 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001749
Johan Hedberg24b78d02012-02-23 23:24:30 +02001750 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001751 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001752 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001753 goto unlock;
1754 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001755
Johan Hedberg9246a862012-02-23 21:33:16 +02001756 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001757 }
1758
1759 found = 0;
1760
Johan Hedberg056341c2013-01-27 00:31:30 +02001761 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001762 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1763 continue;
1764
1765 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001766 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001767 found++;
1768 }
1769
1770 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001771 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001772 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001773 goto unlock;
1774 }
1775
Johan Hedberg9246a862012-02-23 21:33:16 +02001776update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001777 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001778
Johan Hedberg890ea892013-03-15 17:06:52 -05001779 update_class(&req);
1780 update_eir(&req);
1781
Johan Hedberg92da6092013-03-15 17:06:55 -05001782 err = hci_req_run(&req, remove_uuid_complete);
1783 if (err < 0) {
1784 if (err != -ENODATA)
1785 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001786
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001787 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001788 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001789 goto unlock;
1790 }
1791
1792 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001793 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001794 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001795 goto unlock;
1796 }
1797
1798 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001799
1800unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001801 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001802 return err;
1803}
1804
Johan Hedberg92da6092013-03-15 17:06:55 -05001805static void set_class_complete(struct hci_dev *hdev, u8 status)
1806{
1807 BT_DBG("status 0x%02x", status);
1808
1809 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1810}
1811
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001812static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001813 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001814{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001815 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001816 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001817 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001818 int err;
1819
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001820 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001821
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001822 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001823 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1824 MGMT_STATUS_NOT_SUPPORTED);
1825
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001826 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001827
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001828 if (pending_eir_or_class(hdev)) {
1829 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1830 MGMT_STATUS_BUSY);
1831 goto unlock;
1832 }
1833
1834 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1835 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1836 MGMT_STATUS_INVALID_PARAMS);
1837 goto unlock;
1838 }
1839
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001840 hdev->major_class = cp->major;
1841 hdev->minor_class = cp->minor;
1842
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001843 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001844 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001845 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001846 goto unlock;
1847 }
1848
Johan Hedberg890ea892013-03-15 17:06:52 -05001849 hci_req_init(&req, hdev);
1850
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001851 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001852 hci_dev_unlock(hdev);
1853 cancel_delayed_work_sync(&hdev->service_cache);
1854 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001855 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001856 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001857
Johan Hedberg890ea892013-03-15 17:06:52 -05001858 update_class(&req);
1859
Johan Hedberg92da6092013-03-15 17:06:55 -05001860 err = hci_req_run(&req, set_class_complete);
1861 if (err < 0) {
1862 if (err != -ENODATA)
1863 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001864
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001865 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001866 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001867 goto unlock;
1868 }
1869
1870 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001871 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001872 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001873 goto unlock;
1874 }
1875
1876 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001877
Johan Hedbergb5235a62012-02-21 14:32:24 +02001878unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001879 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001880 return err;
1881}
1882
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001883static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001884 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001885{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001886 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001887 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001888 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001889
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001890 BT_DBG("request for %s", hdev->name);
1891
1892 if (!lmp_bredr_capable(hdev))
1893 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1894 MGMT_STATUS_NOT_SUPPORTED);
1895
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001896 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001897
Johan Hedberg86742e12011-11-07 23:13:38 +02001898 expected_len = sizeof(*cp) + key_count *
1899 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001900 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001901 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001902 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001903 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001904 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001905 }
1906
Johan Hedberg4ae143012013-01-20 14:27:13 +02001907 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1908 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1909 MGMT_STATUS_INVALID_PARAMS);
1910
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001911 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001912 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001913
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001914 for (i = 0; i < key_count; i++) {
1915 struct mgmt_link_key_info *key = &cp->keys[i];
1916
1917 if (key->addr.type != BDADDR_BREDR)
1918 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1919 MGMT_STATUS_INVALID_PARAMS);
1920 }
1921
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001922 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001923
1924 hci_link_keys_clear(hdev);
1925
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001926 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001927 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001928 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001929 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001930
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001931 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001932 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001933
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001934 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001935 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001936 }
1937
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001938 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001939
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001940 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001941
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001942 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001943}
1944
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001945static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001946 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001947{
1948 struct mgmt_ev_device_unpaired ev;
1949
1950 bacpy(&ev.addr.bdaddr, bdaddr);
1951 ev.addr.type = addr_type;
1952
1953 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001954 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001955}
1956
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001957static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001958 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001959{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001960 struct mgmt_cp_unpair_device *cp = data;
1961 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001962 struct hci_cp_disconnect dc;
1963 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001964 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001965 int err;
1966
Johan Hedberga8a1d192011-11-10 15:54:38 +02001967 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001968 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1969 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001970
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001971 if (!bdaddr_type_is_valid(cp->addr.type))
1972 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1973 MGMT_STATUS_INVALID_PARAMS,
1974 &rp, sizeof(rp));
1975
Johan Hedberg118da702013-01-20 14:27:20 +02001976 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1977 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1978 MGMT_STATUS_INVALID_PARAMS,
1979 &rp, sizeof(rp));
1980
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001981 hci_dev_lock(hdev);
1982
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001983 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001984 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001985 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001986 goto unlock;
1987 }
1988
Andre Guedes591f47f2012-04-24 21:02:49 -03001989 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001990 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1991 else
1992 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001993
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001994 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001995 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001996 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001997 goto unlock;
1998 }
1999
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002000 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002001 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002002 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002003 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002004 else
2005 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002006 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002007 } else {
2008 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002009 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002010
Johan Hedberga8a1d192011-11-10 15:54:38 +02002011 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002012 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002013 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002014 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002015 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002016 }
2017
Johan Hedberg124f6e32012-02-09 13:50:12 +02002018 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002019 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002020 if (!cmd) {
2021 err = -ENOMEM;
2022 goto unlock;
2023 }
2024
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002025 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002026 dc.reason = 0x13; /* Remote User Terminated Connection */
2027 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2028 if (err < 0)
2029 mgmt_pending_remove(cmd);
2030
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002031unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002032 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002033 return err;
2034}
2035
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002036static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002037 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002038{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002039 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002040 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002041 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002042 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002043 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002044 int err;
2045
2046 BT_DBG("");
2047
Johan Hedberg06a63b12013-01-20 14:27:21 +02002048 memset(&rp, 0, sizeof(rp));
2049 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2050 rp.addr.type = cp->addr.type;
2051
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002052 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002053 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2054 MGMT_STATUS_INVALID_PARAMS,
2055 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002056
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002057 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002058
2059 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002060 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2061 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002062 goto failed;
2063 }
2064
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002065 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002066 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2067 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002068 goto failed;
2069 }
2070
Andre Guedes591f47f2012-04-24 21:02:49 -03002071 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002072 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2073 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002074 else
2075 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002076
Vishal Agarwalf9607272012-06-13 05:32:43 +05302077 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002078 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2079 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002080 goto failed;
2081 }
2082
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002083 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002084 if (!cmd) {
2085 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002086 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002087 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002088
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002089 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002090 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002091
2092 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2093 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002094 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002095
2096failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002097 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002098 return err;
2099}
2100
Andre Guedes57c14772012-04-24 21:02:50 -03002101static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002102{
2103 switch (link_type) {
2104 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002105 switch (addr_type) {
2106 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002107 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002108
Johan Hedberg48264f02011-11-09 13:58:58 +02002109 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002110 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002111 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002112 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002113
Johan Hedberg4c659c32011-11-07 23:13:39 +02002114 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002115 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002116 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002117 }
2118}
2119
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002120static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2121 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002122{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002123 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002124 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002125 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002126 int err;
2127 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002128
2129 BT_DBG("");
2130
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002131 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002132
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002133 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002134 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002135 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002136 goto unlock;
2137 }
2138
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002139 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002140 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2141 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002142 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002143 }
2144
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002145 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002146 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002147 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002148 err = -ENOMEM;
2149 goto unlock;
2150 }
2151
Johan Hedberg2784eb42011-01-21 13:56:35 +02002152 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002153 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002154 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2155 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002156 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002157 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002158 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002159 continue;
2160 i++;
2161 }
2162
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002163 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002164
Johan Hedberg4c659c32011-11-07 23:13:39 +02002165 /* Recalculate length in case of filtered SCO connections, etc */
2166 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002167
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002168 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002169 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002170
Johan Hedberga38528f2011-01-22 06:46:43 +02002171 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002172
2173unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002174 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002175 return err;
2176}
2177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002178static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002179 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002180{
2181 struct pending_cmd *cmd;
2182 int err;
2183
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002184 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002185 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002186 if (!cmd)
2187 return -ENOMEM;
2188
Johan Hedbergd8457692012-02-17 14:24:57 +02002189 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002190 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002191 if (err < 0)
2192 mgmt_pending_remove(cmd);
2193
2194 return err;
2195}
2196
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002197static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002198 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002199{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002200 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002201 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002202 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002203 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002204 int err;
2205
2206 BT_DBG("");
2207
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002208 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002209
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002210 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002211 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002212 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002213 goto failed;
2214 }
2215
Johan Hedbergd8457692012-02-17 14:24:57 +02002216 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002217 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002218 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002219 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002220 goto failed;
2221 }
2222
2223 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002224 struct mgmt_cp_pin_code_neg_reply ncp;
2225
2226 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002227
2228 BT_ERR("PIN code is not 16 bytes long");
2229
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002230 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002231 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002232 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002233 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002234
2235 goto failed;
2236 }
2237
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002238 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002239 if (!cmd) {
2240 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002241 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002242 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002243
Johan Hedbergd8457692012-02-17 14:24:57 +02002244 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002245 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002246 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002247
2248 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2249 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002250 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002251
2252failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002253 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002254 return err;
2255}
2256
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002257static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2258 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002259{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002260 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002261
2262 BT_DBG("");
2263
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002264 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002265
2266 hdev->io_capability = cp->io_capability;
2267
2268 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002269 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002270
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002271 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002272
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002273 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2274 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002275}
2276
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002277static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002278{
2279 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002280 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002281
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002282 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002283 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2284 continue;
2285
Johan Hedberge9a416b2011-02-19 12:05:56 -03002286 if (cmd->user_data != conn)
2287 continue;
2288
2289 return cmd;
2290 }
2291
2292 return NULL;
2293}
2294
2295static void pairing_complete(struct pending_cmd *cmd, u8 status)
2296{
2297 struct mgmt_rp_pair_device rp;
2298 struct hci_conn *conn = cmd->user_data;
2299
Johan Hedbergba4e5642011-11-11 00:07:34 +02002300 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002301 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002302
Johan Hedbergaee9b212012-02-18 15:07:59 +02002303 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002304 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002305
2306 /* So we don't get further callbacks for this connection */
2307 conn->connect_cfm_cb = NULL;
2308 conn->security_cfm_cb = NULL;
2309 conn->disconn_cfm_cb = NULL;
2310
David Herrmann76a68ba2013-04-06 20:28:37 +02002311 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002312
Johan Hedberga664b5b2011-02-19 12:06:02 -03002313 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002314}
2315
2316static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2317{
2318 struct pending_cmd *cmd;
2319
2320 BT_DBG("status %u", status);
2321
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002322 cmd = find_pairing(conn);
2323 if (!cmd)
2324 BT_DBG("Unable to find a pending command");
2325 else
Johan Hedberge2113262012-02-18 15:20:03 +02002326 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002327}
2328
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302329static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2330{
2331 struct pending_cmd *cmd;
2332
2333 BT_DBG("status %u", status);
2334
2335 if (!status)
2336 return;
2337
2338 cmd = find_pairing(conn);
2339 if (!cmd)
2340 BT_DBG("Unable to find a pending command");
2341 else
2342 pairing_complete(cmd, mgmt_status(status));
2343}
2344
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002345static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002346 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002347{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002348 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002349 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002350 struct pending_cmd *cmd;
2351 u8 sec_level, auth_type;
2352 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002353 int err;
2354
2355 BT_DBG("");
2356
Szymon Jancf950a30e2013-01-18 12:48:07 +01002357 memset(&rp, 0, sizeof(rp));
2358 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2359 rp.addr.type = cp->addr.type;
2360
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002361 if (!bdaddr_type_is_valid(cp->addr.type))
2362 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2363 MGMT_STATUS_INVALID_PARAMS,
2364 &rp, sizeof(rp));
2365
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002366 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002367
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002368 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002369 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2370 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002371 goto unlock;
2372 }
2373
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002374 sec_level = BT_SECURITY_MEDIUM;
2375 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002376 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002377 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002378 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002379
Andre Guedes591f47f2012-04-24 21:02:49 -03002380 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002381 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2382 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002383 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002384 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2385 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002386
Ville Tervo30e76272011-02-22 16:10:53 -03002387 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002388 int status;
2389
2390 if (PTR_ERR(conn) == -EBUSY)
2391 status = MGMT_STATUS_BUSY;
2392 else
2393 status = MGMT_STATUS_CONNECT_FAILED;
2394
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002395 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002396 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002397 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002398 goto unlock;
2399 }
2400
2401 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002402 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002403 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002404 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002405 goto unlock;
2406 }
2407
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002408 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002409 if (!cmd) {
2410 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002411 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002412 goto unlock;
2413 }
2414
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002415 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002416 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002417 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302418 else
2419 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002420
Johan Hedberge9a416b2011-02-19 12:05:56 -03002421 conn->security_cfm_cb = pairing_complete_cb;
2422 conn->disconn_cfm_cb = pairing_complete_cb;
2423 conn->io_capability = cp->io_cap;
2424 cmd->user_data = conn;
2425
2426 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002427 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002428 pairing_complete(cmd, 0);
2429
2430 err = 0;
2431
2432unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002433 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002434 return err;
2435}
2436
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002437static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2438 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002439{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002440 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002441 struct pending_cmd *cmd;
2442 struct hci_conn *conn;
2443 int err;
2444
2445 BT_DBG("");
2446
Johan Hedberg28424702012-02-02 04:02:29 +02002447 hci_dev_lock(hdev);
2448
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002449 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002450 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002451 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002452 goto unlock;
2453 }
2454
Johan Hedberg28424702012-02-02 04:02:29 +02002455 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2456 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002457 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002458 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002459 goto unlock;
2460 }
2461
2462 conn = cmd->user_data;
2463
2464 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002465 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002466 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002467 goto unlock;
2468 }
2469
2470 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2471
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002472 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002473 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002474unlock:
2475 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002476 return err;
2477}
2478
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002479static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002480 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002481 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002482{
Johan Hedberga5c29682011-02-19 12:05:57 -03002483 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002484 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002485 int err;
2486
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002487 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002488
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002489 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002490 err = cmd_complete(sk, hdev->id, mgmt_op,
2491 MGMT_STATUS_NOT_POWERED, addr,
2492 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002493 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002494 }
2495
Johan Hedberg1707c602013-03-15 17:07:15 -05002496 if (addr->type == BDADDR_BREDR)
2497 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002498 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002499 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002500
Johan Hedberg272d90d2012-02-09 15:26:12 +02002501 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002502 err = cmd_complete(sk, hdev->id, mgmt_op,
2503 MGMT_STATUS_NOT_CONNECTED, addr,
2504 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002505 goto done;
2506 }
2507
Johan Hedberg1707c602013-03-15 17:07:15 -05002508 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002509 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002510 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002511
Brian Gix5fe57d92011-12-21 16:12:13 -08002512 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002513 err = cmd_complete(sk, hdev->id, mgmt_op,
2514 MGMT_STATUS_SUCCESS, addr,
2515 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002516 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002517 err = cmd_complete(sk, hdev->id, mgmt_op,
2518 MGMT_STATUS_FAILED, addr,
2519 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002520
Brian Gix47c15e22011-11-16 13:53:14 -08002521 goto done;
2522 }
2523
Johan Hedberg1707c602013-03-15 17:07:15 -05002524 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002525 if (!cmd) {
2526 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002527 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002528 }
2529
Brian Gix0df4c182011-11-16 13:53:13 -08002530 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002531 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2532 struct hci_cp_user_passkey_reply cp;
2533
Johan Hedberg1707c602013-03-15 17:07:15 -05002534 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002535 cp.passkey = passkey;
2536 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2537 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002538 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2539 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002540
Johan Hedberga664b5b2011-02-19 12:06:02 -03002541 if (err < 0)
2542 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002543
Brian Gix0df4c182011-11-16 13:53:13 -08002544done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002545 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002546 return err;
2547}
2548
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302549static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2550 void *data, u16 len)
2551{
2552 struct mgmt_cp_pin_code_neg_reply *cp = data;
2553
2554 BT_DBG("");
2555
Johan Hedberg1707c602013-03-15 17:07:15 -05002556 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302557 MGMT_OP_PIN_CODE_NEG_REPLY,
2558 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2559}
2560
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002561static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2562 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002563{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002564 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002565
2566 BT_DBG("");
2567
2568 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002569 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002570 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002571
Johan Hedberg1707c602013-03-15 17:07:15 -05002572 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002573 MGMT_OP_USER_CONFIRM_REPLY,
2574 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002575}
2576
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002577static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002578 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002579{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002580 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002581
2582 BT_DBG("");
2583
Johan Hedberg1707c602013-03-15 17:07:15 -05002584 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002585 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2586 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002587}
2588
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002589static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2590 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002591{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002592 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002593
2594 BT_DBG("");
2595
Johan Hedberg1707c602013-03-15 17:07:15 -05002596 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002597 MGMT_OP_USER_PASSKEY_REPLY,
2598 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002599}
2600
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002601static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002602 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002603{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002604 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002605
2606 BT_DBG("");
2607
Johan Hedberg1707c602013-03-15 17:07:15 -05002608 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002609 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2610 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002611}
2612
Johan Hedberg13928972013-03-15 17:07:00 -05002613static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002614{
Johan Hedberg13928972013-03-15 17:07:00 -05002615 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002616 struct hci_cp_write_local_name cp;
2617
Johan Hedberg13928972013-03-15 17:07:00 -05002618 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002619
Johan Hedberg890ea892013-03-15 17:06:52 -05002620 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002621}
2622
Johan Hedberg13928972013-03-15 17:07:00 -05002623static void set_name_complete(struct hci_dev *hdev, u8 status)
2624{
2625 struct mgmt_cp_set_local_name *cp;
2626 struct pending_cmd *cmd;
2627
2628 BT_DBG("status 0x%02x", status);
2629
2630 hci_dev_lock(hdev);
2631
2632 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2633 if (!cmd)
2634 goto unlock;
2635
2636 cp = cmd->param;
2637
2638 if (status)
2639 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2640 mgmt_status(status));
2641 else
2642 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2643 cp, sizeof(*cp));
2644
2645 mgmt_pending_remove(cmd);
2646
2647unlock:
2648 hci_dev_unlock(hdev);
2649}
2650
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002651static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002652 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002653{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002654 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002655 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002656 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002657 int err;
2658
2659 BT_DBG("");
2660
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002661 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002662
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002663 /* If the old values are the same as the new ones just return a
2664 * direct command complete event.
2665 */
2666 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2667 !memcmp(hdev->short_name, cp->short_name,
2668 sizeof(hdev->short_name))) {
2669 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2670 data, len);
2671 goto failed;
2672 }
2673
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002674 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002675
Johan Hedbergb5235a62012-02-21 14:32:24 +02002676 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002677 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002678
2679 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002680 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002681 if (err < 0)
2682 goto failed;
2683
2684 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002685 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002686
Johan Hedbergb5235a62012-02-21 14:32:24 +02002687 goto failed;
2688 }
2689
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002690 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002691 if (!cmd) {
2692 err = -ENOMEM;
2693 goto failed;
2694 }
2695
Johan Hedberg13928972013-03-15 17:07:00 -05002696 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2697
Johan Hedberg890ea892013-03-15 17:06:52 -05002698 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002699
2700 if (lmp_bredr_capable(hdev)) {
2701 update_name(&req);
2702 update_eir(&req);
2703 }
2704
2705 if (lmp_le_capable(hdev))
2706 hci_update_ad(&req);
2707
Johan Hedberg13928972013-03-15 17:07:00 -05002708 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002709 if (err < 0)
2710 mgmt_pending_remove(cmd);
2711
2712failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002713 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002714 return err;
2715}
2716
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002717static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002718 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002719{
Szymon Jancc35938b2011-03-22 13:12:21 +01002720 struct pending_cmd *cmd;
2721 int err;
2722
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002723 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002724
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002725 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002726
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002727 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002728 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002729 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002730 goto unlock;
2731 }
2732
Andre Guedes9a1a1992012-07-24 15:03:48 -03002733 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002734 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002735 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002736 goto unlock;
2737 }
2738
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002739 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002740 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002741 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002742 goto unlock;
2743 }
2744
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002745 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002746 if (!cmd) {
2747 err = -ENOMEM;
2748 goto unlock;
2749 }
2750
2751 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2752 if (err < 0)
2753 mgmt_pending_remove(cmd);
2754
2755unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002756 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002757 return err;
2758}
2759
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002760static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002761 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002762{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002763 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002764 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002765 int err;
2766
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002767 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002768
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002769 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002770
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002771 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002772 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002773 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002774 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002775 else
Szymon Janca6785be2012-12-13 15:11:21 +01002776 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002777
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002778 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002779 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002780
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002781 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002782 return err;
2783}
2784
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002785static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002786 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002787{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002788 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002789 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002790 int err;
2791
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002792 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002793
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002794 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002795
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002796 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002797 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002798 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002799 else
Szymon Janca6785be2012-12-13 15:11:21 +01002800 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002801
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002802 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002803 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002804
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002805 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002806 return err;
2807}
2808
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002809static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2810{
2811 struct pending_cmd *cmd;
2812 u8 type;
2813 int err;
2814
2815 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2816
2817 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2818 if (!cmd)
2819 return -ENOENT;
2820
2821 type = hdev->discovery.type;
2822
2823 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2824 &type, sizeof(type));
2825 mgmt_pending_remove(cmd);
2826
2827 return err;
2828}
2829
Andre Guedes7c307722013-04-30 15:29:28 -03002830static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2831{
2832 BT_DBG("status %d", status);
2833
2834 if (status) {
2835 hci_dev_lock(hdev);
2836 mgmt_start_discovery_failed(hdev, status);
2837 hci_dev_unlock(hdev);
2838 return;
2839 }
2840
2841 hci_dev_lock(hdev);
2842 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2843 hci_dev_unlock(hdev);
2844
2845 switch (hdev->discovery.type) {
2846 case DISCOV_TYPE_LE:
2847 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002848 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002849 break;
2850
2851 case DISCOV_TYPE_INTERLEAVED:
2852 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002853 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002854 break;
2855
2856 case DISCOV_TYPE_BREDR:
2857 break;
2858
2859 default:
2860 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2861 }
2862}
2863
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002864static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002865 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002866{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002867 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002868 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002869 struct hci_cp_le_set_scan_param param_cp;
2870 struct hci_cp_le_set_scan_enable enable_cp;
2871 struct hci_cp_inquiry inq_cp;
2872 struct hci_request req;
2873 /* General inquiry access code (GIAC) */
2874 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002875 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002876 int err;
2877
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002878 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002879
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002880 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002881
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002882 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002883 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002884 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002885 goto failed;
2886 }
2887
Andre Guedes642be6c2012-03-21 00:03:37 -03002888 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2889 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2890 MGMT_STATUS_BUSY);
2891 goto failed;
2892 }
2893
Johan Hedbergff9ef572012-01-04 14:23:45 +02002894 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002895 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002896 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002897 goto failed;
2898 }
2899
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002900 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002901 if (!cmd) {
2902 err = -ENOMEM;
2903 goto failed;
2904 }
2905
Andre Guedes4aab14e2012-02-17 20:39:36 -03002906 hdev->discovery.type = cp->type;
2907
Andre Guedes7c307722013-04-30 15:29:28 -03002908 hci_req_init(&req, hdev);
2909
Andre Guedes4aab14e2012-02-17 20:39:36 -03002910 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002911 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002912 status = mgmt_bredr_support(hdev);
2913 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002914 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002915 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002916 mgmt_pending_remove(cmd);
2917 goto failed;
2918 }
2919
Andre Guedes7c307722013-04-30 15:29:28 -03002920 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2921 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2922 MGMT_STATUS_BUSY);
2923 mgmt_pending_remove(cmd);
2924 goto failed;
2925 }
2926
2927 hci_inquiry_cache_flush(hdev);
2928
2929 memset(&inq_cp, 0, sizeof(inq_cp));
2930 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002931 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002932 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002933 break;
2934
2935 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002936 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002937 status = mgmt_le_support(hdev);
2938 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002939 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002940 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002941 mgmt_pending_remove(cmd);
2942 goto failed;
2943 }
2944
Andre Guedes7c307722013-04-30 15:29:28 -03002945 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002946 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002947 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2948 MGMT_STATUS_NOT_SUPPORTED);
2949 mgmt_pending_remove(cmd);
2950 goto failed;
2951 }
2952
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002953 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002954 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2955 MGMT_STATUS_REJECTED);
2956 mgmt_pending_remove(cmd);
2957 goto failed;
2958 }
2959
2960 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2961 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2962 MGMT_STATUS_BUSY);
2963 mgmt_pending_remove(cmd);
2964 goto failed;
2965 }
2966
2967 memset(&param_cp, 0, sizeof(param_cp));
2968 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002969 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2970 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002971 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2972 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2973 else
2974 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002975 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2976 &param_cp);
2977
2978 memset(&enable_cp, 0, sizeof(enable_cp));
2979 enable_cp.enable = LE_SCAN_ENABLE;
2980 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2981 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2982 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002983 break;
2984
Andre Guedesf39799f2012-02-17 20:39:35 -03002985 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002986 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2987 MGMT_STATUS_INVALID_PARAMS);
2988 mgmt_pending_remove(cmd);
2989 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002990 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002991
Andre Guedes7c307722013-04-30 15:29:28 -03002992 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002993 if (err < 0)
2994 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002995 else
2996 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002997
2998failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002999 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003000 return err;
3001}
3002
Andre Guedes1183fdc2013-04-30 15:29:35 -03003003static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3004{
3005 struct pending_cmd *cmd;
3006 int err;
3007
3008 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3009 if (!cmd)
3010 return -ENOENT;
3011
3012 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3013 &hdev->discovery.type, sizeof(hdev->discovery.type));
3014 mgmt_pending_remove(cmd);
3015
3016 return err;
3017}
3018
Andre Guedes0e05bba2013-04-30 15:29:33 -03003019static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3020{
3021 BT_DBG("status %d", status);
3022
3023 hci_dev_lock(hdev);
3024
3025 if (status) {
3026 mgmt_stop_discovery_failed(hdev, status);
3027 goto unlock;
3028 }
3029
3030 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3031
3032unlock:
3033 hci_dev_unlock(hdev);
3034}
3035
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003036static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003037 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003038{
Johan Hedbergd9306502012-02-20 23:25:18 +02003039 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003040 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003041 struct hci_cp_remote_name_req_cancel cp;
3042 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003043 struct hci_request req;
3044 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003045 int err;
3046
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003047 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003048
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003049 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003050
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003051 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003052 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003053 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3054 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003055 goto unlock;
3056 }
3057
3058 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003059 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003060 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3061 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003062 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003063 }
3064
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003065 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003066 if (!cmd) {
3067 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003068 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003069 }
3070
Andre Guedes0e05bba2013-04-30 15:29:33 -03003071 hci_req_init(&req, hdev);
3072
Andre Guedese0d9727e2012-03-20 15:15:36 -03003073 switch (hdev->discovery.state) {
3074 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003075 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3076 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3077 } else {
3078 cancel_delayed_work(&hdev->le_scan_disable);
3079
3080 memset(&enable_cp, 0, sizeof(enable_cp));
3081 enable_cp.enable = LE_SCAN_DISABLE;
3082 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3083 sizeof(enable_cp), &enable_cp);
3084 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003085
Andre Guedese0d9727e2012-03-20 15:15:36 -03003086 break;
3087
3088 case DISCOVERY_RESOLVING:
3089 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003090 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003091 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003092 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003093 err = cmd_complete(sk, hdev->id,
3094 MGMT_OP_STOP_DISCOVERY, 0,
3095 &mgmt_cp->type,
3096 sizeof(mgmt_cp->type));
3097 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3098 goto unlock;
3099 }
3100
3101 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003102 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3103 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003104
3105 break;
3106
3107 default:
3108 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003109
3110 mgmt_pending_remove(cmd);
3111 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3112 MGMT_STATUS_FAILED, &mgmt_cp->type,
3113 sizeof(mgmt_cp->type));
3114 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003115 }
3116
Andre Guedes0e05bba2013-04-30 15:29:33 -03003117 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003118 if (err < 0)
3119 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003120 else
3121 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003122
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003123unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003124 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003125 return err;
3126}
3127
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003128static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003129 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003130{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003131 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003132 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003133 int err;
3134
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003135 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003136
Johan Hedberg561aafb2012-01-04 13:31:59 +02003137 hci_dev_lock(hdev);
3138
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003139 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003140 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003141 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003142 goto failed;
3143 }
3144
Johan Hedberga198e7b2012-02-17 14:27:06 +02003145 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003146 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003147 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003148 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003149 goto failed;
3150 }
3151
3152 if (cp->name_known) {
3153 e->name_state = NAME_KNOWN;
3154 list_del(&e->list);
3155 } else {
3156 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003157 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003158 }
3159
Johan Hedberge3846622013-01-09 15:29:33 +02003160 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3161 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003162
3163failed:
3164 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003165 return err;
3166}
3167
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003168static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003169 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003170{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003171 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003172 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003173 int err;
3174
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003175 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003176
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003177 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003178 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3179 MGMT_STATUS_INVALID_PARAMS,
3180 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003181
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003182 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003183
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003184 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003185 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003186 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003187 else
Szymon Janca6785be2012-12-13 15:11:21 +01003188 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003189
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003190 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003191 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003192
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003193 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003194
3195 return err;
3196}
3197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003198static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003199 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003200{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003201 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003202 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003203 int err;
3204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003205 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003206
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003207 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003208 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3209 MGMT_STATUS_INVALID_PARAMS,
3210 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003211
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003212 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003213
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003214 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003215 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003216 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003217 else
Szymon Janca6785be2012-12-13 15:11:21 +01003218 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003219
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003220 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003221 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003222
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003223 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003224
3225 return err;
3226}
3227
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003228static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3229 u16 len)
3230{
3231 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003232 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003233 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003234 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003235
3236 BT_DBG("%s", hdev->name);
3237
Szymon Jancc72d4b82012-03-16 16:02:57 +01003238 source = __le16_to_cpu(cp->source);
3239
3240 if (source > 0x0002)
3241 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3242 MGMT_STATUS_INVALID_PARAMS);
3243
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003244 hci_dev_lock(hdev);
3245
Szymon Jancc72d4b82012-03-16 16:02:57 +01003246 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003247 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3248 hdev->devid_product = __le16_to_cpu(cp->product);
3249 hdev->devid_version = __le16_to_cpu(cp->version);
3250
3251 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3252
Johan Hedberg890ea892013-03-15 17:06:52 -05003253 hci_req_init(&req, hdev);
3254 update_eir(&req);
3255 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003256
3257 hci_dev_unlock(hdev);
3258
3259 return err;
3260}
3261
Johan Hedberg4375f102013-09-25 13:26:10 +03003262static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3263{
3264 struct cmd_lookup match = { NULL, hdev };
3265
3266 if (status) {
3267 u8 mgmt_err = mgmt_status(status);
3268
3269 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3270 cmd_status_rsp, &mgmt_err);
3271 return;
3272 }
3273
3274 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3275 &match);
3276
3277 new_settings(hdev, match.sk);
3278
3279 if (match.sk)
3280 sock_put(match.sk);
3281}
3282
Marcel Holtmann21b51872013-10-10 09:47:53 -07003283static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3284 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003285{
3286 struct mgmt_mode *cp = data;
3287 struct pending_cmd *cmd;
3288 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003289 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003290 int err;
3291
3292 BT_DBG("request for %s", hdev->name);
3293
Johan Hedberge6fe7982013-10-02 15:45:22 +03003294 status = mgmt_le_support(hdev);
3295 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003296 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003297 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003298
3299 if (cp->val != 0x00 && cp->val != 0x01)
3300 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3301 MGMT_STATUS_INVALID_PARAMS);
3302
3303 hci_dev_lock(hdev);
3304
3305 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003306 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003307
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003308 /* The following conditions are ones which mean that we should
3309 * not do any HCI communication but directly send a mgmt
3310 * response to user space (after toggling the flag if
3311 * necessary).
3312 */
3313 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003314 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003315 bool changed = false;
3316
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003317 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3318 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003319 changed = true;
3320 }
3321
3322 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3323 if (err < 0)
3324 goto unlock;
3325
3326 if (changed)
3327 err = new_settings(hdev, sk);
3328
3329 goto unlock;
3330 }
3331
3332 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3333 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3334 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3335 MGMT_STATUS_BUSY);
3336 goto unlock;
3337 }
3338
3339 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3340 if (!cmd) {
3341 err = -ENOMEM;
3342 goto unlock;
3343 }
3344
3345 hci_req_init(&req, hdev);
3346
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003347 if (val)
3348 enable_advertising(&req);
3349 else
3350 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003351
3352 err = hci_req_run(&req, set_advertising_complete);
3353 if (err < 0)
3354 mgmt_pending_remove(cmd);
3355
3356unlock:
3357 hci_dev_unlock(hdev);
3358 return err;
3359}
3360
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003361static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3362 void *data, u16 len)
3363{
3364 struct mgmt_cp_set_static_address *cp = data;
3365 int err;
3366
3367 BT_DBG("%s", hdev->name);
3368
Marcel Holtmann62af4442013-10-02 22:10:32 -07003369 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003370 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003371 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003372
3373 if (hdev_is_powered(hdev))
3374 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3375 MGMT_STATUS_REJECTED);
3376
3377 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3378 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3379 return cmd_status(sk, hdev->id,
3380 MGMT_OP_SET_STATIC_ADDRESS,
3381 MGMT_STATUS_INVALID_PARAMS);
3382
3383 /* Two most significant bits shall be set */
3384 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3385 return cmd_status(sk, hdev->id,
3386 MGMT_OP_SET_STATIC_ADDRESS,
3387 MGMT_STATUS_INVALID_PARAMS);
3388 }
3389
3390 hci_dev_lock(hdev);
3391
3392 bacpy(&hdev->static_addr, &cp->bdaddr);
3393
3394 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3395
3396 hci_dev_unlock(hdev);
3397
3398 return err;
3399}
3400
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003401static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3402 void *data, u16 len)
3403{
3404 struct mgmt_cp_set_scan_params *cp = data;
3405 __u16 interval, window;
3406 int err;
3407
3408 BT_DBG("%s", hdev->name);
3409
3410 if (!lmp_le_capable(hdev))
3411 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3412 MGMT_STATUS_NOT_SUPPORTED);
3413
3414 interval = __le16_to_cpu(cp->interval);
3415
3416 if (interval < 0x0004 || interval > 0x4000)
3417 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3418 MGMT_STATUS_INVALID_PARAMS);
3419
3420 window = __le16_to_cpu(cp->window);
3421
3422 if (window < 0x0004 || window > 0x4000)
3423 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3424 MGMT_STATUS_INVALID_PARAMS);
3425
3426 hci_dev_lock(hdev);
3427
3428 hdev->le_scan_interval = interval;
3429 hdev->le_scan_window = window;
3430
3431 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3432
3433 hci_dev_unlock(hdev);
3434
3435 return err;
3436}
3437
Johan Hedberg33e38b32013-03-15 17:07:05 -05003438static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3439{
3440 struct pending_cmd *cmd;
3441
3442 BT_DBG("status 0x%02x", status);
3443
3444 hci_dev_lock(hdev);
3445
3446 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3447 if (!cmd)
3448 goto unlock;
3449
3450 if (status) {
3451 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3452 mgmt_status(status));
3453 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003454 struct mgmt_mode *cp = cmd->param;
3455
3456 if (cp->val)
3457 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3458 else
3459 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3460
Johan Hedberg33e38b32013-03-15 17:07:05 -05003461 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3462 new_settings(hdev, cmd->sk);
3463 }
3464
3465 mgmt_pending_remove(cmd);
3466
3467unlock:
3468 hci_dev_unlock(hdev);
3469}
3470
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003471static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003472 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003473{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003474 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003475 struct pending_cmd *cmd;
3476 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003477 int err;
3478
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003479 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003480
Johan Hedberg56f87902013-10-02 13:43:13 +03003481 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3482 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003483 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3484 MGMT_STATUS_NOT_SUPPORTED);
3485
Johan Hedberga7e80f22013-01-09 16:05:19 +02003486 if (cp->val != 0x00 && cp->val != 0x01)
3487 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3488 MGMT_STATUS_INVALID_PARAMS);
3489
Johan Hedberg5400c042012-02-21 16:40:33 +02003490 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003491 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003492 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003493
3494 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003495 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003496 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003497
3498 hci_dev_lock(hdev);
3499
Johan Hedberg05cbf292013-03-15 17:07:07 -05003500 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3501 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3502 MGMT_STATUS_BUSY);
3503 goto unlock;
3504 }
3505
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003506 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3507 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3508 hdev);
3509 goto unlock;
3510 }
3511
Johan Hedberg33e38b32013-03-15 17:07:05 -05003512 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3513 data, len);
3514 if (!cmd) {
3515 err = -ENOMEM;
3516 goto unlock;
3517 }
3518
3519 hci_req_init(&req, hdev);
3520
Johan Hedberg406d7802013-03-15 17:07:09 -05003521 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003522
3523 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003524 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003525 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003526 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003527 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003528 }
3529
Johan Hedberg33e38b32013-03-15 17:07:05 -05003530unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003531 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003532
Antti Julkuf6422ec2011-06-22 13:11:56 +03003533 return err;
3534}
3535
Johan Hedberg0663ca22013-10-02 13:43:14 +03003536static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3537{
3538 struct pending_cmd *cmd;
3539
3540 BT_DBG("status 0x%02x", status);
3541
3542 hci_dev_lock(hdev);
3543
3544 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3545 if (!cmd)
3546 goto unlock;
3547
3548 if (status) {
3549 u8 mgmt_err = mgmt_status(status);
3550
3551 /* We need to restore the flag if related HCI commands
3552 * failed.
3553 */
3554 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3555
3556 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3557 } else {
3558 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3559 new_settings(hdev, cmd->sk);
3560 }
3561
3562 mgmt_pending_remove(cmd);
3563
3564unlock:
3565 hci_dev_unlock(hdev);
3566}
3567
3568static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3569{
3570 struct mgmt_mode *cp = data;
3571 struct pending_cmd *cmd;
3572 struct hci_request req;
3573 int err;
3574
3575 BT_DBG("request for %s", hdev->name);
3576
3577 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3578 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3579 MGMT_STATUS_NOT_SUPPORTED);
3580
3581 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3582 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3583 MGMT_STATUS_REJECTED);
3584
3585 if (cp->val != 0x00 && cp->val != 0x01)
3586 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3587 MGMT_STATUS_INVALID_PARAMS);
3588
3589 hci_dev_lock(hdev);
3590
3591 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3592 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3593 goto unlock;
3594 }
3595
3596 if (!hdev_is_powered(hdev)) {
3597 if (!cp->val) {
3598 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3599 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3600 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3601 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3602 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3603 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3604 }
3605
3606 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3607
3608 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3609 if (err < 0)
3610 goto unlock;
3611
3612 err = new_settings(hdev, sk);
3613 goto unlock;
3614 }
3615
3616 /* Reject disabling when powered on */
3617 if (!cp->val) {
3618 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3619 MGMT_STATUS_REJECTED);
3620 goto unlock;
3621 }
3622
3623 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3624 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3625 MGMT_STATUS_BUSY);
3626 goto unlock;
3627 }
3628
3629 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3630 if (!cmd) {
3631 err = -ENOMEM;
3632 goto unlock;
3633 }
3634
3635 /* We need to flip the bit already here so that hci_update_ad
3636 * generates the correct flags.
3637 */
3638 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3639
3640 hci_req_init(&req, hdev);
3641 hci_update_ad(&req);
3642 err = hci_req_run(&req, set_bredr_complete);
3643 if (err < 0)
3644 mgmt_pending_remove(cmd);
3645
3646unlock:
3647 hci_dev_unlock(hdev);
3648 return err;
3649}
3650
Johan Hedberg3f706b72013-01-20 14:27:16 +02003651static bool ltk_is_valid(struct mgmt_ltk_info *key)
3652{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003653 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3654 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003655 if (key->master != 0x00 && key->master != 0x01)
3656 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003657 if (!bdaddr_type_is_le(key->addr.type))
3658 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003659 return true;
3660}
3661
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003662static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003663 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003664{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003665 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3666 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003667 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003668
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003669 BT_DBG("request for %s", hdev->name);
3670
3671 if (!lmp_le_capable(hdev))
3672 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3673 MGMT_STATUS_NOT_SUPPORTED);
3674
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003675 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003676
3677 expected_len = sizeof(*cp) + key_count *
3678 sizeof(struct mgmt_ltk_info);
3679 if (expected_len != len) {
3680 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003681 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003682 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003683 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003684 }
3685
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003686 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003687
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003688 for (i = 0; i < key_count; i++) {
3689 struct mgmt_ltk_info *key = &cp->keys[i];
3690
Johan Hedberg3f706b72013-01-20 14:27:16 +02003691 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003692 return cmd_status(sk, hdev->id,
3693 MGMT_OP_LOAD_LONG_TERM_KEYS,
3694 MGMT_STATUS_INVALID_PARAMS);
3695 }
3696
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003697 hci_dev_lock(hdev);
3698
3699 hci_smp_ltks_clear(hdev);
3700
3701 for (i = 0; i < key_count; i++) {
3702 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003703 u8 type, addr_type;
3704
3705 if (key->addr.type == BDADDR_LE_PUBLIC)
3706 addr_type = ADDR_LE_DEV_PUBLIC;
3707 else
3708 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003709
3710 if (key->master)
3711 type = HCI_SMP_LTK;
3712 else
3713 type = HCI_SMP_LTK_SLAVE;
3714
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003715 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003716 type, 0, key->authenticated, key->val,
3717 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003718 }
3719
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003720 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3721 NULL, 0);
3722
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003723 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003724
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003725 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003726}
3727
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003728static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003729 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3730 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003731 bool var_len;
3732 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003733} mgmt_handlers[] = {
3734 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003735 { read_version, false, MGMT_READ_VERSION_SIZE },
3736 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3737 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3738 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3739 { set_powered, false, MGMT_SETTING_SIZE },
3740 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3741 { set_connectable, false, MGMT_SETTING_SIZE },
3742 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3743 { set_pairable, false, MGMT_SETTING_SIZE },
3744 { set_link_security, false, MGMT_SETTING_SIZE },
3745 { set_ssp, false, MGMT_SETTING_SIZE },
3746 { set_hs, false, MGMT_SETTING_SIZE },
3747 { set_le, false, MGMT_SETTING_SIZE },
3748 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3749 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3750 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3751 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3752 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3753 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3754 { disconnect, false, MGMT_DISCONNECT_SIZE },
3755 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3756 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3757 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3758 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3759 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3760 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3761 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3762 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3763 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3764 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3765 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3766 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3767 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3768 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3769 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3770 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3771 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3772 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3773 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003774 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003775 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003776 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003777 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003778 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003779};
3780
3781
Johan Hedberg03811012010-12-08 00:21:06 +02003782int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3783{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003784 void *buf;
3785 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003786 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003787 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003788 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003789 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003790 int err;
3791
3792 BT_DBG("got %zu bytes", msglen);
3793
3794 if (msglen < sizeof(*hdr))
3795 return -EINVAL;
3796
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003797 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003798 if (!buf)
3799 return -ENOMEM;
3800
3801 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3802 err = -EFAULT;
3803 goto done;
3804 }
3805
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003806 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003807 opcode = __le16_to_cpu(hdr->opcode);
3808 index = __le16_to_cpu(hdr->index);
3809 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003810
3811 if (len != msglen - sizeof(*hdr)) {
3812 err = -EINVAL;
3813 goto done;
3814 }
3815
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003816 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003817 hdev = hci_dev_get(index);
3818 if (!hdev) {
3819 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003820 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003821 goto done;
3822 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003823
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02003824 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
3825 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003826 err = cmd_status(sk, index, opcode,
3827 MGMT_STATUS_INVALID_INDEX);
3828 goto done;
3829 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003830 }
3831
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003832 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003833 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003834 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003835 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003836 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003837 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003838 }
3839
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003840 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003841 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003842 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003843 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003844 goto done;
3845 }
3846
Johan Hedbergbe22b542012-03-01 22:24:41 +02003847 handler = &mgmt_handlers[opcode];
3848
3849 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003850 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003851 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003852 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003853 goto done;
3854 }
3855
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003856 if (hdev)
3857 mgmt_init_hdev(sk, hdev);
3858
3859 cp = buf + sizeof(*hdr);
3860
Johan Hedbergbe22b542012-03-01 22:24:41 +02003861 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003862 if (err < 0)
3863 goto done;
3864
Johan Hedberg03811012010-12-08 00:21:06 +02003865 err = msglen;
3866
3867done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003868 if (hdev)
3869 hci_dev_put(hdev);
3870
Johan Hedberg03811012010-12-08 00:21:06 +02003871 kfree(buf);
3872 return err;
3873}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003874
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003875void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003876{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003877 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003878 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003879
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003880 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003881}
3882
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003883void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003884{
Johan Hedberg5f159032012-03-02 03:13:19 +02003885 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003886
Marcel Holtmann1514b892013-10-06 08:25:01 -07003887 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003888 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003889
Johan Hedberg744cf192011-11-08 20:40:14 +02003890 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003891
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003892 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003893}
3894
Johan Hedberg890ea892013-03-15 17:06:52 -05003895static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003896{
Johan Hedberg890ea892013-03-15 17:06:52 -05003897 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003898 u8 scan = 0;
3899
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003900 /* Ensure that fast connectable is disabled. This function will
3901 * not do anything if the page scan parameters are already what
3902 * they should be.
3903 */
3904 write_fast_connectable(req, false);
3905
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003906 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3907 scan |= SCAN_PAGE;
3908 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3909 scan |= SCAN_INQUIRY;
3910
Johan Hedberg890ea892013-03-15 17:06:52 -05003911 if (scan)
3912 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003913}
3914
Johan Hedberg229ab392013-03-15 17:06:53 -05003915static void powered_complete(struct hci_dev *hdev, u8 status)
3916{
3917 struct cmd_lookup match = { NULL, hdev };
3918
3919 BT_DBG("status 0x%02x", status);
3920
3921 hci_dev_lock(hdev);
3922
3923 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3924
3925 new_settings(hdev, match.sk);
3926
3927 hci_dev_unlock(hdev);
3928
3929 if (match.sk)
3930 sock_put(match.sk);
3931}
3932
Johan Hedberg70da6242013-03-15 17:06:51 -05003933static int powered_update_hci(struct hci_dev *hdev)
3934{
Johan Hedberg890ea892013-03-15 17:06:52 -05003935 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003936 u8 link_sec;
3937
Johan Hedberg890ea892013-03-15 17:06:52 -05003938 hci_req_init(&req, hdev);
3939
Johan Hedberg70da6242013-03-15 17:06:51 -05003940 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3941 !lmp_host_ssp_capable(hdev)) {
3942 u8 ssp = 1;
3943
Johan Hedberg890ea892013-03-15 17:06:52 -05003944 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003945 }
3946
Johan Hedbergc73eee92013-04-19 18:35:21 +03003947 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3948 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003949 struct hci_cp_write_le_host_supported cp;
3950
3951 cp.le = 1;
3952 cp.simul = lmp_le_br_capable(hdev);
3953
3954 /* Check first if we already have the right
3955 * host state (host features set)
3956 */
3957 if (cp.le != lmp_host_le_capable(hdev) ||
3958 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003959 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3960 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003961
3962 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3963 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003964 }
3965
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003966 if (lmp_le_capable(hdev)) {
3967 /* Set random address to static address if configured */
3968 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3969 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3970 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003971
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003972 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3973 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003974 }
3975
Johan Hedberg70da6242013-03-15 17:06:51 -05003976 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3977 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003978 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3979 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003980
3981 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003982 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3983 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003984 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003985 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003986 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003987 }
3988
Johan Hedberg229ab392013-03-15 17:06:53 -05003989 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003990}
3991
Johan Hedberg744cf192011-11-08 20:40:14 +02003992int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003993{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003994 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003995 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3996 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003997 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003998
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003999 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4000 return 0;
4001
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004002 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004003 if (powered_update_hci(hdev) == 0)
4004 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004005
Johan Hedberg229ab392013-03-15 17:06:53 -05004006 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4007 &match);
4008 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004009 }
4010
Johan Hedberg229ab392013-03-15 17:06:53 -05004011 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4012 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4013
4014 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4015 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4016 zero_cod, sizeof(zero_cod), NULL);
4017
4018new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004019 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004020
4021 if (match.sk)
4022 sock_put(match.sk);
4023
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004024 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004025}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004026
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004027void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004028{
4029 struct pending_cmd *cmd;
4030 u8 status;
4031
4032 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4033 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004034 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004035
4036 if (err == -ERFKILL)
4037 status = MGMT_STATUS_RFKILLED;
4038 else
4039 status = MGMT_STATUS_FAILED;
4040
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004041 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004042
4043 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004044}
4045
Johan Hedberg744cf192011-11-08 20:40:14 +02004046int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004047{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004048 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004049 bool changed = false;
4050 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004051
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004052 if (discoverable) {
4053 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4054 changed = true;
4055 } else {
4056 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4057 changed = true;
4058 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004059
Johan Hedberged9b5f22012-02-21 20:47:06 +02004060 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004061 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004062
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004063 if (changed)
4064 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004065
Johan Hedberg73f22f62010-12-29 16:00:25 +02004066 if (match.sk)
4067 sock_put(match.sk);
4068
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004069 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004070}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004071
Johan Hedberg744cf192011-11-08 20:40:14 +02004072int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004073{
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004074 bool changed = false;
4075 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004076
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004077 /* Nothing needed here if there's a pending command since that
4078 * commands request completion callback takes care of everything
4079 * necessary.
4080 */
4081 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
4082 return 0;
4083
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004084 if (connectable) {
4085 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4086 changed = true;
4087 } else {
4088 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4089 changed = true;
4090 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004091
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004092 if (changed)
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004093 err = new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004094
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004095 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004096}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004097
Johan Hedberg744cf192011-11-08 20:40:14 +02004098int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004099{
Johan Hedbergca69b792011-11-11 18:10:00 +02004100 u8 mgmt_err = mgmt_status(status);
4101
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004102 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004103 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004104 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004105
4106 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004107 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004108 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004109
4110 return 0;
4111}
4112
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004113int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4114 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004115{
Johan Hedberg86742e12011-11-07 23:13:38 +02004116 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004117
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004118 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004119
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004120 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004121 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004122 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004123 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004124 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004125 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004126
Johan Hedberg744cf192011-11-08 20:40:14 +02004127 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004128}
Johan Hedbergf7520542011-01-20 12:34:39 +02004129
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004130int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4131{
4132 struct mgmt_ev_new_long_term_key ev;
4133
4134 memset(&ev, 0, sizeof(ev));
4135
4136 ev.store_hint = persistent;
4137 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004138 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004139 ev.key.authenticated = key->authenticated;
4140 ev.key.enc_size = key->enc_size;
4141 ev.key.ediv = key->ediv;
4142
4143 if (key->type == HCI_SMP_LTK)
4144 ev.key.master = 1;
4145
4146 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4147 memcpy(ev.key.val, key->val, sizeof(key->val));
4148
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004149 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4150 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004151}
4152
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004153void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4154 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4155 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004156{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004157 char buf[512];
4158 struct mgmt_ev_device_connected *ev = (void *) buf;
4159 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004160
Johan Hedbergb644ba32012-01-17 21:48:47 +02004161 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004162 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004163
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004164 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004165
Johan Hedbergb644ba32012-01-17 21:48:47 +02004166 if (name_len > 0)
4167 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004168 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004169
4170 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004171 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004172 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004173
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004174 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004175
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004176 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4177 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004178}
4179
Johan Hedberg8962ee72011-01-20 12:40:27 +02004180static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4181{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004182 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004183 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004184 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004185
Johan Hedberg88c3df12012-02-09 14:27:38 +02004186 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4187 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004188
Johan Hedbergaee9b212012-02-18 15:07:59 +02004189 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004190 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004191
4192 *sk = cmd->sk;
4193 sock_hold(*sk);
4194
Johan Hedberga664b5b2011-02-19 12:06:02 -03004195 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004196}
4197
Johan Hedberg124f6e32012-02-09 13:50:12 +02004198static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004199{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004200 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004201 struct mgmt_cp_unpair_device *cp = cmd->param;
4202 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004203
4204 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004205 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4206 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004207
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004208 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4209
Johan Hedbergaee9b212012-02-18 15:07:59 +02004210 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004211
4212 mgmt_pending_remove(cmd);
4213}
4214
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004215void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4216 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004217{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004218 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004219 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004220
Johan Hedberg744cf192011-11-08 20:40:14 +02004221 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004222
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004223 bacpy(&ev.addr.bdaddr, bdaddr);
4224 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4225 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004226
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004227 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004228
4229 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004230 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004231
Johan Hedberg124f6e32012-02-09 13:50:12 +02004232 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004233 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004234}
4235
Marcel Holtmann78929242013-10-06 23:55:47 -07004236void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4237 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004238{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004239 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004240 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004241
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004242 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4243 hdev);
4244
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004245 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004246 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004247 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004248
Johan Hedberg88c3df12012-02-09 14:27:38 +02004249 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004250 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004251
Marcel Holtmann78929242013-10-06 23:55:47 -07004252 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4253 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004254
Johan Hedberga664b5b2011-02-19 12:06:02 -03004255 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004256}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004257
Marcel Holtmann445608d2013-10-06 23:55:48 -07004258void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4259 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004260{
4261 struct mgmt_ev_connect_failed ev;
4262
Johan Hedberg4c659c32011-11-07 23:13:39 +02004263 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004264 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004265 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004266
Marcel Holtmann445608d2013-10-06 23:55:48 -07004267 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004268}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004269
Johan Hedberg744cf192011-11-08 20:40:14 +02004270int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004271{
4272 struct mgmt_ev_pin_code_request ev;
4273
Johan Hedbergd8457692012-02-17 14:24:57 +02004274 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004275 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004276 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004277
Johan Hedberg744cf192011-11-08 20:40:14 +02004278 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004279 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004280}
4281
Johan Hedberg744cf192011-11-08 20:40:14 +02004282int mgmt_pin_code_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_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_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}
4303
Johan Hedberg744cf192011-11-08 20:40:14 +02004304int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004305 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004306{
4307 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004308 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004309 int err;
4310
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004311 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004312 if (!cmd)
4313 return -ENOENT;
4314
Johan Hedbergd8457692012-02-17 14:24:57 +02004315 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004316 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004317
Johan Hedbergaee9b212012-02-18 15:07:59 +02004318 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004319 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004320
Johan Hedberga664b5b2011-02-19 12:06:02 -03004321 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004322
4323 return err;
4324}
Johan Hedberga5c29682011-02-19 12:05:57 -03004325
Johan Hedberg744cf192011-11-08 20:40:14 +02004326int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004327 u8 link_type, u8 addr_type, __le32 value,
4328 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004329{
4330 struct mgmt_ev_user_confirm_request ev;
4331
Johan Hedberg744cf192011-11-08 20:40:14 +02004332 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004333
Johan Hedberg272d90d2012-02-09 15:26:12 +02004334 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004335 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004336 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004337 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004338
Johan Hedberg744cf192011-11-08 20:40:14 +02004339 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004340 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004341}
4342
Johan Hedberg272d90d2012-02-09 15:26:12 +02004343int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004344 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004345{
4346 struct mgmt_ev_user_passkey_request ev;
4347
4348 BT_DBG("%s", hdev->name);
4349
Johan Hedberg272d90d2012-02-09 15:26:12 +02004350 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004351 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004352
4353 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004354 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004355}
4356
Brian Gix0df4c182011-11-16 13:53:13 -08004357static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004358 u8 link_type, u8 addr_type, u8 status,
4359 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004360{
4361 struct pending_cmd *cmd;
4362 struct mgmt_rp_user_confirm_reply rp;
4363 int err;
4364
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004365 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004366 if (!cmd)
4367 return -ENOENT;
4368
Johan Hedberg272d90d2012-02-09 15:26:12 +02004369 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004370 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004371 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004372 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004373
Johan Hedberga664b5b2011-02-19 12:06:02 -03004374 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004375
4376 return err;
4377}
4378
Johan Hedberg744cf192011-11-08 20:40:14 +02004379int mgmt_user_confirm_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)
Johan Hedberga5c29682011-02-19 12:05:57 -03004381{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004382 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004383 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004384}
4385
Johan Hedberg272d90d2012-02-09 15:26:12 +02004386int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004387 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004388{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004389 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004390 status,
4391 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004392}
Johan Hedberg2a611692011-02-19 12:06:00 -03004393
Brian Gix604086b2011-11-23 08:28:33 -08004394int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004395 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004396{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004397 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004398 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004399}
4400
Johan Hedberg272d90d2012-02-09 15:26:12 +02004401int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004402 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004403{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004404 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004405 status,
4406 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004407}
4408
Johan Hedberg92a25252012-09-06 18:39:26 +03004409int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4410 u8 link_type, u8 addr_type, u32 passkey,
4411 u8 entered)
4412{
4413 struct mgmt_ev_passkey_notify ev;
4414
4415 BT_DBG("%s", hdev->name);
4416
4417 bacpy(&ev.addr.bdaddr, bdaddr);
4418 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4419 ev.passkey = __cpu_to_le32(passkey);
4420 ev.entered = entered;
4421
4422 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4423}
4424
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004425int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004426 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004427{
4428 struct mgmt_ev_auth_failed ev;
4429
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004430 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004431 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004432 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004433
Johan Hedberg744cf192011-11-08 20:40:14 +02004434 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004435}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004436
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004437int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4438{
4439 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004440 bool changed = false;
4441 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004442
4443 if (status) {
4444 u8 mgmt_err = mgmt_status(status);
4445 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004446 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004447 return 0;
4448 }
4449
Johan Hedberg47990ea2012-02-22 11:58:37 +02004450 if (test_bit(HCI_AUTH, &hdev->flags)) {
4451 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4452 changed = true;
4453 } else {
4454 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4455 changed = true;
4456 }
4457
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004458 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004459 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004460
Johan Hedberg47990ea2012-02-22 11:58:37 +02004461 if (changed)
4462 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004463
4464 if (match.sk)
4465 sock_put(match.sk);
4466
4467 return err;
4468}
4469
Johan Hedberg890ea892013-03-15 17:06:52 -05004470static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004471{
Johan Hedberg890ea892013-03-15 17:06:52 -05004472 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004473 struct hci_cp_write_eir cp;
4474
Johan Hedberg976eb202012-10-24 21:12:01 +03004475 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004476 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004477
Johan Hedbergc80da272012-02-22 15:38:48 +02004478 memset(hdev->eir, 0, sizeof(hdev->eir));
4479
Johan Hedbergcacaf522012-02-21 00:52:42 +02004480 memset(&cp, 0, sizeof(cp));
4481
Johan Hedberg890ea892013-03-15 17:06:52 -05004482 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004483}
4484
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004485int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004486{
4487 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004488 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004489 bool changed = false;
4490 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004491
4492 if (status) {
4493 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004494
4495 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004496 &hdev->dev_flags)) {
4497 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004498 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004499 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004500
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004501 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4502 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004503
4504 return err;
4505 }
4506
4507 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004508 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004509 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004510 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4511 if (!changed)
4512 changed = test_and_clear_bit(HCI_HS_ENABLED,
4513 &hdev->dev_flags);
4514 else
4515 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004516 }
4517
4518 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4519
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004520 if (changed)
4521 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004522
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004523 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004524 sock_put(match.sk);
4525
Johan Hedberg890ea892013-03-15 17:06:52 -05004526 hci_req_init(&req, hdev);
4527
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004528 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004529 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004530 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004531 clear_eir(&req);
4532
4533 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004534
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004535 return err;
4536}
4537
Johan Hedberg92da6092013-03-15 17:06:55 -05004538static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004539{
4540 struct cmd_lookup *match = data;
4541
Johan Hedberg90e70452012-02-23 23:09:40 +02004542 if (match->sk == NULL) {
4543 match->sk = cmd->sk;
4544 sock_hold(match->sk);
4545 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004546}
4547
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004548int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004549 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004550{
Johan Hedberg90e70452012-02-23 23:09:40 +02004551 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4552 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004553
Johan Hedberg92da6092013-03-15 17:06:55 -05004554 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4555 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4556 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004557
4558 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004559 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4560 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004561
4562 if (match.sk)
4563 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004564
4565 return err;
4566}
4567
Johan Hedberg744cf192011-11-08 20:40:14 +02004568int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004569{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004570 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004571 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004572
Johan Hedberg13928972013-03-15 17:07:00 -05004573 if (status)
4574 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004575
4576 memset(&ev, 0, sizeof(ev));
4577 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004578 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004579
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004580 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004581 if (!cmd) {
4582 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004583
Johan Hedberg13928972013-03-15 17:07:00 -05004584 /* If this is a HCI command related to powering on the
4585 * HCI dev don't send any mgmt signals.
4586 */
4587 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4588 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004589 }
4590
Johan Hedberg13928972013-03-15 17:07:00 -05004591 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4592 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004593}
Szymon Jancc35938b2011-03-22 13:12:21 +01004594
Johan Hedberg744cf192011-11-08 20:40:14 +02004595int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004596 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004597{
4598 struct pending_cmd *cmd;
4599 int err;
4600
Johan Hedberg744cf192011-11-08 20:40:14 +02004601 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004602
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004603 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004604 if (!cmd)
4605 return -ENOENT;
4606
4607 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004608 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4609 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004610 } else {
4611 struct mgmt_rp_read_local_oob_data rp;
4612
4613 memcpy(rp.hash, hash, sizeof(rp.hash));
4614 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4615
Johan Hedberg744cf192011-11-08 20:40:14 +02004616 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004617 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4618 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004619 }
4620
4621 mgmt_pending_remove(cmd);
4622
4623 return err;
4624}
Johan Hedberge17acd42011-03-30 23:57:16 +03004625
Marcel Holtmann901801b2013-10-06 23:55:51 -07004626void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4627 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4628 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004629{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004630 char buf[512];
4631 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004632 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004633
Andre Guedes12602d02013-04-30 15:29:40 -03004634 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004635 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004636
Johan Hedberg1dc06092012-01-15 21:01:23 +02004637 /* Leave 5 bytes for a potential CoD field */
4638 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004639 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004640
Johan Hedberg1dc06092012-01-15 21:01:23 +02004641 memset(buf, 0, sizeof(buf));
4642
Johan Hedberge319d2e2012-01-15 19:51:59 +02004643 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004644 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004645 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004646 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304647 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004648 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304649 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004650
Johan Hedberg1dc06092012-01-15 21:01:23 +02004651 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004652 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004653
Johan Hedberg1dc06092012-01-15 21:01:23 +02004654 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4655 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004656 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004657
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004658 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004659 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004660
Marcel Holtmann901801b2013-10-06 23:55:51 -07004661 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004662}
Johan Hedberga88a9652011-03-30 13:18:12 +03004663
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004664void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4665 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004666{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004667 struct mgmt_ev_device_found *ev;
4668 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4669 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004670
Johan Hedbergb644ba32012-01-17 21:48:47 +02004671 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004672
Johan Hedbergb644ba32012-01-17 21:48:47 +02004673 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004674
Johan Hedbergb644ba32012-01-17 21:48:47 +02004675 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004676 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004677 ev->rssi = rssi;
4678
4679 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004680 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004681
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004682 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004683
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004684 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004685}
Johan Hedberg314b2382011-04-27 10:29:57 -04004686
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004687void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004688{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004689 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004690 struct pending_cmd *cmd;
4691
Andre Guedes343fb142011-11-22 17:14:19 -03004692 BT_DBG("%s discovering %u", hdev->name, discovering);
4693
Johan Hedberg164a6e72011-11-01 17:06:44 +02004694 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004695 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004696 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004697 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004698
4699 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004700 u8 type = hdev->discovery.type;
4701
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004702 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4703 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004704 mgmt_pending_remove(cmd);
4705 }
4706
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004707 memset(&ev, 0, sizeof(ev));
4708 ev.type = hdev->discovery.type;
4709 ev.discovering = discovering;
4710
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004711 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004712}
Antti Julku5e762442011-08-25 16:48:02 +03004713
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004714int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004715{
4716 struct pending_cmd *cmd;
4717 struct mgmt_ev_device_blocked ev;
4718
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004719 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004720
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004721 bacpy(&ev.addr.bdaddr, bdaddr);
4722 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004723
Johan Hedberg744cf192011-11-08 20:40:14 +02004724 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004725 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004726}
4727
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004728int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004729{
4730 struct pending_cmd *cmd;
4731 struct mgmt_ev_device_unblocked ev;
4732
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004733 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004734
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004735 bacpy(&ev.addr.bdaddr, bdaddr);
4736 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004737
Johan Hedberg744cf192011-11-08 20:40:14 +02004738 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004739 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004740}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004741
4742static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4743{
4744 BT_DBG("%s status %u", hdev->name, status);
4745
4746 /* Clear the advertising mgmt setting if we failed to re-enable it */
4747 if (status) {
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}
4752
4753void mgmt_reenable_advertising(struct hci_dev *hdev)
4754{
4755 struct hci_request req;
4756
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004757 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004758 return;
4759
4760 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4761 return;
4762
4763 hci_req_init(&req, hdev);
4764 enable_advertising(&req);
4765
4766 /* If this fails we have no option but to let user space know
4767 * that we've disabled advertising.
4768 */
4769 if (hci_req_run(&req, adv_enable_complete) < 0) {
4770 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004771 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004772 }
4773}