blob: 8dcea7726f8d68ae1de5a1dc7b145ef7bbe1047f [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 Hedbergd7b856f2013-10-14 16:20:04 +03001089 cp = cmd->param;
1090 if (cp->val)
1091 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1092 else
1093 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1094
Johan Hedberg2b76f452013-03-15 17:07:04 -05001095 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1096
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001097 if (changed)
1098 new_settings(hdev, cmd->sk);
1099
Johan Hedberg2b76f452013-03-15 17:07:04 -05001100 mgmt_pending_remove(cmd);
1101
1102unlock:
1103 hci_dev_unlock(hdev);
1104}
1105
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001106static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001107 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001108{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001109 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001110 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001111 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001112 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001113 int err;
1114
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001115 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001116
Johan Hedberge6fe7982013-10-02 15:45:22 +03001117 status = mgmt_bredr_support(hdev);
1118 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001119 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001120 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001121
Johan Hedberga7e80f22013-01-09 16:05:19 +02001122 if (cp->val != 0x00 && cp->val != 0x01)
1123 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1124 MGMT_STATUS_INVALID_PARAMS);
1125
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001126 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001127
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001128 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001129 bool changed = false;
1130
1131 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1132 changed = true;
1133
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001134 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001135 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001136 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001137 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1138 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1139 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001140
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001141 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001142 if (err < 0)
1143 goto failed;
1144
1145 if (changed)
1146 err = new_settings(hdev, sk);
1147
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001148 goto failed;
1149 }
1150
1151 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001152 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001153 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001154 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001155 goto failed;
1156 }
1157
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001158 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1159 if (!cmd) {
1160 err = -ENOMEM;
1161 goto failed;
1162 }
1163
Johan Hedberg2b76f452013-03-15 17:07:04 -05001164 hci_req_init(&req, hdev);
1165
Johan Hedberg9b742462013-10-14 16:20:03 +03001166 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1167 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
1168
1169 if (cp->val) {
1170 scan = SCAN_PAGE;
1171 } else {
1172 scan = 0;
1173
1174 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1175 hdev->discov_timeout > 0)
1176 cancel_delayed_work(&hdev->discov_off);
1177 }
1178
1179 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1180 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001181
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001182 /* If we're going from non-connectable to connectable or
1183 * vice-versa when fast connectable is enabled ensure that fast
1184 * connectable gets disabled. write_fast_connectable won't do
1185 * anything if the page scan parameters are already what they
1186 * should be.
1187 */
1188 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001189 write_fast_connectable(&req, false);
1190
Johan Hedberg2b76f452013-03-15 17:07:04 -05001191 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001192 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001193 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001194 if (err == -ENODATA)
1195 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1196 hdev);
1197 goto failed;
1198 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001199
1200failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001201 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001202 return err;
1203}
1204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001205static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001206 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001207{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001208 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001209 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001210 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001211
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001212 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001213
Johan Hedberga7e80f22013-01-09 16:05:19 +02001214 if (cp->val != 0x00 && cp->val != 0x01)
1215 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1216 MGMT_STATUS_INVALID_PARAMS);
1217
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001218 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001219
1220 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001221 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001222 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001223 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001224
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001225 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001226 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001227 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001228
Marcel Holtmann55594352013-10-06 16:11:57 -07001229 if (changed)
1230 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001231
Marcel Holtmann55594352013-10-06 16:11:57 -07001232unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001233 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001234 return err;
1235}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001236
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001237static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1238 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001239{
1240 struct mgmt_mode *cp = data;
1241 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001242 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001243 int err;
1244
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001245 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001246
Johan Hedberge6fe7982013-10-02 15:45:22 +03001247 status = mgmt_bredr_support(hdev);
1248 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001249 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001250 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001251
Johan Hedberga7e80f22013-01-09 16:05:19 +02001252 if (cp->val != 0x00 && cp->val != 0x01)
1253 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1254 MGMT_STATUS_INVALID_PARAMS);
1255
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001256 hci_dev_lock(hdev);
1257
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001258 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001259 bool changed = false;
1260
1261 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001262 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001263 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1264 changed = true;
1265 }
1266
1267 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1268 if (err < 0)
1269 goto failed;
1270
1271 if (changed)
1272 err = new_settings(hdev, sk);
1273
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001274 goto failed;
1275 }
1276
1277 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001278 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001279 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001280 goto failed;
1281 }
1282
1283 val = !!cp->val;
1284
1285 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1286 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1287 goto failed;
1288 }
1289
1290 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1291 if (!cmd) {
1292 err = -ENOMEM;
1293 goto failed;
1294 }
1295
1296 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1297 if (err < 0) {
1298 mgmt_pending_remove(cmd);
1299 goto failed;
1300 }
1301
1302failed:
1303 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001304 return err;
1305}
1306
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001307static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001308{
1309 struct mgmt_mode *cp = data;
1310 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001311 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001312 int err;
1313
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001314 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001315
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001316 status = mgmt_bredr_support(hdev);
1317 if (status)
1318 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1319
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001320 if (!lmp_ssp_capable(hdev))
1321 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1322 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001323
Johan Hedberga7e80f22013-01-09 16:05:19 +02001324 if (cp->val != 0x00 && cp->val != 0x01)
1325 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1326 MGMT_STATUS_INVALID_PARAMS);
1327
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001328 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001329
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001330 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001331 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001332
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001333 if (cp->val) {
1334 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1335 &hdev->dev_flags);
1336 } else {
1337 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1338 &hdev->dev_flags);
1339 if (!changed)
1340 changed = test_and_clear_bit(HCI_HS_ENABLED,
1341 &hdev->dev_flags);
1342 else
1343 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001344 }
1345
1346 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1347 if (err < 0)
1348 goto failed;
1349
1350 if (changed)
1351 err = new_settings(hdev, sk);
1352
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001353 goto failed;
1354 }
1355
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001356 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1357 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001358 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1359 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001360 goto failed;
1361 }
1362
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001363 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001364 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1365 goto failed;
1366 }
1367
1368 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1369 if (!cmd) {
1370 err = -ENOMEM;
1371 goto failed;
1372 }
1373
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001374 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001375 if (err < 0) {
1376 mgmt_pending_remove(cmd);
1377 goto failed;
1378 }
1379
1380failed:
1381 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001382 return err;
1383}
1384
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001385static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001386{
1387 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001388 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001389 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001390 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001392 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001393
Johan Hedberge6fe7982013-10-02 15:45:22 +03001394 status = mgmt_bredr_support(hdev);
1395 if (status)
1396 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001397
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001398 if (!lmp_ssp_capable(hdev))
1399 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1400 MGMT_STATUS_NOT_SUPPORTED);
1401
1402 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1403 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1404 MGMT_STATUS_REJECTED);
1405
Johan Hedberga7e80f22013-01-09 16:05:19 +02001406 if (cp->val != 0x00 && cp->val != 0x01)
1407 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1408 MGMT_STATUS_INVALID_PARAMS);
1409
Marcel Holtmannee392692013-10-01 22:59:23 -07001410 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001411
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001412 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001413 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001414 } else {
1415 if (hdev_is_powered(hdev)) {
1416 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1417 MGMT_STATUS_REJECTED);
1418 goto unlock;
1419 }
1420
Marcel Holtmannee392692013-10-01 22:59:23 -07001421 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001422 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001423
1424 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1425 if (err < 0)
1426 goto unlock;
1427
1428 if (changed)
1429 err = new_settings(hdev, sk);
1430
1431unlock:
1432 hci_dev_unlock(hdev);
1433 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001434}
1435
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001436static void enable_advertising(struct hci_request *req)
1437{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001438 struct hci_dev *hdev = req->hdev;
1439 struct hci_cp_le_set_adv_param cp;
1440 u8 enable = 0x01;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001441
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001442 memset(&cp, 0, sizeof(cp));
1443 cp.min_interval = __constant_cpu_to_le16(0x0800);
1444 cp.max_interval = __constant_cpu_to_le16(0x0800);
1445 cp.type = LE_ADV_IND;
1446 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1447 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1448 else
1449 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1450 cp.channel_map = 0x07;
1451
1452 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1453
1454 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001455}
1456
1457static void disable_advertising(struct hci_request *req)
1458{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001459 u8 enable = 0x00;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001460
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001461 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001462}
1463
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001464static void le_enable_complete(struct hci_dev *hdev, u8 status)
1465{
1466 struct cmd_lookup match = { NULL, hdev };
1467
1468 if (status) {
1469 u8 mgmt_err = mgmt_status(status);
1470
1471 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1472 &mgmt_err);
1473 return;
1474 }
1475
1476 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1477
1478 new_settings(hdev, match.sk);
1479
1480 if (match.sk)
1481 sock_put(match.sk);
1482}
1483
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001484static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001485{
1486 struct mgmt_mode *cp = data;
1487 struct hci_cp_write_le_host_supported hci_cp;
1488 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001489 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001490 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001491 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001492
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001493 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001494
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001495 if (!lmp_le_capable(hdev))
1496 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1497 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001498
Johan Hedberga7e80f22013-01-09 16:05:19 +02001499 if (cp->val != 0x00 && cp->val != 0x01)
1500 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1501 MGMT_STATUS_INVALID_PARAMS);
1502
Johan Hedbergc73eee92013-04-19 18:35:21 +03001503 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001504 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001505 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1506 MGMT_STATUS_REJECTED);
1507
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001508 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001509
1510 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001511 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001512
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001513 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001514 bool changed = false;
1515
1516 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1517 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1518 changed = true;
1519 }
1520
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001521 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1522 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001523 changed = true;
1524 }
1525
Johan Hedberg06199cf2012-02-22 16:37:11 +02001526 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1527 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001528 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001529
1530 if (changed)
1531 err = new_settings(hdev, sk);
1532
Johan Hedberg1de028c2012-02-29 19:55:35 -08001533 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001534 }
1535
Johan Hedberg4375f102013-09-25 13:26:10 +03001536 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1537 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001538 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001539 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001540 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001541 }
1542
1543 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1544 if (!cmd) {
1545 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001546 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001547 }
1548
1549 memset(&hci_cp, 0, sizeof(hci_cp));
1550
1551 if (val) {
1552 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001553 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001554 }
1555
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001556 hci_req_init(&req, hdev);
1557
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001558 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1559 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001560
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001561 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1562 &hci_cp);
1563
1564 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301565 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001566 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001567
Johan Hedberg1de028c2012-02-29 19:55:35 -08001568unlock:
1569 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001570 return err;
1571}
1572
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001573/* This is a helper function to test for pending mgmt commands that can
1574 * cause CoD or EIR HCI commands. We can only allow one such pending
1575 * mgmt command at a time since otherwise we cannot easily track what
1576 * the current values are, will be, and based on that calculate if a new
1577 * HCI command needs to be sent and if yes with what value.
1578 */
1579static bool pending_eir_or_class(struct hci_dev *hdev)
1580{
1581 struct pending_cmd *cmd;
1582
1583 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1584 switch (cmd->opcode) {
1585 case MGMT_OP_ADD_UUID:
1586 case MGMT_OP_REMOVE_UUID:
1587 case MGMT_OP_SET_DEV_CLASS:
1588 case MGMT_OP_SET_POWERED:
1589 return true;
1590 }
1591 }
1592
1593 return false;
1594}
1595
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001596static const u8 bluetooth_base_uuid[] = {
1597 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1598 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1599};
1600
1601static u8 get_uuid_size(const u8 *uuid)
1602{
1603 u32 val;
1604
1605 if (memcmp(uuid, bluetooth_base_uuid, 12))
1606 return 128;
1607
1608 val = get_unaligned_le32(&uuid[12]);
1609 if (val > 0xffff)
1610 return 32;
1611
1612 return 16;
1613}
1614
Johan Hedberg92da6092013-03-15 17:06:55 -05001615static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1616{
1617 struct pending_cmd *cmd;
1618
1619 hci_dev_lock(hdev);
1620
1621 cmd = mgmt_pending_find(mgmt_op, hdev);
1622 if (!cmd)
1623 goto unlock;
1624
1625 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1626 hdev->dev_class, 3);
1627
1628 mgmt_pending_remove(cmd);
1629
1630unlock:
1631 hci_dev_unlock(hdev);
1632}
1633
1634static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1635{
1636 BT_DBG("status 0x%02x", status);
1637
1638 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1639}
1640
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001641static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001642{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001643 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001644 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001645 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001646 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001647 int err;
1648
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001649 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001650
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001651 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001652
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001653 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001654 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001655 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001656 goto failed;
1657 }
1658
Andre Guedes92c4c202012-06-07 19:05:44 -03001659 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001660 if (!uuid) {
1661 err = -ENOMEM;
1662 goto failed;
1663 }
1664
1665 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001666 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001667 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001668
Johan Hedbergde66aa62013-01-27 00:31:27 +02001669 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001670
Johan Hedberg890ea892013-03-15 17:06:52 -05001671 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001672
Johan Hedberg890ea892013-03-15 17:06:52 -05001673 update_class(&req);
1674 update_eir(&req);
1675
Johan Hedberg92da6092013-03-15 17:06:55 -05001676 err = hci_req_run(&req, add_uuid_complete);
1677 if (err < 0) {
1678 if (err != -ENODATA)
1679 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001680
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001681 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001682 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001683 goto failed;
1684 }
1685
1686 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001687 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001688 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001689 goto failed;
1690 }
1691
1692 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001693
1694failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001695 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001696 return err;
1697}
1698
Johan Hedberg24b78d02012-02-23 23:24:30 +02001699static bool enable_service_cache(struct hci_dev *hdev)
1700{
1701 if (!hdev_is_powered(hdev))
1702 return false;
1703
1704 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001705 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1706 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001707 return true;
1708 }
1709
1710 return false;
1711}
1712
Johan Hedberg92da6092013-03-15 17:06:55 -05001713static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1714{
1715 BT_DBG("status 0x%02x", status);
1716
1717 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1718}
1719
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001720static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001721 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001722{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001723 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001724 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001725 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001726 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 -05001727 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001728 int err, found;
1729
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001730 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001731
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001732 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001733
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001734 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001735 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001736 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001737 goto unlock;
1738 }
1739
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001740 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1741 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001742
Johan Hedberg24b78d02012-02-23 23:24:30 +02001743 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001744 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001745 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001746 goto unlock;
1747 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001748
Johan Hedberg9246a862012-02-23 21:33:16 +02001749 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001750 }
1751
1752 found = 0;
1753
Johan Hedberg056341c2013-01-27 00:31:30 +02001754 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001755 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1756 continue;
1757
1758 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001759 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001760 found++;
1761 }
1762
1763 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001764 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001765 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001766 goto unlock;
1767 }
1768
Johan Hedberg9246a862012-02-23 21:33:16 +02001769update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001770 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001771
Johan Hedberg890ea892013-03-15 17:06:52 -05001772 update_class(&req);
1773 update_eir(&req);
1774
Johan Hedberg92da6092013-03-15 17:06:55 -05001775 err = hci_req_run(&req, remove_uuid_complete);
1776 if (err < 0) {
1777 if (err != -ENODATA)
1778 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001779
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001780 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001781 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001782 goto unlock;
1783 }
1784
1785 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001786 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001787 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001788 goto unlock;
1789 }
1790
1791 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001792
1793unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001794 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001795 return err;
1796}
1797
Johan Hedberg92da6092013-03-15 17:06:55 -05001798static void set_class_complete(struct hci_dev *hdev, u8 status)
1799{
1800 BT_DBG("status 0x%02x", status);
1801
1802 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1803}
1804
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001805static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001806 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001807{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001808 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001809 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001810 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001811 int err;
1812
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001813 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001814
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001815 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001816 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1817 MGMT_STATUS_NOT_SUPPORTED);
1818
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001819 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001820
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001821 if (pending_eir_or_class(hdev)) {
1822 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1823 MGMT_STATUS_BUSY);
1824 goto unlock;
1825 }
1826
1827 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1828 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1829 MGMT_STATUS_INVALID_PARAMS);
1830 goto unlock;
1831 }
1832
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001833 hdev->major_class = cp->major;
1834 hdev->minor_class = cp->minor;
1835
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001836 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001837 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001838 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001839 goto unlock;
1840 }
1841
Johan Hedberg890ea892013-03-15 17:06:52 -05001842 hci_req_init(&req, hdev);
1843
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001844 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001845 hci_dev_unlock(hdev);
1846 cancel_delayed_work_sync(&hdev->service_cache);
1847 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001848 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001849 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001850
Johan Hedberg890ea892013-03-15 17:06:52 -05001851 update_class(&req);
1852
Johan Hedberg92da6092013-03-15 17:06:55 -05001853 err = hci_req_run(&req, set_class_complete);
1854 if (err < 0) {
1855 if (err != -ENODATA)
1856 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001857
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001858 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001859 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001860 goto unlock;
1861 }
1862
1863 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001864 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001865 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001866 goto unlock;
1867 }
1868
1869 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001870
Johan Hedbergb5235a62012-02-21 14:32:24 +02001871unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001872 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001873 return err;
1874}
1875
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001876static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001877 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001878{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001879 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001880 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001881 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001882
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001883 BT_DBG("request for %s", hdev->name);
1884
1885 if (!lmp_bredr_capable(hdev))
1886 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1887 MGMT_STATUS_NOT_SUPPORTED);
1888
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001889 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001890
Johan Hedberg86742e12011-11-07 23:13:38 +02001891 expected_len = sizeof(*cp) + key_count *
1892 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001893 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001894 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001895 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001896 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001897 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001898 }
1899
Johan Hedberg4ae143012013-01-20 14:27:13 +02001900 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1901 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1902 MGMT_STATUS_INVALID_PARAMS);
1903
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001904 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001905 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001906
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001907 for (i = 0; i < key_count; i++) {
1908 struct mgmt_link_key_info *key = &cp->keys[i];
1909
1910 if (key->addr.type != BDADDR_BREDR)
1911 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1912 MGMT_STATUS_INVALID_PARAMS);
1913 }
1914
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001915 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001916
1917 hci_link_keys_clear(hdev);
1918
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001919 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001920 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001921 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001922 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001923
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001924 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001925 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001926
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001927 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001928 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001929 }
1930
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001931 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001932
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001933 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001934
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001935 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001936}
1937
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001938static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001939 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001940{
1941 struct mgmt_ev_device_unpaired ev;
1942
1943 bacpy(&ev.addr.bdaddr, bdaddr);
1944 ev.addr.type = addr_type;
1945
1946 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001947 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001948}
1949
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001950static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001951 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001952{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001953 struct mgmt_cp_unpair_device *cp = data;
1954 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001955 struct hci_cp_disconnect dc;
1956 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001957 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001958 int err;
1959
Johan Hedberga8a1d192011-11-10 15:54:38 +02001960 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001961 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1962 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001963
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001964 if (!bdaddr_type_is_valid(cp->addr.type))
1965 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1966 MGMT_STATUS_INVALID_PARAMS,
1967 &rp, sizeof(rp));
1968
Johan Hedberg118da702013-01-20 14:27:20 +02001969 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1970 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1971 MGMT_STATUS_INVALID_PARAMS,
1972 &rp, sizeof(rp));
1973
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001974 hci_dev_lock(hdev);
1975
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001976 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001977 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001978 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001979 goto unlock;
1980 }
1981
Andre Guedes591f47f2012-04-24 21:02:49 -03001982 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001983 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1984 else
1985 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001986
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001987 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001988 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001989 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001990 goto unlock;
1991 }
1992
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001993 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001994 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001995 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001996 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001997 else
1998 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001999 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002000 } else {
2001 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002002 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002003
Johan Hedberga8a1d192011-11-10 15:54:38 +02002004 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002005 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002006 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002007 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002008 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002009 }
2010
Johan Hedberg124f6e32012-02-09 13:50:12 +02002011 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002012 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002013 if (!cmd) {
2014 err = -ENOMEM;
2015 goto unlock;
2016 }
2017
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002018 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002019 dc.reason = 0x13; /* Remote User Terminated Connection */
2020 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2021 if (err < 0)
2022 mgmt_pending_remove(cmd);
2023
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002024unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002025 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002026 return err;
2027}
2028
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002029static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002030 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002031{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002032 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002033 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002034 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002035 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002036 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002037 int err;
2038
2039 BT_DBG("");
2040
Johan Hedberg06a63b12013-01-20 14:27:21 +02002041 memset(&rp, 0, sizeof(rp));
2042 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2043 rp.addr.type = cp->addr.type;
2044
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002045 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002046 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2047 MGMT_STATUS_INVALID_PARAMS,
2048 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002049
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002050 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002051
2052 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002053 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2054 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002055 goto failed;
2056 }
2057
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002058 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002059 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2060 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002061 goto failed;
2062 }
2063
Andre Guedes591f47f2012-04-24 21:02:49 -03002064 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002065 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2066 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002067 else
2068 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002069
Vishal Agarwalf9607272012-06-13 05:32:43 +05302070 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002071 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2072 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002073 goto failed;
2074 }
2075
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002076 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002077 if (!cmd) {
2078 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002079 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002080 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002081
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002082 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002083 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002084
2085 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2086 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002087 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002088
2089failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002090 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002091 return err;
2092}
2093
Andre Guedes57c14772012-04-24 21:02:50 -03002094static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002095{
2096 switch (link_type) {
2097 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002098 switch (addr_type) {
2099 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002100 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002101
Johan Hedberg48264f02011-11-09 13:58:58 +02002102 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002103 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002104 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002105 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002106
Johan Hedberg4c659c32011-11-07 23:13:39 +02002107 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002108 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002109 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002110 }
2111}
2112
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002113static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2114 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002115{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002116 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002117 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002118 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002119 int err;
2120 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002121
2122 BT_DBG("");
2123
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002124 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002125
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002126 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002127 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002128 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002129 goto unlock;
2130 }
2131
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002132 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002133 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2134 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002135 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002136 }
2137
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002138 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002139 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002140 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002141 err = -ENOMEM;
2142 goto unlock;
2143 }
2144
Johan Hedberg2784eb42011-01-21 13:56:35 +02002145 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002146 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002147 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2148 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002149 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002150 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002151 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002152 continue;
2153 i++;
2154 }
2155
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002156 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002157
Johan Hedberg4c659c32011-11-07 23:13:39 +02002158 /* Recalculate length in case of filtered SCO connections, etc */
2159 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002160
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002161 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002162 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002163
Johan Hedberga38528f2011-01-22 06:46:43 +02002164 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002165
2166unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002167 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002168 return err;
2169}
2170
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002171static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002172 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002173{
2174 struct pending_cmd *cmd;
2175 int err;
2176
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002177 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002178 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002179 if (!cmd)
2180 return -ENOMEM;
2181
Johan Hedbergd8457692012-02-17 14:24:57 +02002182 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002183 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002184 if (err < 0)
2185 mgmt_pending_remove(cmd);
2186
2187 return err;
2188}
2189
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002190static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002191 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002192{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002193 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002194 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002195 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002196 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002197 int err;
2198
2199 BT_DBG("");
2200
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002201 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002202
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002203 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002204 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002205 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002206 goto failed;
2207 }
2208
Johan Hedbergd8457692012-02-17 14:24:57 +02002209 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002210 if (!conn) {
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_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002213 goto failed;
2214 }
2215
2216 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002217 struct mgmt_cp_pin_code_neg_reply ncp;
2218
2219 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002220
2221 BT_ERR("PIN code is not 16 bytes long");
2222
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002223 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002224 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002225 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002226 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002227
2228 goto failed;
2229 }
2230
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002231 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002232 if (!cmd) {
2233 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002234 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002235 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002236
Johan Hedbergd8457692012-02-17 14:24:57 +02002237 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002238 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002239 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002240
2241 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2242 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002243 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002244
2245failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002246 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002247 return err;
2248}
2249
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002250static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2251 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002252{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002253 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002254
2255 BT_DBG("");
2256
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002257 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002258
2259 hdev->io_capability = cp->io_capability;
2260
2261 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002262 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002263
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002264 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002265
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002266 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2267 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002268}
2269
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002270static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002271{
2272 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002273 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002274
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002275 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002276 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2277 continue;
2278
Johan Hedberge9a416b2011-02-19 12:05:56 -03002279 if (cmd->user_data != conn)
2280 continue;
2281
2282 return cmd;
2283 }
2284
2285 return NULL;
2286}
2287
2288static void pairing_complete(struct pending_cmd *cmd, u8 status)
2289{
2290 struct mgmt_rp_pair_device rp;
2291 struct hci_conn *conn = cmd->user_data;
2292
Johan Hedbergba4e5642011-11-11 00:07:34 +02002293 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002294 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002295
Johan Hedbergaee9b212012-02-18 15:07:59 +02002296 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002297 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002298
2299 /* So we don't get further callbacks for this connection */
2300 conn->connect_cfm_cb = NULL;
2301 conn->security_cfm_cb = NULL;
2302 conn->disconn_cfm_cb = NULL;
2303
David Herrmann76a68ba2013-04-06 20:28:37 +02002304 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002305
Johan Hedberga664b5b2011-02-19 12:06:02 -03002306 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002307}
2308
2309static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2310{
2311 struct pending_cmd *cmd;
2312
2313 BT_DBG("status %u", status);
2314
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002315 cmd = find_pairing(conn);
2316 if (!cmd)
2317 BT_DBG("Unable to find a pending command");
2318 else
Johan Hedberge2113262012-02-18 15:20:03 +02002319 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002320}
2321
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302322static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2323{
2324 struct pending_cmd *cmd;
2325
2326 BT_DBG("status %u", status);
2327
2328 if (!status)
2329 return;
2330
2331 cmd = find_pairing(conn);
2332 if (!cmd)
2333 BT_DBG("Unable to find a pending command");
2334 else
2335 pairing_complete(cmd, mgmt_status(status));
2336}
2337
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002338static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002339 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002340{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002341 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002342 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002343 struct pending_cmd *cmd;
2344 u8 sec_level, auth_type;
2345 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002346 int err;
2347
2348 BT_DBG("");
2349
Szymon Jancf950a30e2013-01-18 12:48:07 +01002350 memset(&rp, 0, sizeof(rp));
2351 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2352 rp.addr.type = cp->addr.type;
2353
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002354 if (!bdaddr_type_is_valid(cp->addr.type))
2355 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2356 MGMT_STATUS_INVALID_PARAMS,
2357 &rp, sizeof(rp));
2358
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002359 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002360
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002361 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002362 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2363 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002364 goto unlock;
2365 }
2366
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002367 sec_level = BT_SECURITY_MEDIUM;
2368 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002369 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002370 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002371 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002372
Andre Guedes591f47f2012-04-24 21:02:49 -03002373 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002374 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2375 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002376 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002377 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2378 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002379
Ville Tervo30e76272011-02-22 16:10:53 -03002380 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002381 int status;
2382
2383 if (PTR_ERR(conn) == -EBUSY)
2384 status = MGMT_STATUS_BUSY;
2385 else
2386 status = MGMT_STATUS_CONNECT_FAILED;
2387
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002388 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002389 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002390 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002391 goto unlock;
2392 }
2393
2394 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002395 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002396 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002397 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002398 goto unlock;
2399 }
2400
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002401 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002402 if (!cmd) {
2403 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002404 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002405 goto unlock;
2406 }
2407
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002408 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002409 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002410 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302411 else
2412 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002413
Johan Hedberge9a416b2011-02-19 12:05:56 -03002414 conn->security_cfm_cb = pairing_complete_cb;
2415 conn->disconn_cfm_cb = pairing_complete_cb;
2416 conn->io_capability = cp->io_cap;
2417 cmd->user_data = conn;
2418
2419 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002420 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002421 pairing_complete(cmd, 0);
2422
2423 err = 0;
2424
2425unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002426 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002427 return err;
2428}
2429
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002430static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2431 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002432{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002433 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002434 struct pending_cmd *cmd;
2435 struct hci_conn *conn;
2436 int err;
2437
2438 BT_DBG("");
2439
Johan Hedberg28424702012-02-02 04:02:29 +02002440 hci_dev_lock(hdev);
2441
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002442 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002443 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002444 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002445 goto unlock;
2446 }
2447
Johan Hedberg28424702012-02-02 04:02:29 +02002448 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2449 if (!cmd) {
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_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002452 goto unlock;
2453 }
2454
2455 conn = cmd->user_data;
2456
2457 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002458 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002459 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002460 goto unlock;
2461 }
2462
2463 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2464
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002465 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002466 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002467unlock:
2468 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002469 return err;
2470}
2471
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002472static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002473 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002474 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002475{
Johan Hedberga5c29682011-02-19 12:05:57 -03002476 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002477 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002478 int err;
2479
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002480 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002481
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002482 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002483 err = cmd_complete(sk, hdev->id, mgmt_op,
2484 MGMT_STATUS_NOT_POWERED, addr,
2485 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002486 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002487 }
2488
Johan Hedberg1707c602013-03-15 17:07:15 -05002489 if (addr->type == BDADDR_BREDR)
2490 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002491 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002492 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002493
Johan Hedberg272d90d2012-02-09 15:26:12 +02002494 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002495 err = cmd_complete(sk, hdev->id, mgmt_op,
2496 MGMT_STATUS_NOT_CONNECTED, addr,
2497 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002498 goto done;
2499 }
2500
Johan Hedberg1707c602013-03-15 17:07:15 -05002501 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002502 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002503 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002504
Brian Gix5fe57d92011-12-21 16:12:13 -08002505 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002506 err = cmd_complete(sk, hdev->id, mgmt_op,
2507 MGMT_STATUS_SUCCESS, addr,
2508 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002509 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002510 err = cmd_complete(sk, hdev->id, mgmt_op,
2511 MGMT_STATUS_FAILED, addr,
2512 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002513
Brian Gix47c15e22011-11-16 13:53:14 -08002514 goto done;
2515 }
2516
Johan Hedberg1707c602013-03-15 17:07:15 -05002517 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002518 if (!cmd) {
2519 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002520 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002521 }
2522
Brian Gix0df4c182011-11-16 13:53:13 -08002523 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002524 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2525 struct hci_cp_user_passkey_reply cp;
2526
Johan Hedberg1707c602013-03-15 17:07:15 -05002527 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002528 cp.passkey = passkey;
2529 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2530 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002531 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2532 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002533
Johan Hedberga664b5b2011-02-19 12:06:02 -03002534 if (err < 0)
2535 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002536
Brian Gix0df4c182011-11-16 13:53:13 -08002537done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002538 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002539 return err;
2540}
2541
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302542static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2543 void *data, u16 len)
2544{
2545 struct mgmt_cp_pin_code_neg_reply *cp = data;
2546
2547 BT_DBG("");
2548
Johan Hedberg1707c602013-03-15 17:07:15 -05002549 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302550 MGMT_OP_PIN_CODE_NEG_REPLY,
2551 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2552}
2553
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002554static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2555 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002556{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002557 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002558
2559 BT_DBG("");
2560
2561 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002562 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002563 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002564
Johan Hedberg1707c602013-03-15 17:07:15 -05002565 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002566 MGMT_OP_USER_CONFIRM_REPLY,
2567 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002568}
2569
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002570static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002571 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002572{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002573 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002574
2575 BT_DBG("");
2576
Johan Hedberg1707c602013-03-15 17:07:15 -05002577 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002578 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2579 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002580}
2581
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002582static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2583 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002584{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002585 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002586
2587 BT_DBG("");
2588
Johan Hedberg1707c602013-03-15 17:07:15 -05002589 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002590 MGMT_OP_USER_PASSKEY_REPLY,
2591 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002592}
2593
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002594static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002595 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002596{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002597 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002598
2599 BT_DBG("");
2600
Johan Hedberg1707c602013-03-15 17:07:15 -05002601 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002602 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2603 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002604}
2605
Johan Hedberg13928972013-03-15 17:07:00 -05002606static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002607{
Johan Hedberg13928972013-03-15 17:07:00 -05002608 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002609 struct hci_cp_write_local_name cp;
2610
Johan Hedberg13928972013-03-15 17:07:00 -05002611 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002612
Johan Hedberg890ea892013-03-15 17:06:52 -05002613 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002614}
2615
Johan Hedberg13928972013-03-15 17:07:00 -05002616static void set_name_complete(struct hci_dev *hdev, u8 status)
2617{
2618 struct mgmt_cp_set_local_name *cp;
2619 struct pending_cmd *cmd;
2620
2621 BT_DBG("status 0x%02x", status);
2622
2623 hci_dev_lock(hdev);
2624
2625 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2626 if (!cmd)
2627 goto unlock;
2628
2629 cp = cmd->param;
2630
2631 if (status)
2632 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2633 mgmt_status(status));
2634 else
2635 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2636 cp, sizeof(*cp));
2637
2638 mgmt_pending_remove(cmd);
2639
2640unlock:
2641 hci_dev_unlock(hdev);
2642}
2643
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002644static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002645 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002646{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002647 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002648 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002649 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002650 int err;
2651
2652 BT_DBG("");
2653
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002654 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002655
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002656 /* If the old values are the same as the new ones just return a
2657 * direct command complete event.
2658 */
2659 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2660 !memcmp(hdev->short_name, cp->short_name,
2661 sizeof(hdev->short_name))) {
2662 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2663 data, len);
2664 goto failed;
2665 }
2666
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002667 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002668
Johan Hedbergb5235a62012-02-21 14:32:24 +02002669 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002670 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002671
2672 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002673 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002674 if (err < 0)
2675 goto failed;
2676
2677 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002678 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002679
Johan Hedbergb5235a62012-02-21 14:32:24 +02002680 goto failed;
2681 }
2682
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002683 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002684 if (!cmd) {
2685 err = -ENOMEM;
2686 goto failed;
2687 }
2688
Johan Hedberg13928972013-03-15 17:07:00 -05002689 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2690
Johan Hedberg890ea892013-03-15 17:06:52 -05002691 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002692
2693 if (lmp_bredr_capable(hdev)) {
2694 update_name(&req);
2695 update_eir(&req);
2696 }
2697
2698 if (lmp_le_capable(hdev))
2699 hci_update_ad(&req);
2700
Johan Hedberg13928972013-03-15 17:07:00 -05002701 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002702 if (err < 0)
2703 mgmt_pending_remove(cmd);
2704
2705failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002706 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002707 return err;
2708}
2709
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002710static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002711 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002712{
Szymon Jancc35938b2011-03-22 13:12:21 +01002713 struct pending_cmd *cmd;
2714 int err;
2715
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002716 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002717
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002718 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002719
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002720 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002721 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002722 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002723 goto unlock;
2724 }
2725
Andre Guedes9a1a1992012-07-24 15:03:48 -03002726 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002727 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002728 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002729 goto unlock;
2730 }
2731
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002732 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002733 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002734 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002735 goto unlock;
2736 }
2737
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002738 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002739 if (!cmd) {
2740 err = -ENOMEM;
2741 goto unlock;
2742 }
2743
2744 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2745 if (err < 0)
2746 mgmt_pending_remove(cmd);
2747
2748unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002749 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002750 return err;
2751}
2752
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002753static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002754 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002755{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002756 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002757 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002758 int err;
2759
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002760 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002761
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002762 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002763
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002764 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002765 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002766 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002767 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002768 else
Szymon Janca6785be2012-12-13 15:11:21 +01002769 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002770
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002771 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002772 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002773
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002774 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002775 return err;
2776}
2777
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002778static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002779 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002780{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002781 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002782 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002783 int err;
2784
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002785 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002786
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002787 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002788
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002789 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002790 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002791 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002792 else
Szymon Janca6785be2012-12-13 15:11:21 +01002793 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002794
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002795 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002796 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002797
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002798 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002799 return err;
2800}
2801
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002802static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2803{
2804 struct pending_cmd *cmd;
2805 u8 type;
2806 int err;
2807
2808 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2809
2810 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2811 if (!cmd)
2812 return -ENOENT;
2813
2814 type = hdev->discovery.type;
2815
2816 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2817 &type, sizeof(type));
2818 mgmt_pending_remove(cmd);
2819
2820 return err;
2821}
2822
Andre Guedes7c307722013-04-30 15:29:28 -03002823static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2824{
2825 BT_DBG("status %d", status);
2826
2827 if (status) {
2828 hci_dev_lock(hdev);
2829 mgmt_start_discovery_failed(hdev, status);
2830 hci_dev_unlock(hdev);
2831 return;
2832 }
2833
2834 hci_dev_lock(hdev);
2835 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2836 hci_dev_unlock(hdev);
2837
2838 switch (hdev->discovery.type) {
2839 case DISCOV_TYPE_LE:
2840 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002841 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002842 break;
2843
2844 case DISCOV_TYPE_INTERLEAVED:
2845 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002846 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002847 break;
2848
2849 case DISCOV_TYPE_BREDR:
2850 break;
2851
2852 default:
2853 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2854 }
2855}
2856
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002857static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002858 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002859{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002860 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002861 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002862 struct hci_cp_le_set_scan_param param_cp;
2863 struct hci_cp_le_set_scan_enable enable_cp;
2864 struct hci_cp_inquiry inq_cp;
2865 struct hci_request req;
2866 /* General inquiry access code (GIAC) */
2867 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002868 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002869 int err;
2870
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002871 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002872
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002873 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002874
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002875 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002876 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002877 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002878 goto failed;
2879 }
2880
Andre Guedes642be6c2012-03-21 00:03:37 -03002881 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2882 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2883 MGMT_STATUS_BUSY);
2884 goto failed;
2885 }
2886
Johan Hedbergff9ef572012-01-04 14:23:45 +02002887 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002888 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002889 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002890 goto failed;
2891 }
2892
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002893 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002894 if (!cmd) {
2895 err = -ENOMEM;
2896 goto failed;
2897 }
2898
Andre Guedes4aab14e2012-02-17 20:39:36 -03002899 hdev->discovery.type = cp->type;
2900
Andre Guedes7c307722013-04-30 15:29:28 -03002901 hci_req_init(&req, hdev);
2902
Andre Guedes4aab14e2012-02-17 20:39:36 -03002903 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002904 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002905 status = mgmt_bredr_support(hdev);
2906 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002907 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002908 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002909 mgmt_pending_remove(cmd);
2910 goto failed;
2911 }
2912
Andre Guedes7c307722013-04-30 15:29:28 -03002913 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2914 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2915 MGMT_STATUS_BUSY);
2916 mgmt_pending_remove(cmd);
2917 goto failed;
2918 }
2919
2920 hci_inquiry_cache_flush(hdev);
2921
2922 memset(&inq_cp, 0, sizeof(inq_cp));
2923 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002924 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002925 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002926 break;
2927
2928 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002929 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002930 status = mgmt_le_support(hdev);
2931 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002932 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002933 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002934 mgmt_pending_remove(cmd);
2935 goto failed;
2936 }
2937
Andre Guedes7c307722013-04-30 15:29:28 -03002938 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002939 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002940 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2941 MGMT_STATUS_NOT_SUPPORTED);
2942 mgmt_pending_remove(cmd);
2943 goto failed;
2944 }
2945
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002946 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002947 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2948 MGMT_STATUS_REJECTED);
2949 mgmt_pending_remove(cmd);
2950 goto failed;
2951 }
2952
2953 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2954 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2955 MGMT_STATUS_BUSY);
2956 mgmt_pending_remove(cmd);
2957 goto failed;
2958 }
2959
2960 memset(&param_cp, 0, sizeof(param_cp));
2961 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002962 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2963 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002964 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2965 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2966 else
2967 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002968 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2969 &param_cp);
2970
2971 memset(&enable_cp, 0, sizeof(enable_cp));
2972 enable_cp.enable = LE_SCAN_ENABLE;
2973 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2974 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2975 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002976 break;
2977
Andre Guedesf39799f2012-02-17 20:39:35 -03002978 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002979 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2980 MGMT_STATUS_INVALID_PARAMS);
2981 mgmt_pending_remove(cmd);
2982 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002983 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002984
Andre Guedes7c307722013-04-30 15:29:28 -03002985 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002986 if (err < 0)
2987 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002988 else
2989 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002990
2991failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002992 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002993 return err;
2994}
2995
Andre Guedes1183fdc2013-04-30 15:29:35 -03002996static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2997{
2998 struct pending_cmd *cmd;
2999 int err;
3000
3001 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3002 if (!cmd)
3003 return -ENOENT;
3004
3005 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3006 &hdev->discovery.type, sizeof(hdev->discovery.type));
3007 mgmt_pending_remove(cmd);
3008
3009 return err;
3010}
3011
Andre Guedes0e05bba2013-04-30 15:29:33 -03003012static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3013{
3014 BT_DBG("status %d", status);
3015
3016 hci_dev_lock(hdev);
3017
3018 if (status) {
3019 mgmt_stop_discovery_failed(hdev, status);
3020 goto unlock;
3021 }
3022
3023 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3024
3025unlock:
3026 hci_dev_unlock(hdev);
3027}
3028
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003029static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003030 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003031{
Johan Hedbergd9306502012-02-20 23:25:18 +02003032 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003033 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003034 struct hci_cp_remote_name_req_cancel cp;
3035 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003036 struct hci_request req;
3037 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003038 int err;
3039
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003040 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003041
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003042 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003043
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003044 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003045 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003046 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3047 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003048 goto unlock;
3049 }
3050
3051 if (hdev->discovery.type != mgmt_cp->type) {
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_INVALID_PARAMS, &mgmt_cp->type,
3054 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003055 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003056 }
3057
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003058 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003059 if (!cmd) {
3060 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003061 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003062 }
3063
Andre Guedes0e05bba2013-04-30 15:29:33 -03003064 hci_req_init(&req, hdev);
3065
Andre Guedese0d9727e2012-03-20 15:15:36 -03003066 switch (hdev->discovery.state) {
3067 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003068 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3069 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3070 } else {
3071 cancel_delayed_work(&hdev->le_scan_disable);
3072
3073 memset(&enable_cp, 0, sizeof(enable_cp));
3074 enable_cp.enable = LE_SCAN_DISABLE;
3075 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3076 sizeof(enable_cp), &enable_cp);
3077 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003078
Andre Guedese0d9727e2012-03-20 15:15:36 -03003079 break;
3080
3081 case DISCOVERY_RESOLVING:
3082 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003083 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003084 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003085 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003086 err = cmd_complete(sk, hdev->id,
3087 MGMT_OP_STOP_DISCOVERY, 0,
3088 &mgmt_cp->type,
3089 sizeof(mgmt_cp->type));
3090 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3091 goto unlock;
3092 }
3093
3094 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003095 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3096 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003097
3098 break;
3099
3100 default:
3101 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003102
3103 mgmt_pending_remove(cmd);
3104 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3105 MGMT_STATUS_FAILED, &mgmt_cp->type,
3106 sizeof(mgmt_cp->type));
3107 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003108 }
3109
Andre Guedes0e05bba2013-04-30 15:29:33 -03003110 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003111 if (err < 0)
3112 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003113 else
3114 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003115
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003116unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003117 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003118 return err;
3119}
3120
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003121static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003122 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003123{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003124 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003125 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003126 int err;
3127
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003128 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003129
Johan Hedberg561aafb2012-01-04 13:31:59 +02003130 hci_dev_lock(hdev);
3131
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003132 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003133 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003134 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003135 goto failed;
3136 }
3137
Johan Hedberga198e7b2012-02-17 14:27:06 +02003138 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003139 if (!e) {
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_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003142 goto failed;
3143 }
3144
3145 if (cp->name_known) {
3146 e->name_state = NAME_KNOWN;
3147 list_del(&e->list);
3148 } else {
3149 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003150 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003151 }
3152
Johan Hedberge3846622013-01-09 15:29:33 +02003153 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3154 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003155
3156failed:
3157 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003158 return err;
3159}
3160
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003161static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003162 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003163{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003164 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003165 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003166 int err;
3167
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003168 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003169
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003170 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003171 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3172 MGMT_STATUS_INVALID_PARAMS,
3173 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003174
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003175 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003176
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003177 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003178 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003179 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003180 else
Szymon Janca6785be2012-12-13 15:11:21 +01003181 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003182
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003183 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003184 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003185
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003186 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003187
3188 return err;
3189}
3190
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003191static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003192 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003193{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003194 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003195 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003196 int err;
3197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003198 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003199
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003200 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003201 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3202 MGMT_STATUS_INVALID_PARAMS,
3203 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003204
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003205 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003206
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003207 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003208 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003209 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003210 else
Szymon Janca6785be2012-12-13 15:11:21 +01003211 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003212
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003213 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003214 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003215
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003216 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003217
3218 return err;
3219}
3220
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003221static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3222 u16 len)
3223{
3224 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003225 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003226 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003227 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003228
3229 BT_DBG("%s", hdev->name);
3230
Szymon Jancc72d4b82012-03-16 16:02:57 +01003231 source = __le16_to_cpu(cp->source);
3232
3233 if (source > 0x0002)
3234 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3235 MGMT_STATUS_INVALID_PARAMS);
3236
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003237 hci_dev_lock(hdev);
3238
Szymon Jancc72d4b82012-03-16 16:02:57 +01003239 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003240 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3241 hdev->devid_product = __le16_to_cpu(cp->product);
3242 hdev->devid_version = __le16_to_cpu(cp->version);
3243
3244 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3245
Johan Hedberg890ea892013-03-15 17:06:52 -05003246 hci_req_init(&req, hdev);
3247 update_eir(&req);
3248 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003249
3250 hci_dev_unlock(hdev);
3251
3252 return err;
3253}
3254
Johan Hedberg4375f102013-09-25 13:26:10 +03003255static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3256{
3257 struct cmd_lookup match = { NULL, hdev };
3258
3259 if (status) {
3260 u8 mgmt_err = mgmt_status(status);
3261
3262 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3263 cmd_status_rsp, &mgmt_err);
3264 return;
3265 }
3266
3267 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3268 &match);
3269
3270 new_settings(hdev, match.sk);
3271
3272 if (match.sk)
3273 sock_put(match.sk);
3274}
3275
Marcel Holtmann21b51872013-10-10 09:47:53 -07003276static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3277 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003278{
3279 struct mgmt_mode *cp = data;
3280 struct pending_cmd *cmd;
3281 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003282 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003283 int err;
3284
3285 BT_DBG("request for %s", hdev->name);
3286
Johan Hedberge6fe7982013-10-02 15:45:22 +03003287 status = mgmt_le_support(hdev);
3288 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003289 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003290 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003291
3292 if (cp->val != 0x00 && cp->val != 0x01)
3293 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3294 MGMT_STATUS_INVALID_PARAMS);
3295
3296 hci_dev_lock(hdev);
3297
3298 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003299 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003300
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003301 /* The following conditions are ones which mean that we should
3302 * not do any HCI communication but directly send a mgmt
3303 * response to user space (after toggling the flag if
3304 * necessary).
3305 */
3306 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003307 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003308 bool changed = false;
3309
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003310 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3311 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003312 changed = true;
3313 }
3314
3315 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3316 if (err < 0)
3317 goto unlock;
3318
3319 if (changed)
3320 err = new_settings(hdev, sk);
3321
3322 goto unlock;
3323 }
3324
3325 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3326 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3327 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3328 MGMT_STATUS_BUSY);
3329 goto unlock;
3330 }
3331
3332 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3333 if (!cmd) {
3334 err = -ENOMEM;
3335 goto unlock;
3336 }
3337
3338 hci_req_init(&req, hdev);
3339
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003340 if (val)
3341 enable_advertising(&req);
3342 else
3343 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003344
3345 err = hci_req_run(&req, set_advertising_complete);
3346 if (err < 0)
3347 mgmt_pending_remove(cmd);
3348
3349unlock:
3350 hci_dev_unlock(hdev);
3351 return err;
3352}
3353
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003354static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3355 void *data, u16 len)
3356{
3357 struct mgmt_cp_set_static_address *cp = data;
3358 int err;
3359
3360 BT_DBG("%s", hdev->name);
3361
Marcel Holtmann62af4442013-10-02 22:10:32 -07003362 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003363 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003364 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003365
3366 if (hdev_is_powered(hdev))
3367 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3368 MGMT_STATUS_REJECTED);
3369
3370 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3371 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3372 return cmd_status(sk, hdev->id,
3373 MGMT_OP_SET_STATIC_ADDRESS,
3374 MGMT_STATUS_INVALID_PARAMS);
3375
3376 /* Two most significant bits shall be set */
3377 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3378 return cmd_status(sk, hdev->id,
3379 MGMT_OP_SET_STATIC_ADDRESS,
3380 MGMT_STATUS_INVALID_PARAMS);
3381 }
3382
3383 hci_dev_lock(hdev);
3384
3385 bacpy(&hdev->static_addr, &cp->bdaddr);
3386
3387 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3388
3389 hci_dev_unlock(hdev);
3390
3391 return err;
3392}
3393
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003394static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3395 void *data, u16 len)
3396{
3397 struct mgmt_cp_set_scan_params *cp = data;
3398 __u16 interval, window;
3399 int err;
3400
3401 BT_DBG("%s", hdev->name);
3402
3403 if (!lmp_le_capable(hdev))
3404 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3405 MGMT_STATUS_NOT_SUPPORTED);
3406
3407 interval = __le16_to_cpu(cp->interval);
3408
3409 if (interval < 0x0004 || interval > 0x4000)
3410 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3411 MGMT_STATUS_INVALID_PARAMS);
3412
3413 window = __le16_to_cpu(cp->window);
3414
3415 if (window < 0x0004 || window > 0x4000)
3416 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3417 MGMT_STATUS_INVALID_PARAMS);
3418
3419 hci_dev_lock(hdev);
3420
3421 hdev->le_scan_interval = interval;
3422 hdev->le_scan_window = window;
3423
3424 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3425
3426 hci_dev_unlock(hdev);
3427
3428 return err;
3429}
3430
Johan Hedberg33e38b32013-03-15 17:07:05 -05003431static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3432{
3433 struct pending_cmd *cmd;
3434
3435 BT_DBG("status 0x%02x", status);
3436
3437 hci_dev_lock(hdev);
3438
3439 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3440 if (!cmd)
3441 goto unlock;
3442
3443 if (status) {
3444 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3445 mgmt_status(status));
3446 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003447 struct mgmt_mode *cp = cmd->param;
3448
3449 if (cp->val)
3450 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3451 else
3452 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3453
Johan Hedberg33e38b32013-03-15 17:07:05 -05003454 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3455 new_settings(hdev, cmd->sk);
3456 }
3457
3458 mgmt_pending_remove(cmd);
3459
3460unlock:
3461 hci_dev_unlock(hdev);
3462}
3463
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003464static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003465 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003466{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003467 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003468 struct pending_cmd *cmd;
3469 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003470 int err;
3471
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003472 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003473
Johan Hedberg56f87902013-10-02 13:43:13 +03003474 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3475 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003476 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3477 MGMT_STATUS_NOT_SUPPORTED);
3478
Johan Hedberga7e80f22013-01-09 16:05:19 +02003479 if (cp->val != 0x00 && cp->val != 0x01)
3480 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3481 MGMT_STATUS_INVALID_PARAMS);
3482
Johan Hedberg5400c042012-02-21 16:40:33 +02003483 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003484 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003485 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003486
3487 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003488 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003489 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003490
3491 hci_dev_lock(hdev);
3492
Johan Hedberg05cbf292013-03-15 17:07:07 -05003493 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3494 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3495 MGMT_STATUS_BUSY);
3496 goto unlock;
3497 }
3498
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003499 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3500 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3501 hdev);
3502 goto unlock;
3503 }
3504
Johan Hedberg33e38b32013-03-15 17:07:05 -05003505 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3506 data, len);
3507 if (!cmd) {
3508 err = -ENOMEM;
3509 goto unlock;
3510 }
3511
3512 hci_req_init(&req, hdev);
3513
Johan Hedberg406d7802013-03-15 17:07:09 -05003514 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003515
3516 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003517 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003518 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003519 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003520 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003521 }
3522
Johan Hedberg33e38b32013-03-15 17:07:05 -05003523unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003524 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003525
Antti Julkuf6422ec2011-06-22 13:11:56 +03003526 return err;
3527}
3528
Johan Hedberg0663ca22013-10-02 13:43:14 +03003529static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3530{
3531 struct pending_cmd *cmd;
3532
3533 BT_DBG("status 0x%02x", status);
3534
3535 hci_dev_lock(hdev);
3536
3537 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3538 if (!cmd)
3539 goto unlock;
3540
3541 if (status) {
3542 u8 mgmt_err = mgmt_status(status);
3543
3544 /* We need to restore the flag if related HCI commands
3545 * failed.
3546 */
3547 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3548
3549 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3550 } else {
3551 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3552 new_settings(hdev, cmd->sk);
3553 }
3554
3555 mgmt_pending_remove(cmd);
3556
3557unlock:
3558 hci_dev_unlock(hdev);
3559}
3560
3561static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3562{
3563 struct mgmt_mode *cp = data;
3564 struct pending_cmd *cmd;
3565 struct hci_request req;
3566 int err;
3567
3568 BT_DBG("request for %s", hdev->name);
3569
3570 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3571 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3572 MGMT_STATUS_NOT_SUPPORTED);
3573
3574 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3575 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3576 MGMT_STATUS_REJECTED);
3577
3578 if (cp->val != 0x00 && cp->val != 0x01)
3579 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3580 MGMT_STATUS_INVALID_PARAMS);
3581
3582 hci_dev_lock(hdev);
3583
3584 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3585 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3586 goto unlock;
3587 }
3588
3589 if (!hdev_is_powered(hdev)) {
3590 if (!cp->val) {
3591 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3592 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3593 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3594 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3595 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3596 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3597 }
3598
3599 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3600
3601 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3602 if (err < 0)
3603 goto unlock;
3604
3605 err = new_settings(hdev, sk);
3606 goto unlock;
3607 }
3608
3609 /* Reject disabling when powered on */
3610 if (!cp->val) {
3611 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3612 MGMT_STATUS_REJECTED);
3613 goto unlock;
3614 }
3615
3616 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3617 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3618 MGMT_STATUS_BUSY);
3619 goto unlock;
3620 }
3621
3622 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3623 if (!cmd) {
3624 err = -ENOMEM;
3625 goto unlock;
3626 }
3627
3628 /* We need to flip the bit already here so that hci_update_ad
3629 * generates the correct flags.
3630 */
3631 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3632
3633 hci_req_init(&req, hdev);
3634 hci_update_ad(&req);
3635 err = hci_req_run(&req, set_bredr_complete);
3636 if (err < 0)
3637 mgmt_pending_remove(cmd);
3638
3639unlock:
3640 hci_dev_unlock(hdev);
3641 return err;
3642}
3643
Johan Hedberg3f706b72013-01-20 14:27:16 +02003644static bool ltk_is_valid(struct mgmt_ltk_info *key)
3645{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003646 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3647 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003648 if (key->master != 0x00 && key->master != 0x01)
3649 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003650 if (!bdaddr_type_is_le(key->addr.type))
3651 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003652 return true;
3653}
3654
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003655static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003656 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003657{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003658 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3659 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003660 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003661
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003662 BT_DBG("request for %s", hdev->name);
3663
3664 if (!lmp_le_capable(hdev))
3665 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3666 MGMT_STATUS_NOT_SUPPORTED);
3667
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003668 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003669
3670 expected_len = sizeof(*cp) + key_count *
3671 sizeof(struct mgmt_ltk_info);
3672 if (expected_len != len) {
3673 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003674 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003675 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003676 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003677 }
3678
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003679 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003680
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003681 for (i = 0; i < key_count; i++) {
3682 struct mgmt_ltk_info *key = &cp->keys[i];
3683
Johan Hedberg3f706b72013-01-20 14:27:16 +02003684 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003685 return cmd_status(sk, hdev->id,
3686 MGMT_OP_LOAD_LONG_TERM_KEYS,
3687 MGMT_STATUS_INVALID_PARAMS);
3688 }
3689
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003690 hci_dev_lock(hdev);
3691
3692 hci_smp_ltks_clear(hdev);
3693
3694 for (i = 0; i < key_count; i++) {
3695 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003696 u8 type, addr_type;
3697
3698 if (key->addr.type == BDADDR_LE_PUBLIC)
3699 addr_type = ADDR_LE_DEV_PUBLIC;
3700 else
3701 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003702
3703 if (key->master)
3704 type = HCI_SMP_LTK;
3705 else
3706 type = HCI_SMP_LTK_SLAVE;
3707
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003708 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003709 type, 0, key->authenticated, key->val,
3710 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003711 }
3712
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003713 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3714 NULL, 0);
3715
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003716 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003717
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003718 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003719}
3720
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003721static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003722 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3723 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003724 bool var_len;
3725 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003726} mgmt_handlers[] = {
3727 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003728 { read_version, false, MGMT_READ_VERSION_SIZE },
3729 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3730 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3731 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3732 { set_powered, false, MGMT_SETTING_SIZE },
3733 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3734 { set_connectable, false, MGMT_SETTING_SIZE },
3735 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3736 { set_pairable, false, MGMT_SETTING_SIZE },
3737 { set_link_security, false, MGMT_SETTING_SIZE },
3738 { set_ssp, false, MGMT_SETTING_SIZE },
3739 { set_hs, false, MGMT_SETTING_SIZE },
3740 { set_le, false, MGMT_SETTING_SIZE },
3741 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3742 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3743 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3744 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3745 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3746 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3747 { disconnect, false, MGMT_DISCONNECT_SIZE },
3748 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3749 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3750 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3751 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3752 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3753 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3754 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3755 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3756 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3757 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3758 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3759 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3760 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3761 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3762 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3763 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3764 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3765 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3766 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003767 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003768 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003769 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003770 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003771 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003772};
3773
3774
Johan Hedberg03811012010-12-08 00:21:06 +02003775int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3776{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003777 void *buf;
3778 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003779 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003780 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003781 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003782 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003783 int err;
3784
3785 BT_DBG("got %zu bytes", msglen);
3786
3787 if (msglen < sizeof(*hdr))
3788 return -EINVAL;
3789
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003790 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003791 if (!buf)
3792 return -ENOMEM;
3793
3794 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3795 err = -EFAULT;
3796 goto done;
3797 }
3798
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003799 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003800 opcode = __le16_to_cpu(hdr->opcode);
3801 index = __le16_to_cpu(hdr->index);
3802 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003803
3804 if (len != msglen - sizeof(*hdr)) {
3805 err = -EINVAL;
3806 goto done;
3807 }
3808
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003809 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003810 hdev = hci_dev_get(index);
3811 if (!hdev) {
3812 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003813 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003814 goto done;
3815 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003816
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02003817 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
3818 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003819 err = cmd_status(sk, index, opcode,
3820 MGMT_STATUS_INVALID_INDEX);
3821 goto done;
3822 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003823 }
3824
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003825 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003826 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003827 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003828 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003829 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003830 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003831 }
3832
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003833 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003834 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003835 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003836 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003837 goto done;
3838 }
3839
Johan Hedbergbe22b542012-03-01 22:24:41 +02003840 handler = &mgmt_handlers[opcode];
3841
3842 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003843 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003844 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003845 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003846 goto done;
3847 }
3848
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003849 if (hdev)
3850 mgmt_init_hdev(sk, hdev);
3851
3852 cp = buf + sizeof(*hdr);
3853
Johan Hedbergbe22b542012-03-01 22:24:41 +02003854 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003855 if (err < 0)
3856 goto done;
3857
Johan Hedberg03811012010-12-08 00:21:06 +02003858 err = msglen;
3859
3860done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003861 if (hdev)
3862 hci_dev_put(hdev);
3863
Johan Hedberg03811012010-12-08 00:21:06 +02003864 kfree(buf);
3865 return err;
3866}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003867
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003868void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003869{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003870 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003871 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003872
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003873 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003874}
3875
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003876void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003877{
Johan Hedberg5f159032012-03-02 03:13:19 +02003878 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003879
Marcel Holtmann1514b892013-10-06 08:25:01 -07003880 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003881 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003882
Johan Hedberg744cf192011-11-08 20:40:14 +02003883 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003884
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003885 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003886}
3887
Johan Hedberg890ea892013-03-15 17:06:52 -05003888static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003889{
Johan Hedberg890ea892013-03-15 17:06:52 -05003890 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003891 u8 scan = 0;
3892
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003893 /* Ensure that fast connectable is disabled. This function will
3894 * not do anything if the page scan parameters are already what
3895 * they should be.
3896 */
3897 write_fast_connectable(req, false);
3898
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003899 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3900 scan |= SCAN_PAGE;
3901 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3902 scan |= SCAN_INQUIRY;
3903
Johan Hedberg890ea892013-03-15 17:06:52 -05003904 if (scan)
3905 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003906}
3907
Johan Hedberg229ab392013-03-15 17:06:53 -05003908static void powered_complete(struct hci_dev *hdev, u8 status)
3909{
3910 struct cmd_lookup match = { NULL, hdev };
3911
3912 BT_DBG("status 0x%02x", status);
3913
3914 hci_dev_lock(hdev);
3915
3916 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3917
3918 new_settings(hdev, match.sk);
3919
3920 hci_dev_unlock(hdev);
3921
3922 if (match.sk)
3923 sock_put(match.sk);
3924}
3925
Johan Hedberg70da6242013-03-15 17:06:51 -05003926static int powered_update_hci(struct hci_dev *hdev)
3927{
Johan Hedberg890ea892013-03-15 17:06:52 -05003928 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003929 u8 link_sec;
3930
Johan Hedberg890ea892013-03-15 17:06:52 -05003931 hci_req_init(&req, hdev);
3932
Johan Hedberg70da6242013-03-15 17:06:51 -05003933 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3934 !lmp_host_ssp_capable(hdev)) {
3935 u8 ssp = 1;
3936
Johan Hedberg890ea892013-03-15 17:06:52 -05003937 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003938 }
3939
Johan Hedbergc73eee92013-04-19 18:35:21 +03003940 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3941 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003942 struct hci_cp_write_le_host_supported cp;
3943
3944 cp.le = 1;
3945 cp.simul = lmp_le_br_capable(hdev);
3946
3947 /* Check first if we already have the right
3948 * host state (host features set)
3949 */
3950 if (cp.le != lmp_host_le_capable(hdev) ||
3951 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003952 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3953 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003954
3955 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3956 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003957 }
3958
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003959 if (lmp_le_capable(hdev)) {
3960 /* Set random address to static address if configured */
3961 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3962 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3963 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003964
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003965 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3966 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003967 }
3968
Johan Hedberg70da6242013-03-15 17:06:51 -05003969 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3970 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003971 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3972 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003973
3974 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003975 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3976 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003977 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003978 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003979 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003980 }
3981
Johan Hedberg229ab392013-03-15 17:06:53 -05003982 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003983}
3984
Johan Hedberg744cf192011-11-08 20:40:14 +02003985int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003986{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003987 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003988 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3989 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003990 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003991
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003992 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3993 return 0;
3994
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003995 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003996 if (powered_update_hci(hdev) == 0)
3997 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003998
Johan Hedberg229ab392013-03-15 17:06:53 -05003999 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4000 &match);
4001 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004002 }
4003
Johan Hedberg229ab392013-03-15 17:06:53 -05004004 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4005 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4006
4007 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4008 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4009 zero_cod, sizeof(zero_cod), NULL);
4010
4011new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004012 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004013
4014 if (match.sk)
4015 sock_put(match.sk);
4016
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004017 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004018}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004019
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004020void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004021{
4022 struct pending_cmd *cmd;
4023 u8 status;
4024
4025 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4026 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004027 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004028
4029 if (err == -ERFKILL)
4030 status = MGMT_STATUS_RFKILLED;
4031 else
4032 status = MGMT_STATUS_FAILED;
4033
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004034 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004035
4036 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004037}
4038
Johan Hedberg744cf192011-11-08 20:40:14 +02004039int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004040{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004041 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004042 bool changed = false;
4043 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004044
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004045 if (discoverable) {
4046 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4047 changed = true;
4048 } else {
4049 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4050 changed = true;
4051 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004052
Johan Hedberged9b5f22012-02-21 20:47:06 +02004053 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004054 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004055
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004056 if (changed)
4057 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004058
Johan Hedberg73f22f62010-12-29 16:00:25 +02004059 if (match.sk)
4060 sock_put(match.sk);
4061
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004062 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004063}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004064
Johan Hedberg744cf192011-11-08 20:40:14 +02004065int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004066{
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004067 bool changed = false;
4068 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004069
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004070 /* Nothing needed here if there's a pending command since that
4071 * commands request completion callback takes care of everything
4072 * necessary.
4073 */
4074 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
4075 return 0;
4076
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004077 if (connectable) {
4078 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4079 changed = true;
4080 } else {
4081 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4082 changed = true;
4083 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004084
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004085 if (changed)
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004086 err = new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004087
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004088 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004089}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004090
Johan Hedberg744cf192011-11-08 20:40:14 +02004091int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004092{
Johan Hedbergca69b792011-11-11 18:10:00 +02004093 u8 mgmt_err = mgmt_status(status);
4094
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004095 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004096 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004097 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004098
4099 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004100 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004101 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004102
4103 return 0;
4104}
4105
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004106int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4107 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004108{
Johan Hedberg86742e12011-11-07 23:13:38 +02004109 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004110
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004111 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004112
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004113 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004114 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004115 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004116 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004117 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004118 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004119
Johan Hedberg744cf192011-11-08 20:40:14 +02004120 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004121}
Johan Hedbergf7520542011-01-20 12:34:39 +02004122
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004123int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4124{
4125 struct mgmt_ev_new_long_term_key ev;
4126
4127 memset(&ev, 0, sizeof(ev));
4128
4129 ev.store_hint = persistent;
4130 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004131 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004132 ev.key.authenticated = key->authenticated;
4133 ev.key.enc_size = key->enc_size;
4134 ev.key.ediv = key->ediv;
4135
4136 if (key->type == HCI_SMP_LTK)
4137 ev.key.master = 1;
4138
4139 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4140 memcpy(ev.key.val, key->val, sizeof(key->val));
4141
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004142 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4143 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004144}
4145
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004146void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4147 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4148 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004149{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004150 char buf[512];
4151 struct mgmt_ev_device_connected *ev = (void *) buf;
4152 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004153
Johan Hedbergb644ba32012-01-17 21:48:47 +02004154 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004155 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004156
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004157 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004158
Johan Hedbergb644ba32012-01-17 21:48:47 +02004159 if (name_len > 0)
4160 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004161 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004162
4163 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004164 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004165 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004166
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004167 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004168
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004169 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4170 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004171}
4172
Johan Hedberg8962ee72011-01-20 12:40:27 +02004173static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4174{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004175 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004176 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004177 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004178
Johan Hedberg88c3df12012-02-09 14:27:38 +02004179 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4180 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004181
Johan Hedbergaee9b212012-02-18 15:07:59 +02004182 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004183 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004184
4185 *sk = cmd->sk;
4186 sock_hold(*sk);
4187
Johan Hedberga664b5b2011-02-19 12:06:02 -03004188 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004189}
4190
Johan Hedberg124f6e32012-02-09 13:50:12 +02004191static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004192{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004193 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004194 struct mgmt_cp_unpair_device *cp = cmd->param;
4195 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004196
4197 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004198 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4199 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004200
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004201 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4202
Johan Hedbergaee9b212012-02-18 15:07:59 +02004203 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004204
4205 mgmt_pending_remove(cmd);
4206}
4207
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004208void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4209 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004210{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004211 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004212 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004213
Johan Hedberg744cf192011-11-08 20:40:14 +02004214 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004215
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004216 bacpy(&ev.addr.bdaddr, bdaddr);
4217 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4218 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004219
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004220 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004221
4222 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004223 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004224
Johan Hedberg124f6e32012-02-09 13:50:12 +02004225 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004226 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004227}
4228
Marcel Holtmann78929242013-10-06 23:55:47 -07004229void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4230 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004231{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004232 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004233 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004234
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004235 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4236 hdev);
4237
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004238 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004239 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004240 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004241
Johan Hedberg88c3df12012-02-09 14:27:38 +02004242 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004243 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004244
Marcel Holtmann78929242013-10-06 23:55:47 -07004245 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4246 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004247
Johan Hedberga664b5b2011-02-19 12:06:02 -03004248 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004249}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004250
Marcel Holtmann445608d2013-10-06 23:55:48 -07004251void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4252 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004253{
4254 struct mgmt_ev_connect_failed ev;
4255
Johan Hedberg4c659c32011-11-07 23:13:39 +02004256 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004257 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004258 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004259
Marcel Holtmann445608d2013-10-06 23:55:48 -07004260 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004261}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004262
Johan Hedberg744cf192011-11-08 20:40:14 +02004263int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004264{
4265 struct mgmt_ev_pin_code_request ev;
4266
Johan Hedbergd8457692012-02-17 14:24:57 +02004267 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004268 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004269 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004270
Johan Hedberg744cf192011-11-08 20:40:14 +02004271 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004272 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004273}
4274
Johan Hedberg744cf192011-11-08 20:40:14 +02004275int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004276 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004277{
4278 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004279 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004280 int err;
4281
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004282 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004283 if (!cmd)
4284 return -ENOENT;
4285
Johan Hedbergd8457692012-02-17 14:24:57 +02004286 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004287 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004288
Johan Hedbergaee9b212012-02-18 15:07:59 +02004289 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004290 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004291
Johan Hedberga664b5b2011-02-19 12:06:02 -03004292 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004293
4294 return err;
4295}
4296
Johan Hedberg744cf192011-11-08 20:40:14 +02004297int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004298 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004299{
4300 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004301 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004302 int err;
4303
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004304 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004305 if (!cmd)
4306 return -ENOENT;
4307
Johan Hedbergd8457692012-02-17 14:24:57 +02004308 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004309 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004310
Johan Hedbergaee9b212012-02-18 15:07:59 +02004311 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004312 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004313
Johan Hedberga664b5b2011-02-19 12:06:02 -03004314 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004315
4316 return err;
4317}
Johan Hedberga5c29682011-02-19 12:05:57 -03004318
Johan Hedberg744cf192011-11-08 20:40:14 +02004319int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004320 u8 link_type, u8 addr_type, __le32 value,
4321 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004322{
4323 struct mgmt_ev_user_confirm_request ev;
4324
Johan Hedberg744cf192011-11-08 20:40:14 +02004325 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004326
Johan Hedberg272d90d2012-02-09 15:26:12 +02004327 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004328 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004329 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004330 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004331
Johan Hedberg744cf192011-11-08 20:40:14 +02004332 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004333 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004334}
4335
Johan Hedberg272d90d2012-02-09 15:26:12 +02004336int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004337 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004338{
4339 struct mgmt_ev_user_passkey_request ev;
4340
4341 BT_DBG("%s", hdev->name);
4342
Johan Hedberg272d90d2012-02-09 15:26:12 +02004343 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004344 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004345
4346 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004347 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004348}
4349
Brian Gix0df4c182011-11-16 13:53:13 -08004350static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004351 u8 link_type, u8 addr_type, u8 status,
4352 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004353{
4354 struct pending_cmd *cmd;
4355 struct mgmt_rp_user_confirm_reply rp;
4356 int err;
4357
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004358 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004359 if (!cmd)
4360 return -ENOENT;
4361
Johan Hedberg272d90d2012-02-09 15:26:12 +02004362 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004363 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004364 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004365 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004366
Johan Hedberga664b5b2011-02-19 12:06:02 -03004367 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004368
4369 return err;
4370}
4371
Johan Hedberg744cf192011-11-08 20:40:14 +02004372int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004373 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004374{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004375 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004376 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004377}
4378
Johan Hedberg272d90d2012-02-09 15:26:12 +02004379int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004380 u8 link_type, u8 addr_type, u8 status)
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 Padovan8fc9ced2012-05-23 04:04:21 -03004383 status,
4384 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004385}
Johan Hedberg2a611692011-02-19 12:06:00 -03004386
Brian Gix604086b2011-11-23 08:28:33 -08004387int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004388 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004389{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004390 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004391 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004392}
4393
Johan Hedberg272d90d2012-02-09 15:26:12 +02004394int mgmt_user_passkey_neg_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 Padovan8fc9ced2012-05-23 04:04:21 -03004398 status,
4399 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004400}
4401
Johan Hedberg92a25252012-09-06 18:39:26 +03004402int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4403 u8 link_type, u8 addr_type, u32 passkey,
4404 u8 entered)
4405{
4406 struct mgmt_ev_passkey_notify ev;
4407
4408 BT_DBG("%s", hdev->name);
4409
4410 bacpy(&ev.addr.bdaddr, bdaddr);
4411 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4412 ev.passkey = __cpu_to_le32(passkey);
4413 ev.entered = entered;
4414
4415 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4416}
4417
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004418int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004419 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004420{
4421 struct mgmt_ev_auth_failed ev;
4422
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004423 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004424 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004425 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004426
Johan Hedberg744cf192011-11-08 20:40:14 +02004427 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004428}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004429
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004430int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4431{
4432 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004433 bool changed = false;
4434 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004435
4436 if (status) {
4437 u8 mgmt_err = mgmt_status(status);
4438 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004439 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004440 return 0;
4441 }
4442
Johan Hedberg47990ea2012-02-22 11:58:37 +02004443 if (test_bit(HCI_AUTH, &hdev->flags)) {
4444 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4445 changed = true;
4446 } else {
4447 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4448 changed = true;
4449 }
4450
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004451 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004452 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004453
Johan Hedberg47990ea2012-02-22 11:58:37 +02004454 if (changed)
4455 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004456
4457 if (match.sk)
4458 sock_put(match.sk);
4459
4460 return err;
4461}
4462
Johan Hedberg890ea892013-03-15 17:06:52 -05004463static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004464{
Johan Hedberg890ea892013-03-15 17:06:52 -05004465 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004466 struct hci_cp_write_eir cp;
4467
Johan Hedberg976eb202012-10-24 21:12:01 +03004468 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004469 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004470
Johan Hedbergc80da272012-02-22 15:38:48 +02004471 memset(hdev->eir, 0, sizeof(hdev->eir));
4472
Johan Hedbergcacaf522012-02-21 00:52:42 +02004473 memset(&cp, 0, sizeof(cp));
4474
Johan Hedberg890ea892013-03-15 17:06:52 -05004475 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004476}
4477
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004478int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004479{
4480 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004481 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004482 bool changed = false;
4483 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004484
4485 if (status) {
4486 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004487
4488 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004489 &hdev->dev_flags)) {
4490 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004491 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004492 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004493
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004494 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4495 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004496
4497 return err;
4498 }
4499
4500 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004501 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004502 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004503 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4504 if (!changed)
4505 changed = test_and_clear_bit(HCI_HS_ENABLED,
4506 &hdev->dev_flags);
4507 else
4508 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004509 }
4510
4511 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4512
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004513 if (changed)
4514 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004515
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004516 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004517 sock_put(match.sk);
4518
Johan Hedberg890ea892013-03-15 17:06:52 -05004519 hci_req_init(&req, hdev);
4520
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004521 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004522 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004523 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004524 clear_eir(&req);
4525
4526 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004527
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004528 return err;
4529}
4530
Johan Hedberg92da6092013-03-15 17:06:55 -05004531static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004532{
4533 struct cmd_lookup *match = data;
4534
Johan Hedberg90e70452012-02-23 23:09:40 +02004535 if (match->sk == NULL) {
4536 match->sk = cmd->sk;
4537 sock_hold(match->sk);
4538 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004539}
4540
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004541int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004542 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004543{
Johan Hedberg90e70452012-02-23 23:09:40 +02004544 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4545 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004546
Johan Hedberg92da6092013-03-15 17:06:55 -05004547 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4548 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4549 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004550
4551 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004552 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4553 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004554
4555 if (match.sk)
4556 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004557
4558 return err;
4559}
4560
Johan Hedberg744cf192011-11-08 20:40:14 +02004561int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004562{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004563 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004564 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004565
Johan Hedberg13928972013-03-15 17:07:00 -05004566 if (status)
4567 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004568
4569 memset(&ev, 0, sizeof(ev));
4570 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004571 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004572
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004573 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004574 if (!cmd) {
4575 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004576
Johan Hedberg13928972013-03-15 17:07:00 -05004577 /* If this is a HCI command related to powering on the
4578 * HCI dev don't send any mgmt signals.
4579 */
4580 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4581 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004582 }
4583
Johan Hedberg13928972013-03-15 17:07:00 -05004584 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4585 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004586}
Szymon Jancc35938b2011-03-22 13:12:21 +01004587
Johan Hedberg744cf192011-11-08 20:40:14 +02004588int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004589 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004590{
4591 struct pending_cmd *cmd;
4592 int err;
4593
Johan Hedberg744cf192011-11-08 20:40:14 +02004594 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004595
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004596 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004597 if (!cmd)
4598 return -ENOENT;
4599
4600 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004601 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4602 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004603 } else {
4604 struct mgmt_rp_read_local_oob_data rp;
4605
4606 memcpy(rp.hash, hash, sizeof(rp.hash));
4607 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4608
Johan Hedberg744cf192011-11-08 20:40:14 +02004609 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004610 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4611 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004612 }
4613
4614 mgmt_pending_remove(cmd);
4615
4616 return err;
4617}
Johan Hedberge17acd42011-03-30 23:57:16 +03004618
Marcel Holtmann901801b2013-10-06 23:55:51 -07004619void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4620 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4621 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004622{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004623 char buf[512];
4624 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004625 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004626
Andre Guedes12602d02013-04-30 15:29:40 -03004627 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004628 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004629
Johan Hedberg1dc06092012-01-15 21:01:23 +02004630 /* Leave 5 bytes for a potential CoD field */
4631 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004632 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004633
Johan Hedberg1dc06092012-01-15 21:01:23 +02004634 memset(buf, 0, sizeof(buf));
4635
Johan Hedberge319d2e2012-01-15 19:51:59 +02004636 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004637 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004638 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004639 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304640 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004641 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304642 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004643
Johan Hedberg1dc06092012-01-15 21:01:23 +02004644 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004645 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004646
Johan Hedberg1dc06092012-01-15 21:01:23 +02004647 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4648 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004649 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004650
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004651 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004652 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004653
Marcel Holtmann901801b2013-10-06 23:55:51 -07004654 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004655}
Johan Hedberga88a9652011-03-30 13:18:12 +03004656
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004657void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4658 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004659{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004660 struct mgmt_ev_device_found *ev;
4661 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4662 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004663
Johan Hedbergb644ba32012-01-17 21:48:47 +02004664 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004665
Johan Hedbergb644ba32012-01-17 21:48:47 +02004666 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004667
Johan Hedbergb644ba32012-01-17 21:48:47 +02004668 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004669 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004670 ev->rssi = rssi;
4671
4672 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004673 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004674
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004675 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004676
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004677 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004678}
Johan Hedberg314b2382011-04-27 10:29:57 -04004679
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004680void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004681{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004682 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004683 struct pending_cmd *cmd;
4684
Andre Guedes343fb142011-11-22 17:14:19 -03004685 BT_DBG("%s discovering %u", hdev->name, discovering);
4686
Johan Hedberg164a6e72011-11-01 17:06:44 +02004687 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004688 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004689 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004690 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004691
4692 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004693 u8 type = hdev->discovery.type;
4694
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004695 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4696 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004697 mgmt_pending_remove(cmd);
4698 }
4699
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004700 memset(&ev, 0, sizeof(ev));
4701 ev.type = hdev->discovery.type;
4702 ev.discovering = discovering;
4703
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004704 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004705}
Antti Julku5e762442011-08-25 16:48:02 +03004706
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004707int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004708{
4709 struct pending_cmd *cmd;
4710 struct mgmt_ev_device_blocked ev;
4711
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004712 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004713
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004714 bacpy(&ev.addr.bdaddr, bdaddr);
4715 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004716
Johan Hedberg744cf192011-11-08 20:40:14 +02004717 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004718 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004719}
4720
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004721int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004722{
4723 struct pending_cmd *cmd;
4724 struct mgmt_ev_device_unblocked ev;
4725
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004726 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004727
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004728 bacpy(&ev.addr.bdaddr, bdaddr);
4729 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004730
Johan Hedberg744cf192011-11-08 20:40:14 +02004731 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004732 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004733}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004734
4735static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4736{
4737 BT_DBG("%s status %u", hdev->name, status);
4738
4739 /* Clear the advertising mgmt setting if we failed to re-enable it */
4740 if (status) {
4741 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004742 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004743 }
4744}
4745
4746void mgmt_reenable_advertising(struct hci_dev *hdev)
4747{
4748 struct hci_request req;
4749
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004750 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004751 return;
4752
4753 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4754 return;
4755
4756 hci_req_init(&req, hdev);
4757 enable_advertising(&req);
4758
4759 /* If this fails we have no option but to let user space know
4760 * that we've disabled advertising.
4761 */
4762 if (hci_req_run(&req, adv_enable_complete) < 0) {
4763 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004764 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004765 }
4766}