blob: f57ec19547afc47ff8d46c365ba7ce287c7693a1 [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,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020081};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300104 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200105};
106
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800107#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200108
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200109#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
110 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
111
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200112struct pending_cmd {
113 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200114 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200115 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100116 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300118 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200119};
120
Johan Hedbergca69b792011-11-11 18:10:00 +0200121/* HCI to MGMT error code conversion table */
122static u8 mgmt_status_table[] = {
123 MGMT_STATUS_SUCCESS,
124 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
125 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
126 MGMT_STATUS_FAILED, /* Hardware Failure */
127 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
128 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
129 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
130 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
131 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
132 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
133 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
134 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
135 MGMT_STATUS_BUSY, /* Command Disallowed */
136 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
137 MGMT_STATUS_REJECTED, /* Rejected Security */
138 MGMT_STATUS_REJECTED, /* Rejected Personal */
139 MGMT_STATUS_TIMEOUT, /* Host Timeout */
140 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
141 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
142 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
143 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
144 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
145 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
146 MGMT_STATUS_BUSY, /* Repeated Attempts */
147 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
148 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
149 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
150 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
151 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
152 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
154 MGMT_STATUS_FAILED, /* Unspecified Error */
155 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
156 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
157 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
158 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
159 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
160 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
161 MGMT_STATUS_FAILED, /* Unit Link Key Used */
162 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
163 MGMT_STATUS_TIMEOUT, /* Instant Passed */
164 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
165 MGMT_STATUS_FAILED, /* Transaction Collision */
166 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
167 MGMT_STATUS_REJECTED, /* QoS Rejected */
168 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
169 MGMT_STATUS_REJECTED, /* Insufficient Security */
170 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
171 MGMT_STATUS_BUSY, /* Role Switch Pending */
172 MGMT_STATUS_FAILED, /* Slot Violation */
173 MGMT_STATUS_FAILED, /* Role Switch Failed */
174 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
175 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
176 MGMT_STATUS_BUSY, /* Host Busy Pairing */
177 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
178 MGMT_STATUS_BUSY, /* Controller Busy */
179 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
180 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
181 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
182 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
183 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
184};
185
186static u8 mgmt_status(u8 hci_status)
187{
188 if (hci_status < ARRAY_SIZE(mgmt_status_table))
189 return mgmt_status_table[hci_status];
190
191 return MGMT_STATUS_FAILED;
192}
193
Szymon Janc4e51eae2011-02-25 19:05:48 +0100194static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200195{
196 struct sk_buff *skb;
197 struct mgmt_hdr *hdr;
198 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300199 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200200
Szymon Janc34eb5252011-02-28 14:10:08 +0100201 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200202
Andre Guedes790eff42012-06-07 19:05:46 -0300203 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200204 if (!skb)
205 return -ENOMEM;
206
207 hdr = (void *) skb_put(skb, sizeof(*hdr));
208
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530209 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100210 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200211 hdr->len = cpu_to_le16(sizeof(*ev));
212
213 ev = (void *) skb_put(skb, sizeof(*ev));
214 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200215 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200216
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300217 err = sock_queue_rcv_skb(sk, skb);
218 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200219 kfree_skb(skb);
220
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300221 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200222}
223
Johan Hedbergaee9b212012-02-18 15:07:59 +0200224static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300225 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200226{
227 struct sk_buff *skb;
228 struct mgmt_hdr *hdr;
229 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300230 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200231
232 BT_DBG("sock %p", sk);
233
Andre Guedes790eff42012-06-07 19:05:46 -0300234 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200235 if (!skb)
236 return -ENOMEM;
237
238 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200239
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530240 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100241 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200242 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200245 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200246 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100247
248 if (rp)
249 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200250
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300251 err = sock_queue_rcv_skb(sk, skb);
252 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200253 kfree_skb(skb);
254
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100255 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200256}
257
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300258static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
259 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200260{
261 struct mgmt_rp_read_version rp;
262
263 BT_DBG("sock %p", sk);
264
265 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200266 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200267
Johan Hedbergaee9b212012-02-18 15:07:59 +0200268 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300269 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200270}
271
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300272static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
273 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200274{
275 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200276 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
277 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200278 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200279 size_t rp_size;
280 int i, err;
281
282 BT_DBG("sock %p", sk);
283
284 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
285
286 rp = kmalloc(rp_size, GFP_KERNEL);
287 if (!rp)
288 return -ENOMEM;
289
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200290 rp->num_commands = __constant_cpu_to_le16(num_commands);
291 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200292
293 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
294 put_unaligned_le16(mgmt_commands[i], opcode);
295
296 for (i = 0; i < num_events; i++, opcode++)
297 put_unaligned_le16(mgmt_events[i], opcode);
298
Johan Hedbergaee9b212012-02-18 15:07:59 +0200299 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300300 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200301 kfree(rp);
302
303 return err;
304}
305
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300306static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
307 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200308{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200309 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200310 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200311 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300313 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200314
315 BT_DBG("sock %p", sk);
316
317 read_lock(&hci_dev_list_lock);
318
319 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300320 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700321 if (d->dev_type == HCI_BREDR)
322 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200323 }
324
Johan Hedberga38528f2011-01-22 06:46:43 +0200325 rp_len = sizeof(*rp) + (2 * count);
326 rp = kmalloc(rp_len, GFP_ATOMIC);
327 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100328 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200329 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100330 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200331
Johan Hedberg476e44c2012-10-19 20:10:46 +0300332 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200333 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200334 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200335 continue;
336
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700337 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
338 continue;
339
Marcel Holtmann1514b892013-10-06 08:25:01 -0700340 if (d->dev_type == HCI_BREDR) {
341 rp->index[count++] = cpu_to_le16(d->id);
342 BT_DBG("Added hci%u", d->id);
343 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200344 }
345
Johan Hedberg476e44c2012-10-19 20:10:46 +0300346 rp->num_controllers = cpu_to_le16(count);
347 rp_len = sizeof(*rp) + (2 * count);
348
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 read_unlock(&hci_dev_list_lock);
350
Johan Hedbergaee9b212012-02-18 15:07:59 +0200351 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300352 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200353
Johan Hedberga38528f2011-01-22 06:46:43 +0200354 kfree(rp);
355
356 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200357}
358
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200359static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200360{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200361 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200362
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200363 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Andre Guedes9a1a1992012-07-24 15:03:48 -0300366 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200368
Andre Guedesed3fa312012-07-24 15:03:46 -0300369 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300370 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500371 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
372 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300373 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200374 settings |= MGMT_SETTING_BREDR;
375 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100376 settings |= MGMT_SETTING_HS;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700377 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100378
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300379 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200380 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300381 settings |= MGMT_SETTING_ADVERTISING;
382 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200383
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200384 return settings;
385}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200386
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200387static u32 get_current_settings(struct hci_dev *hdev)
388{
389 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200390
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200391 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100392 settings |= MGMT_SETTING_POWERED;
393
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200394 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200395 settings |= MGMT_SETTING_CONNECTABLE;
396
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500397 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
398 settings |= MGMT_SETTING_FAST_CONNECTABLE;
399
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200400 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401 settings |= MGMT_SETTING_DISCOVERABLE;
402
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200403 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200404 settings |= MGMT_SETTING_PAIRABLE;
405
Johan Hedberg56f87902013-10-02 13:43:13 +0300406 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200407 settings |= MGMT_SETTING_BREDR;
408
Johan Hedberg06199cf2012-02-22 16:37:11 +0200409 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200411
Johan Hedberg47990ea2012-02-22 11:58:37 +0200412 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200414
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200415 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200417
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200418 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
419 settings |= MGMT_SETTING_HS;
420
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200421 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300422 settings |= MGMT_SETTING_ADVERTISING;
423
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200424 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200425}
426
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300427#define PNP_INFO_SVCLASS_ID 0x1200
428
Johan Hedberg213202e2013-01-27 00:31:33 +0200429static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
430{
431 u8 *ptr = data, *uuids_start = NULL;
432 struct bt_uuid *uuid;
433
434 if (len < 4)
435 return ptr;
436
437 list_for_each_entry(uuid, &hdev->uuids, list) {
438 u16 uuid16;
439
440 if (uuid->size != 16)
441 continue;
442
443 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
444 if (uuid16 < 0x1100)
445 continue;
446
447 if (uuid16 == PNP_INFO_SVCLASS_ID)
448 continue;
449
450 if (!uuids_start) {
451 uuids_start = ptr;
452 uuids_start[0] = 1;
453 uuids_start[1] = EIR_UUID16_ALL;
454 ptr += 2;
455 }
456
457 /* Stop if not enough space to put next UUID */
458 if ((ptr - data) + sizeof(u16) > len) {
459 uuids_start[1] = EIR_UUID16_SOME;
460 break;
461 }
462
463 *ptr++ = (uuid16 & 0x00ff);
464 *ptr++ = (uuid16 & 0xff00) >> 8;
465 uuids_start[0] += sizeof(uuid16);
466 }
467
468 return ptr;
469}
470
Johan Hedbergcdf19632013-01-27 00:31:34 +0200471static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
472{
473 u8 *ptr = data, *uuids_start = NULL;
474 struct bt_uuid *uuid;
475
476 if (len < 6)
477 return ptr;
478
479 list_for_each_entry(uuid, &hdev->uuids, list) {
480 if (uuid->size != 32)
481 continue;
482
483 if (!uuids_start) {
484 uuids_start = ptr;
485 uuids_start[0] = 1;
486 uuids_start[1] = EIR_UUID32_ALL;
487 ptr += 2;
488 }
489
490 /* Stop if not enough space to put next UUID */
491 if ((ptr - data) + sizeof(u32) > len) {
492 uuids_start[1] = EIR_UUID32_SOME;
493 break;
494 }
495
496 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
497 ptr += sizeof(u32);
498 uuids_start[0] += sizeof(u32);
499 }
500
501 return ptr;
502}
503
Johan Hedbergc00d5752013-01-27 00:31:35 +0200504static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
505{
506 u8 *ptr = data, *uuids_start = NULL;
507 struct bt_uuid *uuid;
508
509 if (len < 18)
510 return ptr;
511
512 list_for_each_entry(uuid, &hdev->uuids, list) {
513 if (uuid->size != 128)
514 continue;
515
516 if (!uuids_start) {
517 uuids_start = ptr;
518 uuids_start[0] = 1;
519 uuids_start[1] = EIR_UUID128_ALL;
520 ptr += 2;
521 }
522
523 /* Stop if not enough space to put next UUID */
524 if ((ptr - data) + 16 > len) {
525 uuids_start[1] = EIR_UUID128_SOME;
526 break;
527 }
528
529 memcpy(ptr, uuid->uuid, 16);
530 ptr += 16;
531 uuids_start[0] += 16;
532 }
533
534 return ptr;
535}
536
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300537static void create_eir(struct hci_dev *hdev, u8 *data)
538{
539 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300540 size_t name_len;
541
542 name_len = strlen(hdev->dev_name);
543
544 if (name_len > 0) {
545 /* EIR Data type */
546 if (name_len > 48) {
547 name_len = 48;
548 ptr[1] = EIR_NAME_SHORT;
549 } else
550 ptr[1] = EIR_NAME_COMPLETE;
551
552 /* EIR Data length */
553 ptr[0] = name_len + 1;
554
555 memcpy(ptr + 2, hdev->dev_name, name_len);
556
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300557 ptr += (name_len + 2);
558 }
559
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100560 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700561 ptr[0] = 2;
562 ptr[1] = EIR_TX_POWER;
563 ptr[2] = (u8) hdev->inq_tx_power;
564
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700565 ptr += 3;
566 }
567
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700568 if (hdev->devid_source > 0) {
569 ptr[0] = 9;
570 ptr[1] = EIR_DEVICE_ID;
571
572 put_unaligned_le16(hdev->devid_source, ptr + 2);
573 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
574 put_unaligned_le16(hdev->devid_product, ptr + 6);
575 put_unaligned_le16(hdev->devid_version, ptr + 8);
576
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700577 ptr += 10;
578 }
579
Johan Hedberg213202e2013-01-27 00:31:33 +0200580 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200581 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200582 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300583}
584
Johan Hedberg890ea892013-03-15 17:06:52 -0500585static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300586{
Johan Hedberg890ea892013-03-15 17:06:52 -0500587 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300588 struct hci_cp_write_eir cp;
589
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200590 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500591 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200592
Johan Hedberg976eb202012-10-24 21:12:01 +0300593 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500594 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300595
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200596 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500597 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300598
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200599 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500600 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300601
602 memset(&cp, 0, sizeof(cp));
603
604 create_eir(hdev, cp.data);
605
606 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500607 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300608
609 memcpy(hdev->eir, cp.data, sizeof(cp.data));
610
Johan Hedberg890ea892013-03-15 17:06:52 -0500611 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300612}
613
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200614static u8 get_service_classes(struct hci_dev *hdev)
615{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300616 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200617 u8 val = 0;
618
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300619 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200620 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200621
622 return val;
623}
624
Johan Hedberg890ea892013-03-15 17:06:52 -0500625static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200626{
Johan Hedberg890ea892013-03-15 17:06:52 -0500627 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200628 u8 cod[3];
629
630 BT_DBG("%s", hdev->name);
631
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200632 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500633 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200634
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200635 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500636 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200637
638 cod[0] = hdev->minor_class;
639 cod[1] = hdev->major_class;
640 cod[2] = get_service_classes(hdev);
641
642 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500643 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200644
Johan Hedberg890ea892013-03-15 17:06:52 -0500645 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200646}
647
Johan Hedberg7d785252011-12-15 00:47:39 +0200648static void service_cache_off(struct work_struct *work)
649{
650 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300651 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500652 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200653
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200654 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200655 return;
656
Johan Hedberg890ea892013-03-15 17:06:52 -0500657 hci_req_init(&req, hdev);
658
Johan Hedberg7d785252011-12-15 00:47:39 +0200659 hci_dev_lock(hdev);
660
Johan Hedberg890ea892013-03-15 17:06:52 -0500661 update_eir(&req);
662 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200663
664 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500665
666 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200667}
668
Johan Hedberg6a919082012-02-28 06:17:26 +0200669static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200670{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200671 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200672 return;
673
Johan Hedberg4f87da82012-03-02 19:55:56 +0200674 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200675
Johan Hedberg4f87da82012-03-02 19:55:56 +0200676 /* Non-mgmt controlled devices get this bit set
677 * implicitly so that pairing works for them, however
678 * for mgmt we require user-space to explicitly enable
679 * it
680 */
681 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200682}
683
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200684static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300685 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200686{
687 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200688
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200689 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200690
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300691 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200692
Johan Hedberg03811012010-12-08 00:21:06 +0200693 memset(&rp, 0, sizeof(rp));
694
Johan Hedberg03811012010-12-08 00:21:06 +0200695 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200696
697 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200698 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200699
700 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
701 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
702
703 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200704
705 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200706 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200707
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300708 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200709
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200710 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300711 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200712}
713
714static void mgmt_pending_free(struct pending_cmd *cmd)
715{
716 sock_put(cmd->sk);
717 kfree(cmd->param);
718 kfree(cmd);
719}
720
721static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300722 struct hci_dev *hdev, void *data,
723 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200724{
725 struct pending_cmd *cmd;
726
Andre Guedes12b94562012-06-07 19:05:45 -0300727 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200728 if (!cmd)
729 return NULL;
730
731 cmd->opcode = opcode;
732 cmd->index = hdev->id;
733
Andre Guedes12b94562012-06-07 19:05:45 -0300734 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200735 if (!cmd->param) {
736 kfree(cmd);
737 return NULL;
738 }
739
740 if (data)
741 memcpy(cmd->param, data, len);
742
743 cmd->sk = sk;
744 sock_hold(sk);
745
746 list_add(&cmd->list, &hdev->mgmt_pending);
747
748 return cmd;
749}
750
751static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300752 void (*cb)(struct pending_cmd *cmd,
753 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300754 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200755{
Andre Guedesa3d09352013-02-01 11:21:30 -0300756 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200757
Andre Guedesa3d09352013-02-01 11:21:30 -0300758 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200759 if (opcode > 0 && cmd->opcode != opcode)
760 continue;
761
762 cb(cmd, data);
763 }
764}
765
766static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
767{
768 struct pending_cmd *cmd;
769
770 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
771 if (cmd->opcode == opcode)
772 return cmd;
773 }
774
775 return NULL;
776}
777
778static void mgmt_pending_remove(struct pending_cmd *cmd)
779{
780 list_del(&cmd->list);
781 mgmt_pending_free(cmd);
782}
783
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200784static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200785{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200786 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200787
Johan Hedbergaee9b212012-02-18 15:07:59 +0200788 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300789 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200790}
791
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200792static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300793 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200794{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300795 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200796 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200797 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200798
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200799 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200800
Johan Hedberga7e80f22013-01-09 16:05:19 +0200801 if (cp->val != 0x00 && cp->val != 0x01)
802 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
803 MGMT_STATUS_INVALID_PARAMS);
804
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300805 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200806
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300807 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
808 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
809 MGMT_STATUS_BUSY);
810 goto failed;
811 }
812
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100813 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
814 cancel_delayed_work(&hdev->power_off);
815
816 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200817 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
818 data, len);
819 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100820 goto failed;
821 }
822 }
823
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200824 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200825 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200826 goto failed;
827 }
828
Johan Hedberg03811012010-12-08 00:21:06 +0200829 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
830 if (!cmd) {
831 err = -ENOMEM;
832 goto failed;
833 }
834
835 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200836 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200837 else
Johan Hedberg19202572013-01-14 22:33:51 +0200838 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200839
840 err = 0;
841
842failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300843 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200844 return err;
845}
846
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300847static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
848 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200849{
850 struct sk_buff *skb;
851 struct mgmt_hdr *hdr;
852
Andre Guedes790eff42012-06-07 19:05:46 -0300853 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200854 if (!skb)
855 return -ENOMEM;
856
857 hdr = (void *) skb_put(skb, sizeof(*hdr));
858 hdr->opcode = cpu_to_le16(event);
859 if (hdev)
860 hdr->index = cpu_to_le16(hdev->id);
861 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530862 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200863 hdr->len = cpu_to_le16(data_len);
864
865 if (data)
866 memcpy(skb_put(skb, data_len), data, data_len);
867
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100868 /* Time stamp */
869 __net_timestamp(skb);
870
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200871 hci_send_to_control(skb, skip_sk);
872 kfree_skb(skb);
873
874 return 0;
875}
876
877static int new_settings(struct hci_dev *hdev, struct sock *skip)
878{
879 __le32 ev;
880
881 ev = cpu_to_le32(get_current_settings(hdev));
882
883 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
884}
885
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300886struct cmd_lookup {
887 struct sock *sk;
888 struct hci_dev *hdev;
889 u8 mgmt_status;
890};
891
892static void settings_rsp(struct pending_cmd *cmd, void *data)
893{
894 struct cmd_lookup *match = data;
895
896 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
897
898 list_del(&cmd->list);
899
900 if (match->sk == NULL) {
901 match->sk = cmd->sk;
902 sock_hold(match->sk);
903 }
904
905 mgmt_pending_free(cmd);
906}
907
908static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
909{
910 u8 *status = data;
911
912 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
913 mgmt_pending_remove(cmd);
914}
915
Johan Hedberge6fe7982013-10-02 15:45:22 +0300916static u8 mgmt_bredr_support(struct hci_dev *hdev)
917{
918 if (!lmp_bredr_capable(hdev))
919 return MGMT_STATUS_NOT_SUPPORTED;
920 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
921 return MGMT_STATUS_REJECTED;
922 else
923 return MGMT_STATUS_SUCCESS;
924}
925
926static u8 mgmt_le_support(struct hci_dev *hdev)
927{
928 if (!lmp_le_capable(hdev))
929 return MGMT_STATUS_NOT_SUPPORTED;
930 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
931 return MGMT_STATUS_REJECTED;
932 else
933 return MGMT_STATUS_SUCCESS;
934}
935
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200936static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300937 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200938{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300939 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200940 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200941 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +0300942 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +0200943 int err;
944
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200945 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200946
Johan Hedberge6fe7982013-10-02 15:45:22 +0300947 status = mgmt_bredr_support(hdev);
948 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +0300949 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +0300950 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +0300951
Johan Hedberga7e80f22013-01-09 16:05:19 +0200952 if (cp->val != 0x00 && cp->val != 0x01)
953 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
954 MGMT_STATUS_INVALID_PARAMS);
955
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700956 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100957 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200958 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300959 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200960
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300961 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200962
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200963 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200964 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300965 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200966 goto failed;
967 }
968
969 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300970 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200971 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300972 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200973 goto failed;
974 }
975
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200976 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200977 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300978 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200979 goto failed;
980 }
981
982 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200983 bool changed = false;
984
985 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
986 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
987 changed = true;
988 }
989
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200990 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200991 if (err < 0)
992 goto failed;
993
994 if (changed)
995 err = new_settings(hdev, sk);
996
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200997 goto failed;
998 }
999
1000 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001001 if (hdev->discov_timeout > 0) {
1002 cancel_delayed_work(&hdev->discov_off);
1003 hdev->discov_timeout = 0;
1004 }
1005
1006 if (cp->val && timeout > 0) {
1007 hdev->discov_timeout = timeout;
1008 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1009 msecs_to_jiffies(hdev->discov_timeout * 1000));
1010 }
1011
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001012 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001013 goto failed;
1014 }
1015
1016 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1017 if (!cmd) {
1018 err = -ENOMEM;
1019 goto failed;
1020 }
1021
1022 scan = SCAN_PAGE;
1023
1024 if (cp->val)
1025 scan |= SCAN_INQUIRY;
1026 else
1027 cancel_delayed_work(&hdev->discov_off);
1028
1029 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1030 if (err < 0)
1031 mgmt_pending_remove(cmd);
1032
Johan Hedberg03811012010-12-08 00:21:06 +02001033 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001034 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001035
1036failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001037 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001038 return err;
1039}
1040
Johan Hedberg406d7802013-03-15 17:07:09 -05001041static void write_fast_connectable(struct hci_request *req, bool enable)
1042{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001043 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001044 struct hci_cp_write_page_scan_activity acp;
1045 u8 type;
1046
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001047 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1048 return;
1049
Johan Hedberg406d7802013-03-15 17:07:09 -05001050 if (enable) {
1051 type = PAGE_SCAN_TYPE_INTERLACED;
1052
1053 /* 160 msec page scan interval */
1054 acp.interval = __constant_cpu_to_le16(0x0100);
1055 } else {
1056 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1057
1058 /* default 1.28 sec page scan */
1059 acp.interval = __constant_cpu_to_le16(0x0800);
1060 }
1061
1062 acp.window = __constant_cpu_to_le16(0x0012);
1063
Johan Hedbergbd98b992013-03-15 17:07:13 -05001064 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1065 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1066 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1067 sizeof(acp), &acp);
1068
1069 if (hdev->page_scan_type != type)
1070 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001071}
1072
Johan Hedberg2b76f452013-03-15 17:07:04 -05001073static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1074{
1075 struct pending_cmd *cmd;
1076
1077 BT_DBG("status 0x%02x", status);
1078
1079 hci_dev_lock(hdev);
1080
1081 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1082 if (!cmd)
1083 goto unlock;
1084
1085 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1086
1087 mgmt_pending_remove(cmd);
1088
1089unlock:
1090 hci_dev_unlock(hdev);
1091}
1092
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001093static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001094 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001095{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001096 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001097 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001098 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001099 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001100 int err;
1101
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001102 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001103
Johan Hedberge6fe7982013-10-02 15:45:22 +03001104 status = mgmt_bredr_support(hdev);
1105 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001106 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001107 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001108
Johan Hedberga7e80f22013-01-09 16:05:19 +02001109 if (cp->val != 0x00 && cp->val != 0x01)
1110 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1111 MGMT_STATUS_INVALID_PARAMS);
1112
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001113 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001114
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001115 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001116 bool changed = false;
1117
1118 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1119 changed = true;
1120
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001121 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001122 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001123 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001124 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1125 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1126 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001127
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001128 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001129 if (err < 0)
1130 goto failed;
1131
1132 if (changed)
1133 err = new_settings(hdev, sk);
1134
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001135 goto failed;
1136 }
1137
1138 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001139 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001140 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001141 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001142 goto failed;
1143 }
1144
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001145 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001146 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001147 goto failed;
1148 }
1149
1150 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1151 if (!cmd) {
1152 err = -ENOMEM;
1153 goto failed;
1154 }
1155
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001156 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001157 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001158 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001159 scan = 0;
1160
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001161 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001162 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001163 cancel_delayed_work(&hdev->discov_off);
1164 }
1165
Johan Hedberg2b76f452013-03-15 17:07:04 -05001166 hci_req_init(&req, hdev);
1167
1168 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1169
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001170 /* If we're going from non-connectable to connectable or
1171 * vice-versa when fast connectable is enabled ensure that fast
1172 * connectable gets disabled. write_fast_connectable won't do
1173 * anything if the page scan parameters are already what they
1174 * should be.
1175 */
1176 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001177 write_fast_connectable(&req, false);
1178
Johan Hedberg2b76f452013-03-15 17:07:04 -05001179 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001180 if (err < 0)
1181 mgmt_pending_remove(cmd);
1182
1183failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001184 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001185 return err;
1186}
1187
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001188static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001189 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001190{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001191 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001192 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001193 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001195 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001196
Johan Hedberga7e80f22013-01-09 16:05:19 +02001197 if (cp->val != 0x00 && cp->val != 0x01)
1198 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1199 MGMT_STATUS_INVALID_PARAMS);
1200
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001201 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001202
1203 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001204 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001205 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001206 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001208 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001209 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001210 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001211
Marcel Holtmann55594352013-10-06 16:11:57 -07001212 if (changed)
1213 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001214
Marcel Holtmann55594352013-10-06 16:11:57 -07001215unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001216 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001217 return err;
1218}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001219
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001220static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1221 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001222{
1223 struct mgmt_mode *cp = data;
1224 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001225 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001226 int err;
1227
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001228 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001229
Johan Hedberge6fe7982013-10-02 15:45:22 +03001230 status = mgmt_bredr_support(hdev);
1231 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001232 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001233 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001234
Johan Hedberga7e80f22013-01-09 16:05:19 +02001235 if (cp->val != 0x00 && cp->val != 0x01)
1236 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1237 MGMT_STATUS_INVALID_PARAMS);
1238
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001239 hci_dev_lock(hdev);
1240
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001241 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001242 bool changed = false;
1243
1244 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001245 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001246 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1247 changed = true;
1248 }
1249
1250 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1251 if (err < 0)
1252 goto failed;
1253
1254 if (changed)
1255 err = new_settings(hdev, sk);
1256
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001257 goto failed;
1258 }
1259
1260 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001261 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001262 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001263 goto failed;
1264 }
1265
1266 val = !!cp->val;
1267
1268 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1269 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1270 goto failed;
1271 }
1272
1273 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1274 if (!cmd) {
1275 err = -ENOMEM;
1276 goto failed;
1277 }
1278
1279 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1280 if (err < 0) {
1281 mgmt_pending_remove(cmd);
1282 goto failed;
1283 }
1284
1285failed:
1286 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001287 return err;
1288}
1289
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001290static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001291{
1292 struct mgmt_mode *cp = data;
1293 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001294 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001295 int err;
1296
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001297 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001298
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001299 status = mgmt_bredr_support(hdev);
1300 if (status)
1301 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1302
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001303 if (!lmp_ssp_capable(hdev))
1304 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1305 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001306
Johan Hedberga7e80f22013-01-09 16:05:19 +02001307 if (cp->val != 0x00 && cp->val != 0x01)
1308 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1309 MGMT_STATUS_INVALID_PARAMS);
1310
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001311 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001312
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001313 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001314 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001315
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001316 if (cp->val) {
1317 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1318 &hdev->dev_flags);
1319 } else {
1320 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1321 &hdev->dev_flags);
1322 if (!changed)
1323 changed = test_and_clear_bit(HCI_HS_ENABLED,
1324 &hdev->dev_flags);
1325 else
1326 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001327 }
1328
1329 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1330 if (err < 0)
1331 goto failed;
1332
1333 if (changed)
1334 err = new_settings(hdev, sk);
1335
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001336 goto failed;
1337 }
1338
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001339 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1340 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001341 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1342 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001343 goto failed;
1344 }
1345
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001346 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001347 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1348 goto failed;
1349 }
1350
1351 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1352 if (!cmd) {
1353 err = -ENOMEM;
1354 goto failed;
1355 }
1356
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001357 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001358 if (err < 0) {
1359 mgmt_pending_remove(cmd);
1360 goto failed;
1361 }
1362
1363failed:
1364 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001365 return err;
1366}
1367
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001368static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001369{
1370 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001371 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001372 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001373 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001374
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001375 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001376
Johan Hedberge6fe7982013-10-02 15:45:22 +03001377 status = mgmt_bredr_support(hdev);
1378 if (status)
1379 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001380
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001381 if (!lmp_ssp_capable(hdev))
1382 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1383 MGMT_STATUS_NOT_SUPPORTED);
1384
1385 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1386 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1387 MGMT_STATUS_REJECTED);
1388
Johan Hedberga7e80f22013-01-09 16:05:19 +02001389 if (cp->val != 0x00 && cp->val != 0x01)
1390 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1391 MGMT_STATUS_INVALID_PARAMS);
1392
Marcel Holtmannee392692013-10-01 22:59:23 -07001393 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001394
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001395 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001396 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001397 } else {
1398 if (hdev_is_powered(hdev)) {
1399 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1400 MGMT_STATUS_REJECTED);
1401 goto unlock;
1402 }
1403
Marcel Holtmannee392692013-10-01 22:59:23 -07001404 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001405 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001406
1407 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1408 if (err < 0)
1409 goto unlock;
1410
1411 if (changed)
1412 err = new_settings(hdev, sk);
1413
1414unlock:
1415 hci_dev_unlock(hdev);
1416 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001417}
1418
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001419static void enable_advertising(struct hci_request *req)
1420{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001421 struct hci_dev *hdev = req->hdev;
1422 struct hci_cp_le_set_adv_param cp;
1423 u8 enable = 0x01;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001424
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001425 memset(&cp, 0, sizeof(cp));
1426 cp.min_interval = __constant_cpu_to_le16(0x0800);
1427 cp.max_interval = __constant_cpu_to_le16(0x0800);
1428 cp.type = LE_ADV_IND;
1429 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1430 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1431 else
1432 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1433 cp.channel_map = 0x07;
1434
1435 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1436
1437 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001438}
1439
1440static void disable_advertising(struct hci_request *req)
1441{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001442 u8 enable = 0x00;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001443
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001444 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001445}
1446
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001447static void le_enable_complete(struct hci_dev *hdev, u8 status)
1448{
1449 struct cmd_lookup match = { NULL, hdev };
1450
1451 if (status) {
1452 u8 mgmt_err = mgmt_status(status);
1453
1454 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1455 &mgmt_err);
1456 return;
1457 }
1458
1459 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1460
1461 new_settings(hdev, match.sk);
1462
1463 if (match.sk)
1464 sock_put(match.sk);
1465}
1466
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001467static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001468{
1469 struct mgmt_mode *cp = data;
1470 struct hci_cp_write_le_host_supported hci_cp;
1471 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001472 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001473 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001474 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001475
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001476 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001477
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001478 if (!lmp_le_capable(hdev))
1479 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1480 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001481
Johan Hedberga7e80f22013-01-09 16:05:19 +02001482 if (cp->val != 0x00 && cp->val != 0x01)
1483 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1484 MGMT_STATUS_INVALID_PARAMS);
1485
Johan Hedbergc73eee92013-04-19 18:35:21 +03001486 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001487 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001488 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1489 MGMT_STATUS_REJECTED);
1490
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001491 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001492
1493 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001494 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001495
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001496 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001497 bool changed = false;
1498
1499 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1500 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1501 changed = true;
1502 }
1503
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001504 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1505 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001506 changed = true;
1507 }
1508
Johan Hedberg06199cf2012-02-22 16:37:11 +02001509 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1510 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001511 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001512
1513 if (changed)
1514 err = new_settings(hdev, sk);
1515
Johan Hedberg1de028c2012-02-29 19:55:35 -08001516 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001517 }
1518
Johan Hedberg4375f102013-09-25 13:26:10 +03001519 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1520 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001521 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001522 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001523 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001524 }
1525
1526 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1527 if (!cmd) {
1528 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001529 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001530 }
1531
1532 memset(&hci_cp, 0, sizeof(hci_cp));
1533
1534 if (val) {
1535 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001536 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001537 }
1538
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001539 hci_req_init(&req, hdev);
1540
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001541 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1542 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001543
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001544 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1545 &hci_cp);
1546
1547 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301548 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001549 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001550
Johan Hedberg1de028c2012-02-29 19:55:35 -08001551unlock:
1552 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001553 return err;
1554}
1555
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001556/* This is a helper function to test for pending mgmt commands that can
1557 * cause CoD or EIR HCI commands. We can only allow one such pending
1558 * mgmt command at a time since otherwise we cannot easily track what
1559 * the current values are, will be, and based on that calculate if a new
1560 * HCI command needs to be sent and if yes with what value.
1561 */
1562static bool pending_eir_or_class(struct hci_dev *hdev)
1563{
1564 struct pending_cmd *cmd;
1565
1566 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1567 switch (cmd->opcode) {
1568 case MGMT_OP_ADD_UUID:
1569 case MGMT_OP_REMOVE_UUID:
1570 case MGMT_OP_SET_DEV_CLASS:
1571 case MGMT_OP_SET_POWERED:
1572 return true;
1573 }
1574 }
1575
1576 return false;
1577}
1578
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001579static const u8 bluetooth_base_uuid[] = {
1580 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1581 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1582};
1583
1584static u8 get_uuid_size(const u8 *uuid)
1585{
1586 u32 val;
1587
1588 if (memcmp(uuid, bluetooth_base_uuid, 12))
1589 return 128;
1590
1591 val = get_unaligned_le32(&uuid[12]);
1592 if (val > 0xffff)
1593 return 32;
1594
1595 return 16;
1596}
1597
Johan Hedberg92da6092013-03-15 17:06:55 -05001598static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1599{
1600 struct pending_cmd *cmd;
1601
1602 hci_dev_lock(hdev);
1603
1604 cmd = mgmt_pending_find(mgmt_op, hdev);
1605 if (!cmd)
1606 goto unlock;
1607
1608 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1609 hdev->dev_class, 3);
1610
1611 mgmt_pending_remove(cmd);
1612
1613unlock:
1614 hci_dev_unlock(hdev);
1615}
1616
1617static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1618{
1619 BT_DBG("status 0x%02x", status);
1620
1621 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1622}
1623
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001624static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001625{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001626 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001627 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001628 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001629 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001630 int err;
1631
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001632 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001633
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001634 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001635
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001636 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001637 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001638 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001639 goto failed;
1640 }
1641
Andre Guedes92c4c202012-06-07 19:05:44 -03001642 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001643 if (!uuid) {
1644 err = -ENOMEM;
1645 goto failed;
1646 }
1647
1648 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001649 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001650 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001651
Johan Hedbergde66aa62013-01-27 00:31:27 +02001652 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001653
Johan Hedberg890ea892013-03-15 17:06:52 -05001654 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001655
Johan Hedberg890ea892013-03-15 17:06:52 -05001656 update_class(&req);
1657 update_eir(&req);
1658
Johan Hedberg92da6092013-03-15 17:06:55 -05001659 err = hci_req_run(&req, add_uuid_complete);
1660 if (err < 0) {
1661 if (err != -ENODATA)
1662 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001663
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001664 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001665 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001666 goto failed;
1667 }
1668
1669 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001670 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001671 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001672 goto failed;
1673 }
1674
1675 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001676
1677failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001678 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001679 return err;
1680}
1681
Johan Hedberg24b78d02012-02-23 23:24:30 +02001682static bool enable_service_cache(struct hci_dev *hdev)
1683{
1684 if (!hdev_is_powered(hdev))
1685 return false;
1686
1687 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001688 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1689 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001690 return true;
1691 }
1692
1693 return false;
1694}
1695
Johan Hedberg92da6092013-03-15 17:06:55 -05001696static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1697{
1698 BT_DBG("status 0x%02x", status);
1699
1700 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1701}
1702
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001703static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001704 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001705{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001706 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001707 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001708 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001709 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 -05001710 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001711 int err, found;
1712
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001713 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001715 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001716
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001717 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001718 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001719 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001720 goto unlock;
1721 }
1722
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001723 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1724 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001725
Johan Hedberg24b78d02012-02-23 23:24:30 +02001726 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001727 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001728 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001729 goto unlock;
1730 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001731
Johan Hedberg9246a862012-02-23 21:33:16 +02001732 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001733 }
1734
1735 found = 0;
1736
Johan Hedberg056341c2013-01-27 00:31:30 +02001737 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001738 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1739 continue;
1740
1741 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001742 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001743 found++;
1744 }
1745
1746 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001747 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001748 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001749 goto unlock;
1750 }
1751
Johan Hedberg9246a862012-02-23 21:33:16 +02001752update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001753 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001754
Johan Hedberg890ea892013-03-15 17:06:52 -05001755 update_class(&req);
1756 update_eir(&req);
1757
Johan Hedberg92da6092013-03-15 17:06:55 -05001758 err = hci_req_run(&req, remove_uuid_complete);
1759 if (err < 0) {
1760 if (err != -ENODATA)
1761 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001762
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001763 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001764 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001765 goto unlock;
1766 }
1767
1768 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001769 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001770 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001771 goto unlock;
1772 }
1773
1774 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001775
1776unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001777 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001778 return err;
1779}
1780
Johan Hedberg92da6092013-03-15 17:06:55 -05001781static void set_class_complete(struct hci_dev *hdev, u8 status)
1782{
1783 BT_DBG("status 0x%02x", status);
1784
1785 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1786}
1787
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001788static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001789 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001790{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001791 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001792 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001793 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001794 int err;
1795
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001796 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001797
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001798 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001799 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1800 MGMT_STATUS_NOT_SUPPORTED);
1801
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001802 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001803
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001804 if (pending_eir_or_class(hdev)) {
1805 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1806 MGMT_STATUS_BUSY);
1807 goto unlock;
1808 }
1809
1810 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1811 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1812 MGMT_STATUS_INVALID_PARAMS);
1813 goto unlock;
1814 }
1815
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001816 hdev->major_class = cp->major;
1817 hdev->minor_class = cp->minor;
1818
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001819 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001820 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001821 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001822 goto unlock;
1823 }
1824
Johan Hedberg890ea892013-03-15 17:06:52 -05001825 hci_req_init(&req, hdev);
1826
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001827 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001828 hci_dev_unlock(hdev);
1829 cancel_delayed_work_sync(&hdev->service_cache);
1830 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001831 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001832 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001833
Johan Hedberg890ea892013-03-15 17:06:52 -05001834 update_class(&req);
1835
Johan Hedberg92da6092013-03-15 17:06:55 -05001836 err = hci_req_run(&req, set_class_complete);
1837 if (err < 0) {
1838 if (err != -ENODATA)
1839 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001840
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001841 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001842 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001843 goto unlock;
1844 }
1845
1846 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001847 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001848 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001849 goto unlock;
1850 }
1851
1852 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001853
Johan Hedbergb5235a62012-02-21 14:32:24 +02001854unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001855 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001856 return err;
1857}
1858
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001859static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001860 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001861{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001862 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001863 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001864 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001865
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001866 BT_DBG("request for %s", hdev->name);
1867
1868 if (!lmp_bredr_capable(hdev))
1869 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1870 MGMT_STATUS_NOT_SUPPORTED);
1871
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001872 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001873
Johan Hedberg86742e12011-11-07 23:13:38 +02001874 expected_len = sizeof(*cp) + key_count *
1875 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001876 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001877 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001878 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001879 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001880 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001881 }
1882
Johan Hedberg4ae14302013-01-20 14:27:13 +02001883 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1884 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1885 MGMT_STATUS_INVALID_PARAMS);
1886
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001887 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001888 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001889
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001890 for (i = 0; i < key_count; i++) {
1891 struct mgmt_link_key_info *key = &cp->keys[i];
1892
1893 if (key->addr.type != BDADDR_BREDR)
1894 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1895 MGMT_STATUS_INVALID_PARAMS);
1896 }
1897
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001898 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001899
1900 hci_link_keys_clear(hdev);
1901
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001902 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001903 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001904 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001905 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001906
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001907 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001908 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001909
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001910 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001911 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001912 }
1913
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001914 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001915
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001916 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001917
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001918 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001919}
1920
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001921static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001922 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001923{
1924 struct mgmt_ev_device_unpaired ev;
1925
1926 bacpy(&ev.addr.bdaddr, bdaddr);
1927 ev.addr.type = addr_type;
1928
1929 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001930 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001931}
1932
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001933static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001934 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001935{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001936 struct mgmt_cp_unpair_device *cp = data;
1937 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001938 struct hci_cp_disconnect dc;
1939 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001940 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001941 int err;
1942
Johan Hedberga8a1d192011-11-10 15:54:38 +02001943 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001944 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1945 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001946
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001947 if (!bdaddr_type_is_valid(cp->addr.type))
1948 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1949 MGMT_STATUS_INVALID_PARAMS,
1950 &rp, sizeof(rp));
1951
Johan Hedberg118da702013-01-20 14:27:20 +02001952 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1953 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1954 MGMT_STATUS_INVALID_PARAMS,
1955 &rp, sizeof(rp));
1956
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001957 hci_dev_lock(hdev);
1958
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001959 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001960 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001961 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001962 goto unlock;
1963 }
1964
Andre Guedes591f47f2012-04-24 21:02:49 -03001965 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001966 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1967 else
1968 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001969
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001970 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001971 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001972 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001973 goto unlock;
1974 }
1975
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001976 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001977 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001978 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001979 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001980 else
1981 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001982 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001983 } else {
1984 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001985 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001986
Johan Hedberga8a1d192011-11-10 15:54:38 +02001987 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001988 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001989 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001990 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001991 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001992 }
1993
Johan Hedberg124f6e32012-02-09 13:50:12 +02001994 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001995 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001996 if (!cmd) {
1997 err = -ENOMEM;
1998 goto unlock;
1999 }
2000
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002001 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002002 dc.reason = 0x13; /* Remote User Terminated Connection */
2003 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2004 if (err < 0)
2005 mgmt_pending_remove(cmd);
2006
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002007unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002008 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002009 return err;
2010}
2011
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002012static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002013 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002014{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002015 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002016 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002017 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002018 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002019 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002020 int err;
2021
2022 BT_DBG("");
2023
Johan Hedberg06a63b12013-01-20 14:27:21 +02002024 memset(&rp, 0, sizeof(rp));
2025 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2026 rp.addr.type = cp->addr.type;
2027
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002028 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002029 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2030 MGMT_STATUS_INVALID_PARAMS,
2031 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002032
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002033 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002034
2035 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002036 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2037 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002038 goto failed;
2039 }
2040
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002041 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002042 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2043 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002044 goto failed;
2045 }
2046
Andre Guedes591f47f2012-04-24 21:02:49 -03002047 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002048 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2049 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002050 else
2051 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002052
Vishal Agarwalf9607272012-06-13 05:32:43 +05302053 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002054 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2055 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002056 goto failed;
2057 }
2058
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002059 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002060 if (!cmd) {
2061 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002062 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002063 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002064
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002065 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002066 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002067
2068 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2069 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002070 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002071
2072failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002073 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002074 return err;
2075}
2076
Andre Guedes57c14772012-04-24 21:02:50 -03002077static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002078{
2079 switch (link_type) {
2080 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002081 switch (addr_type) {
2082 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002083 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002084
Johan Hedberg48264f02011-11-09 13:58:58 +02002085 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002086 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002087 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002088 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002089
Johan Hedberg4c659c32011-11-07 23:13:39 +02002090 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002091 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002092 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002093 }
2094}
2095
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002096static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2097 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002098{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002099 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002100 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002101 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002102 int err;
2103 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002104
2105 BT_DBG("");
2106
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002107 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002108
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002109 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002110 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002111 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002112 goto unlock;
2113 }
2114
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002115 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002116 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2117 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002118 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002119 }
2120
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002121 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002122 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002123 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002124 err = -ENOMEM;
2125 goto unlock;
2126 }
2127
Johan Hedberg2784eb42011-01-21 13:56:35 +02002128 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002129 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002130 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2131 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002132 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002133 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002134 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002135 continue;
2136 i++;
2137 }
2138
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002139 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002140
Johan Hedberg4c659c32011-11-07 23:13:39 +02002141 /* Recalculate length in case of filtered SCO connections, etc */
2142 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002144 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002145 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002146
Johan Hedberga38528f2011-01-22 06:46:43 +02002147 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002148
2149unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002150 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002151 return err;
2152}
2153
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002154static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002155 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002156{
2157 struct pending_cmd *cmd;
2158 int err;
2159
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002160 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002161 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002162 if (!cmd)
2163 return -ENOMEM;
2164
Johan Hedbergd8457692012-02-17 14:24:57 +02002165 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002166 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002167 if (err < 0)
2168 mgmt_pending_remove(cmd);
2169
2170 return err;
2171}
2172
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002173static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002174 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002175{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002176 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002177 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002178 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002179 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002180 int err;
2181
2182 BT_DBG("");
2183
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002184 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002185
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002186 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002187 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002188 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002189 goto failed;
2190 }
2191
Johan Hedbergd8457692012-02-17 14:24:57 +02002192 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002193 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002194 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002195 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002196 goto failed;
2197 }
2198
2199 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002200 struct mgmt_cp_pin_code_neg_reply ncp;
2201
2202 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002203
2204 BT_ERR("PIN code is not 16 bytes long");
2205
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002206 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002207 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002208 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002209 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002210
2211 goto failed;
2212 }
2213
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002214 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002215 if (!cmd) {
2216 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002217 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002218 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002219
Johan Hedbergd8457692012-02-17 14:24:57 +02002220 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002221 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002222 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002223
2224 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2225 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002226 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002227
2228failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002229 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002230 return err;
2231}
2232
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002233static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2234 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002235{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002236 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002237
2238 BT_DBG("");
2239
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002240 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002241
2242 hdev->io_capability = cp->io_capability;
2243
2244 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002245 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002246
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002247 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002248
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002249 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2250 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002251}
2252
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002253static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002254{
2255 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002256 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002257
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002258 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002259 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2260 continue;
2261
Johan Hedberge9a416b2011-02-19 12:05:56 -03002262 if (cmd->user_data != conn)
2263 continue;
2264
2265 return cmd;
2266 }
2267
2268 return NULL;
2269}
2270
2271static void pairing_complete(struct pending_cmd *cmd, u8 status)
2272{
2273 struct mgmt_rp_pair_device rp;
2274 struct hci_conn *conn = cmd->user_data;
2275
Johan Hedbergba4e5642011-11-11 00:07:34 +02002276 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002277 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002278
Johan Hedbergaee9b212012-02-18 15:07:59 +02002279 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002280 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002281
2282 /* So we don't get further callbacks for this connection */
2283 conn->connect_cfm_cb = NULL;
2284 conn->security_cfm_cb = NULL;
2285 conn->disconn_cfm_cb = NULL;
2286
David Herrmann76a68ba2013-04-06 20:28:37 +02002287 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002288
Johan Hedberga664b5b2011-02-19 12:06:02 -03002289 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002290}
2291
2292static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2293{
2294 struct pending_cmd *cmd;
2295
2296 BT_DBG("status %u", status);
2297
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002298 cmd = find_pairing(conn);
2299 if (!cmd)
2300 BT_DBG("Unable to find a pending command");
2301 else
Johan Hedberge2113262012-02-18 15:20:03 +02002302 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002303}
2304
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302305static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2306{
2307 struct pending_cmd *cmd;
2308
2309 BT_DBG("status %u", status);
2310
2311 if (!status)
2312 return;
2313
2314 cmd = find_pairing(conn);
2315 if (!cmd)
2316 BT_DBG("Unable to find a pending command");
2317 else
2318 pairing_complete(cmd, mgmt_status(status));
2319}
2320
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002321static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002322 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002323{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002324 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002325 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002326 struct pending_cmd *cmd;
2327 u8 sec_level, auth_type;
2328 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002329 int err;
2330
2331 BT_DBG("");
2332
Szymon Jancf950a30e2013-01-18 12:48:07 +01002333 memset(&rp, 0, sizeof(rp));
2334 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2335 rp.addr.type = cp->addr.type;
2336
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002337 if (!bdaddr_type_is_valid(cp->addr.type))
2338 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2339 MGMT_STATUS_INVALID_PARAMS,
2340 &rp, sizeof(rp));
2341
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002342 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002343
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002344 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002345 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2346 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002347 goto unlock;
2348 }
2349
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002350 sec_level = BT_SECURITY_MEDIUM;
2351 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002352 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002353 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002354 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002355
Andre Guedes591f47f2012-04-24 21:02:49 -03002356 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002357 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2358 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002359 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002360 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2361 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002362
Ville Tervo30e76272011-02-22 16:10:53 -03002363 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002364 int status;
2365
2366 if (PTR_ERR(conn) == -EBUSY)
2367 status = MGMT_STATUS_BUSY;
2368 else
2369 status = MGMT_STATUS_CONNECT_FAILED;
2370
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002371 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002372 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002373 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002374 goto unlock;
2375 }
2376
2377 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002378 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002379 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002380 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002381 goto unlock;
2382 }
2383
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002384 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002385 if (!cmd) {
2386 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002387 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002388 goto unlock;
2389 }
2390
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002391 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002392 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002393 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302394 else
2395 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002396
Johan Hedberge9a416b2011-02-19 12:05:56 -03002397 conn->security_cfm_cb = pairing_complete_cb;
2398 conn->disconn_cfm_cb = pairing_complete_cb;
2399 conn->io_capability = cp->io_cap;
2400 cmd->user_data = conn;
2401
2402 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002403 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002404 pairing_complete(cmd, 0);
2405
2406 err = 0;
2407
2408unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002409 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002410 return err;
2411}
2412
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002413static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2414 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002415{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002416 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002417 struct pending_cmd *cmd;
2418 struct hci_conn *conn;
2419 int err;
2420
2421 BT_DBG("");
2422
Johan Hedberg28424702012-02-02 04:02:29 +02002423 hci_dev_lock(hdev);
2424
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002425 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002426 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002427 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002428 goto unlock;
2429 }
2430
Johan Hedberg28424702012-02-02 04:02:29 +02002431 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2432 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002433 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002434 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002435 goto unlock;
2436 }
2437
2438 conn = cmd->user_data;
2439
2440 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002441 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002442 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002443 goto unlock;
2444 }
2445
2446 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2447
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002448 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002449 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002450unlock:
2451 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002452 return err;
2453}
2454
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002455static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002456 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002457 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002458{
Johan Hedberga5c29682011-02-19 12:05:57 -03002459 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002460 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002461 int err;
2462
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002463 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002464
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002465 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002466 err = cmd_complete(sk, hdev->id, mgmt_op,
2467 MGMT_STATUS_NOT_POWERED, addr,
2468 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002469 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002470 }
2471
Johan Hedberg1707c602013-03-15 17:07:15 -05002472 if (addr->type == BDADDR_BREDR)
2473 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002474 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002475 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002476
Johan Hedberg272d90d2012-02-09 15:26:12 +02002477 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002478 err = cmd_complete(sk, hdev->id, mgmt_op,
2479 MGMT_STATUS_NOT_CONNECTED, addr,
2480 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002481 goto done;
2482 }
2483
Johan Hedberg1707c602013-03-15 17:07:15 -05002484 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002485 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002486 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002487
Brian Gix5fe57d92011-12-21 16:12:13 -08002488 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002489 err = cmd_complete(sk, hdev->id, mgmt_op,
2490 MGMT_STATUS_SUCCESS, addr,
2491 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002492 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002493 err = cmd_complete(sk, hdev->id, mgmt_op,
2494 MGMT_STATUS_FAILED, addr,
2495 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002496
Brian Gix47c15e22011-11-16 13:53:14 -08002497 goto done;
2498 }
2499
Johan Hedberg1707c602013-03-15 17:07:15 -05002500 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002501 if (!cmd) {
2502 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002503 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002504 }
2505
Brian Gix0df4c182011-11-16 13:53:13 -08002506 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002507 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2508 struct hci_cp_user_passkey_reply cp;
2509
Johan Hedberg1707c602013-03-15 17:07:15 -05002510 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002511 cp.passkey = passkey;
2512 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2513 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002514 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2515 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002516
Johan Hedberga664b5b2011-02-19 12:06:02 -03002517 if (err < 0)
2518 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002519
Brian Gix0df4c182011-11-16 13:53:13 -08002520done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002521 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002522 return err;
2523}
2524
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302525static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2526 void *data, u16 len)
2527{
2528 struct mgmt_cp_pin_code_neg_reply *cp = data;
2529
2530 BT_DBG("");
2531
Johan Hedberg1707c602013-03-15 17:07:15 -05002532 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302533 MGMT_OP_PIN_CODE_NEG_REPLY,
2534 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2535}
2536
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002537static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2538 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002539{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002540 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002541
2542 BT_DBG("");
2543
2544 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002545 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002546 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002547
Johan Hedberg1707c602013-03-15 17:07:15 -05002548 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002549 MGMT_OP_USER_CONFIRM_REPLY,
2550 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002551}
2552
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002553static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002554 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002555{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002556 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002557
2558 BT_DBG("");
2559
Johan Hedberg1707c602013-03-15 17:07:15 -05002560 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002561 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2562 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002563}
2564
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002565static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2566 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002567{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002568 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002569
2570 BT_DBG("");
2571
Johan Hedberg1707c602013-03-15 17:07:15 -05002572 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002573 MGMT_OP_USER_PASSKEY_REPLY,
2574 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002575}
2576
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002577static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002578 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002579{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002580 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002581
2582 BT_DBG("");
2583
Johan Hedberg1707c602013-03-15 17:07:15 -05002584 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002585 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2586 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002587}
2588
Johan Hedberg13928972013-03-15 17:07:00 -05002589static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002590{
Johan Hedberg13928972013-03-15 17:07:00 -05002591 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002592 struct hci_cp_write_local_name cp;
2593
Johan Hedberg13928972013-03-15 17:07:00 -05002594 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002595
Johan Hedberg890ea892013-03-15 17:06:52 -05002596 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002597}
2598
Johan Hedberg13928972013-03-15 17:07:00 -05002599static void set_name_complete(struct hci_dev *hdev, u8 status)
2600{
2601 struct mgmt_cp_set_local_name *cp;
2602 struct pending_cmd *cmd;
2603
2604 BT_DBG("status 0x%02x", status);
2605
2606 hci_dev_lock(hdev);
2607
2608 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2609 if (!cmd)
2610 goto unlock;
2611
2612 cp = cmd->param;
2613
2614 if (status)
2615 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2616 mgmt_status(status));
2617 else
2618 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2619 cp, sizeof(*cp));
2620
2621 mgmt_pending_remove(cmd);
2622
2623unlock:
2624 hci_dev_unlock(hdev);
2625}
2626
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002627static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002628 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002629{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002630 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002631 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002632 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002633 int err;
2634
2635 BT_DBG("");
2636
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002637 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002638
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002639 /* If the old values are the same as the new ones just return a
2640 * direct command complete event.
2641 */
2642 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2643 !memcmp(hdev->short_name, cp->short_name,
2644 sizeof(hdev->short_name))) {
2645 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2646 data, len);
2647 goto failed;
2648 }
2649
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002650 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002651
Johan Hedbergb5235a62012-02-21 14:32:24 +02002652 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002653 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002654
2655 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002656 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002657 if (err < 0)
2658 goto failed;
2659
2660 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002661 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002662
Johan Hedbergb5235a62012-02-21 14:32:24 +02002663 goto failed;
2664 }
2665
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002666 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002667 if (!cmd) {
2668 err = -ENOMEM;
2669 goto failed;
2670 }
2671
Johan Hedberg13928972013-03-15 17:07:00 -05002672 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2673
Johan Hedberg890ea892013-03-15 17:06:52 -05002674 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002675
2676 if (lmp_bredr_capable(hdev)) {
2677 update_name(&req);
2678 update_eir(&req);
2679 }
2680
2681 if (lmp_le_capable(hdev))
2682 hci_update_ad(&req);
2683
Johan Hedberg13928972013-03-15 17:07:00 -05002684 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002685 if (err < 0)
2686 mgmt_pending_remove(cmd);
2687
2688failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002689 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002690 return err;
2691}
2692
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002693static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002694 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002695{
Szymon Jancc35938b2011-03-22 13:12:21 +01002696 struct pending_cmd *cmd;
2697 int err;
2698
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002699 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002700
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002701 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002702
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002703 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002704 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002705 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002706 goto unlock;
2707 }
2708
Andre Guedes9a1a1992012-07-24 15:03:48 -03002709 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002710 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002711 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002712 goto unlock;
2713 }
2714
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002715 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002716 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002717 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002718 goto unlock;
2719 }
2720
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002721 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002722 if (!cmd) {
2723 err = -ENOMEM;
2724 goto unlock;
2725 }
2726
2727 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2728 if (err < 0)
2729 mgmt_pending_remove(cmd);
2730
2731unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002732 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002733 return err;
2734}
2735
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002736static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002737 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002738{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002739 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002740 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002741 int err;
2742
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002743 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002744
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002745 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002746
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002747 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002748 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002749 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002750 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002751 else
Szymon Janca6785be2012-12-13 15:11:21 +01002752 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002753
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002754 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002755 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002756
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002757 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002758 return err;
2759}
2760
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002761static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002762 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002763{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002764 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002765 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002766 int err;
2767
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002768 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002769
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002770 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002771
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002772 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002773 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002774 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002775 else
Szymon Janca6785be2012-12-13 15:11:21 +01002776 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002777
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002778 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002779 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002780
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002781 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002782 return err;
2783}
2784
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002785static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2786{
2787 struct pending_cmd *cmd;
2788 u8 type;
2789 int err;
2790
2791 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2792
2793 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2794 if (!cmd)
2795 return -ENOENT;
2796
2797 type = hdev->discovery.type;
2798
2799 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2800 &type, sizeof(type));
2801 mgmt_pending_remove(cmd);
2802
2803 return err;
2804}
2805
Andre Guedes7c307722013-04-30 15:29:28 -03002806static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2807{
2808 BT_DBG("status %d", status);
2809
2810 if (status) {
2811 hci_dev_lock(hdev);
2812 mgmt_start_discovery_failed(hdev, status);
2813 hci_dev_unlock(hdev);
2814 return;
2815 }
2816
2817 hci_dev_lock(hdev);
2818 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2819 hci_dev_unlock(hdev);
2820
2821 switch (hdev->discovery.type) {
2822 case DISCOV_TYPE_LE:
2823 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002824 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002825 break;
2826
2827 case DISCOV_TYPE_INTERLEAVED:
2828 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002829 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002830 break;
2831
2832 case DISCOV_TYPE_BREDR:
2833 break;
2834
2835 default:
2836 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2837 }
2838}
2839
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002840static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002841 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002842{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002843 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002844 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002845 struct hci_cp_le_set_scan_param param_cp;
2846 struct hci_cp_le_set_scan_enable enable_cp;
2847 struct hci_cp_inquiry inq_cp;
2848 struct hci_request req;
2849 /* General inquiry access code (GIAC) */
2850 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002851 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002852 int err;
2853
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002854 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002855
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002856 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002857
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002858 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002859 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002860 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002861 goto failed;
2862 }
2863
Andre Guedes642be6c2012-03-21 00:03:37 -03002864 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2865 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2866 MGMT_STATUS_BUSY);
2867 goto failed;
2868 }
2869
Johan Hedbergff9ef572012-01-04 14:23:45 +02002870 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002871 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002872 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002873 goto failed;
2874 }
2875
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002876 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002877 if (!cmd) {
2878 err = -ENOMEM;
2879 goto failed;
2880 }
2881
Andre Guedes4aab14e2012-02-17 20:39:36 -03002882 hdev->discovery.type = cp->type;
2883
Andre Guedes7c307722013-04-30 15:29:28 -03002884 hci_req_init(&req, hdev);
2885
Andre Guedes4aab14e2012-02-17 20:39:36 -03002886 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002887 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002888 status = mgmt_bredr_support(hdev);
2889 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002890 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002891 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002892 mgmt_pending_remove(cmd);
2893 goto failed;
2894 }
2895
Andre Guedes7c307722013-04-30 15:29:28 -03002896 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2897 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2898 MGMT_STATUS_BUSY);
2899 mgmt_pending_remove(cmd);
2900 goto failed;
2901 }
2902
2903 hci_inquiry_cache_flush(hdev);
2904
2905 memset(&inq_cp, 0, sizeof(inq_cp));
2906 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002907 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002908 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002909 break;
2910
2911 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002912 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002913 status = mgmt_le_support(hdev);
2914 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002915 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002916 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002917 mgmt_pending_remove(cmd);
2918 goto failed;
2919 }
2920
Andre Guedes7c307722013-04-30 15:29:28 -03002921 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002922 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002923 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2924 MGMT_STATUS_NOT_SUPPORTED);
2925 mgmt_pending_remove(cmd);
2926 goto failed;
2927 }
2928
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002929 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002930 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2931 MGMT_STATUS_REJECTED);
2932 mgmt_pending_remove(cmd);
2933 goto failed;
2934 }
2935
2936 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2937 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2938 MGMT_STATUS_BUSY);
2939 mgmt_pending_remove(cmd);
2940 goto failed;
2941 }
2942
2943 memset(&param_cp, 0, sizeof(param_cp));
2944 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002945 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2946 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002947 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2948 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2949 else
2950 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002951 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2952 &param_cp);
2953
2954 memset(&enable_cp, 0, sizeof(enable_cp));
2955 enable_cp.enable = LE_SCAN_ENABLE;
2956 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2957 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2958 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002959 break;
2960
Andre Guedesf39799f2012-02-17 20:39:35 -03002961 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002962 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2963 MGMT_STATUS_INVALID_PARAMS);
2964 mgmt_pending_remove(cmd);
2965 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002966 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002967
Andre Guedes7c307722013-04-30 15:29:28 -03002968 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002969 if (err < 0)
2970 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002971 else
2972 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002973
2974failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002975 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002976 return err;
2977}
2978
Andre Guedes1183fdc2013-04-30 15:29:35 -03002979static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2980{
2981 struct pending_cmd *cmd;
2982 int err;
2983
2984 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2985 if (!cmd)
2986 return -ENOENT;
2987
2988 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2989 &hdev->discovery.type, sizeof(hdev->discovery.type));
2990 mgmt_pending_remove(cmd);
2991
2992 return err;
2993}
2994
Andre Guedes0e05bba2013-04-30 15:29:33 -03002995static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2996{
2997 BT_DBG("status %d", status);
2998
2999 hci_dev_lock(hdev);
3000
3001 if (status) {
3002 mgmt_stop_discovery_failed(hdev, status);
3003 goto unlock;
3004 }
3005
3006 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3007
3008unlock:
3009 hci_dev_unlock(hdev);
3010}
3011
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003012static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003013 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003014{
Johan Hedbergd9306502012-02-20 23:25:18 +02003015 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003016 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003017 struct hci_cp_remote_name_req_cancel cp;
3018 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003019 struct hci_request req;
3020 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003021 int err;
3022
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003023 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003024
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003025 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003026
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003027 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003028 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003029 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3030 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003031 goto unlock;
3032 }
3033
3034 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003035 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3037 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003038 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003039 }
3040
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003041 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003042 if (!cmd) {
3043 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003044 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003045 }
3046
Andre Guedes0e05bba2013-04-30 15:29:33 -03003047 hci_req_init(&req, hdev);
3048
Andre Guedese0d9727e2012-03-20 15:15:36 -03003049 switch (hdev->discovery.state) {
3050 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003051 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3052 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3053 } else {
3054 cancel_delayed_work(&hdev->le_scan_disable);
3055
3056 memset(&enable_cp, 0, sizeof(enable_cp));
3057 enable_cp.enable = LE_SCAN_DISABLE;
3058 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3059 sizeof(enable_cp), &enable_cp);
3060 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003061
Andre Guedese0d9727e2012-03-20 15:15:36 -03003062 break;
3063
3064 case DISCOVERY_RESOLVING:
3065 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003066 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003067 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003068 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003069 err = cmd_complete(sk, hdev->id,
3070 MGMT_OP_STOP_DISCOVERY, 0,
3071 &mgmt_cp->type,
3072 sizeof(mgmt_cp->type));
3073 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3074 goto unlock;
3075 }
3076
3077 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003078 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3079 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003080
3081 break;
3082
3083 default:
3084 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003085
3086 mgmt_pending_remove(cmd);
3087 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3088 MGMT_STATUS_FAILED, &mgmt_cp->type,
3089 sizeof(mgmt_cp->type));
3090 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003091 }
3092
Andre Guedes0e05bba2013-04-30 15:29:33 -03003093 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003094 if (err < 0)
3095 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003096 else
3097 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003098
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003099unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003100 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003101 return err;
3102}
3103
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003104static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003105 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003106{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003107 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003108 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003109 int err;
3110
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003111 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003112
Johan Hedberg561aafb2012-01-04 13:31:59 +02003113 hci_dev_lock(hdev);
3114
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003115 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003116 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003117 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003118 goto failed;
3119 }
3120
Johan Hedberga198e7b2012-02-17 14:27:06 +02003121 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003122 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003123 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003124 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003125 goto failed;
3126 }
3127
3128 if (cp->name_known) {
3129 e->name_state = NAME_KNOWN;
3130 list_del(&e->list);
3131 } else {
3132 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003133 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003134 }
3135
Johan Hedberge3846622013-01-09 15:29:33 +02003136 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3137 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003138
3139failed:
3140 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003141 return err;
3142}
3143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003144static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003145 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003146{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003147 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003148 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003149 int err;
3150
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003151 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003152
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003153 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003154 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3155 MGMT_STATUS_INVALID_PARAMS,
3156 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003157
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003158 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003159
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003160 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003161 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003162 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003163 else
Szymon Janca6785be2012-12-13 15:11:21 +01003164 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003165
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003166 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003167 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003168
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003169 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003170
3171 return err;
3172}
3173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003174static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003175 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003176{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003177 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003178 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003179 int err;
3180
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003181 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003182
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003183 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003184 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3185 MGMT_STATUS_INVALID_PARAMS,
3186 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003187
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003188 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003189
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003190 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003191 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003192 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003193 else
Szymon Janca6785be2012-12-13 15:11:21 +01003194 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003195
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003196 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003197 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003198
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003199 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003200
3201 return err;
3202}
3203
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003204static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3205 u16 len)
3206{
3207 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003208 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003209 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003210 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003211
3212 BT_DBG("%s", hdev->name);
3213
Szymon Jancc72d4b82012-03-16 16:02:57 +01003214 source = __le16_to_cpu(cp->source);
3215
3216 if (source > 0x0002)
3217 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3218 MGMT_STATUS_INVALID_PARAMS);
3219
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003220 hci_dev_lock(hdev);
3221
Szymon Jancc72d4b82012-03-16 16:02:57 +01003222 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003223 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3224 hdev->devid_product = __le16_to_cpu(cp->product);
3225 hdev->devid_version = __le16_to_cpu(cp->version);
3226
3227 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3228
Johan Hedberg890ea892013-03-15 17:06:52 -05003229 hci_req_init(&req, hdev);
3230 update_eir(&req);
3231 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003232
3233 hci_dev_unlock(hdev);
3234
3235 return err;
3236}
3237
Johan Hedberg4375f102013-09-25 13:26:10 +03003238static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3239{
3240 struct cmd_lookup match = { NULL, hdev };
3241
3242 if (status) {
3243 u8 mgmt_err = mgmt_status(status);
3244
3245 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3246 cmd_status_rsp, &mgmt_err);
3247 return;
3248 }
3249
3250 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3251 &match);
3252
3253 new_settings(hdev, match.sk);
3254
3255 if (match.sk)
3256 sock_put(match.sk);
3257}
3258
Marcel Holtmann21b51872013-10-10 09:47:53 -07003259static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3260 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003261{
3262 struct mgmt_mode *cp = data;
3263 struct pending_cmd *cmd;
3264 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003265 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003266 int err;
3267
3268 BT_DBG("request for %s", hdev->name);
3269
Johan Hedberge6fe7982013-10-02 15:45:22 +03003270 status = mgmt_le_support(hdev);
3271 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003272 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003273 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003274
3275 if (cp->val != 0x00 && cp->val != 0x01)
3276 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3277 MGMT_STATUS_INVALID_PARAMS);
3278
3279 hci_dev_lock(hdev);
3280
3281 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003282 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003283
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003284 /* The following conditions are ones which mean that we should
3285 * not do any HCI communication but directly send a mgmt
3286 * response to user space (after toggling the flag if
3287 * necessary).
3288 */
3289 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003290 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003291 bool changed = false;
3292
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003293 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3294 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003295 changed = true;
3296 }
3297
3298 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3299 if (err < 0)
3300 goto unlock;
3301
3302 if (changed)
3303 err = new_settings(hdev, sk);
3304
3305 goto unlock;
3306 }
3307
3308 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3309 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3310 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3311 MGMT_STATUS_BUSY);
3312 goto unlock;
3313 }
3314
3315 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3316 if (!cmd) {
3317 err = -ENOMEM;
3318 goto unlock;
3319 }
3320
3321 hci_req_init(&req, hdev);
3322
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003323 if (val)
3324 enable_advertising(&req);
3325 else
3326 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003327
3328 err = hci_req_run(&req, set_advertising_complete);
3329 if (err < 0)
3330 mgmt_pending_remove(cmd);
3331
3332unlock:
3333 hci_dev_unlock(hdev);
3334 return err;
3335}
3336
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003337static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3338 void *data, u16 len)
3339{
3340 struct mgmt_cp_set_static_address *cp = data;
3341 int err;
3342
3343 BT_DBG("%s", hdev->name);
3344
Marcel Holtmann62af4442013-10-02 22:10:32 -07003345 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003346 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003347 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003348
3349 if (hdev_is_powered(hdev))
3350 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3351 MGMT_STATUS_REJECTED);
3352
3353 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3354 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3355 return cmd_status(sk, hdev->id,
3356 MGMT_OP_SET_STATIC_ADDRESS,
3357 MGMT_STATUS_INVALID_PARAMS);
3358
3359 /* Two most significant bits shall be set */
3360 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3361 return cmd_status(sk, hdev->id,
3362 MGMT_OP_SET_STATIC_ADDRESS,
3363 MGMT_STATUS_INVALID_PARAMS);
3364 }
3365
3366 hci_dev_lock(hdev);
3367
3368 bacpy(&hdev->static_addr, &cp->bdaddr);
3369
3370 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3371
3372 hci_dev_unlock(hdev);
3373
3374 return err;
3375}
3376
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003377static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3378 void *data, u16 len)
3379{
3380 struct mgmt_cp_set_scan_params *cp = data;
3381 __u16 interval, window;
3382 int err;
3383
3384 BT_DBG("%s", hdev->name);
3385
3386 if (!lmp_le_capable(hdev))
3387 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3388 MGMT_STATUS_NOT_SUPPORTED);
3389
3390 interval = __le16_to_cpu(cp->interval);
3391
3392 if (interval < 0x0004 || interval > 0x4000)
3393 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3394 MGMT_STATUS_INVALID_PARAMS);
3395
3396 window = __le16_to_cpu(cp->window);
3397
3398 if (window < 0x0004 || window > 0x4000)
3399 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3400 MGMT_STATUS_INVALID_PARAMS);
3401
3402 hci_dev_lock(hdev);
3403
3404 hdev->le_scan_interval = interval;
3405 hdev->le_scan_window = window;
3406
3407 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3408
3409 hci_dev_unlock(hdev);
3410
3411 return err;
3412}
3413
Johan Hedberg33e38b32013-03-15 17:07:05 -05003414static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3415{
3416 struct pending_cmd *cmd;
3417
3418 BT_DBG("status 0x%02x", status);
3419
3420 hci_dev_lock(hdev);
3421
3422 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3423 if (!cmd)
3424 goto unlock;
3425
3426 if (status) {
3427 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3428 mgmt_status(status));
3429 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003430 struct mgmt_mode *cp = cmd->param;
3431
3432 if (cp->val)
3433 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3434 else
3435 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3436
Johan Hedberg33e38b32013-03-15 17:07:05 -05003437 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3438 new_settings(hdev, cmd->sk);
3439 }
3440
3441 mgmt_pending_remove(cmd);
3442
3443unlock:
3444 hci_dev_unlock(hdev);
3445}
3446
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003447static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003448 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003449{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003450 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003451 struct pending_cmd *cmd;
3452 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003453 int err;
3454
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003455 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003456
Johan Hedberg56f87902013-10-02 13:43:13 +03003457 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3458 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003459 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3460 MGMT_STATUS_NOT_SUPPORTED);
3461
Johan Hedberga7e80f22013-01-09 16:05:19 +02003462 if (cp->val != 0x00 && cp->val != 0x01)
3463 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3464 MGMT_STATUS_INVALID_PARAMS);
3465
Johan Hedberg5400c042012-02-21 16:40:33 +02003466 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003467 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003468 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003469
3470 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003471 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003472 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003473
3474 hci_dev_lock(hdev);
3475
Johan Hedberg05cbf292013-03-15 17:07:07 -05003476 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3477 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3478 MGMT_STATUS_BUSY);
3479 goto unlock;
3480 }
3481
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003482 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3483 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3484 hdev);
3485 goto unlock;
3486 }
3487
Johan Hedberg33e38b32013-03-15 17:07:05 -05003488 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3489 data, len);
3490 if (!cmd) {
3491 err = -ENOMEM;
3492 goto unlock;
3493 }
3494
3495 hci_req_init(&req, hdev);
3496
Johan Hedberg406d7802013-03-15 17:07:09 -05003497 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003498
3499 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003500 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003501 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003502 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003503 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003504 }
3505
Johan Hedberg33e38b32013-03-15 17:07:05 -05003506unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003507 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003508
Antti Julkuf6422ec2011-06-22 13:11:56 +03003509 return err;
3510}
3511
Johan Hedberg0663ca22013-10-02 13:43:14 +03003512static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3513{
3514 struct pending_cmd *cmd;
3515
3516 BT_DBG("status 0x%02x", status);
3517
3518 hci_dev_lock(hdev);
3519
3520 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3521 if (!cmd)
3522 goto unlock;
3523
3524 if (status) {
3525 u8 mgmt_err = mgmt_status(status);
3526
3527 /* We need to restore the flag if related HCI commands
3528 * failed.
3529 */
3530 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3531
3532 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3533 } else {
3534 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3535 new_settings(hdev, cmd->sk);
3536 }
3537
3538 mgmt_pending_remove(cmd);
3539
3540unlock:
3541 hci_dev_unlock(hdev);
3542}
3543
3544static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3545{
3546 struct mgmt_mode *cp = data;
3547 struct pending_cmd *cmd;
3548 struct hci_request req;
3549 int err;
3550
3551 BT_DBG("request for %s", hdev->name);
3552
3553 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3554 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3555 MGMT_STATUS_NOT_SUPPORTED);
3556
3557 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3558 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3559 MGMT_STATUS_REJECTED);
3560
3561 if (cp->val != 0x00 && cp->val != 0x01)
3562 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3563 MGMT_STATUS_INVALID_PARAMS);
3564
3565 hci_dev_lock(hdev);
3566
3567 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3568 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3569 goto unlock;
3570 }
3571
3572 if (!hdev_is_powered(hdev)) {
3573 if (!cp->val) {
3574 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3575 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3576 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3577 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3578 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3579 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3580 }
3581
3582 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3583
3584 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3585 if (err < 0)
3586 goto unlock;
3587
3588 err = new_settings(hdev, sk);
3589 goto unlock;
3590 }
3591
3592 /* Reject disabling when powered on */
3593 if (!cp->val) {
3594 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3595 MGMT_STATUS_REJECTED);
3596 goto unlock;
3597 }
3598
3599 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3600 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3601 MGMT_STATUS_BUSY);
3602 goto unlock;
3603 }
3604
3605 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3606 if (!cmd) {
3607 err = -ENOMEM;
3608 goto unlock;
3609 }
3610
3611 /* We need to flip the bit already here so that hci_update_ad
3612 * generates the correct flags.
3613 */
3614 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3615
3616 hci_req_init(&req, hdev);
3617 hci_update_ad(&req);
3618 err = hci_req_run(&req, set_bredr_complete);
3619 if (err < 0)
3620 mgmt_pending_remove(cmd);
3621
3622unlock:
3623 hci_dev_unlock(hdev);
3624 return err;
3625}
3626
Johan Hedberg3f706b72013-01-20 14:27:16 +02003627static bool ltk_is_valid(struct mgmt_ltk_info *key)
3628{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003629 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3630 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003631 if (key->master != 0x00 && key->master != 0x01)
3632 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003633 if (!bdaddr_type_is_le(key->addr.type))
3634 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003635 return true;
3636}
3637
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003638static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003639 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003640{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003641 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3642 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003643 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003644
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003645 BT_DBG("request for %s", hdev->name);
3646
3647 if (!lmp_le_capable(hdev))
3648 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3649 MGMT_STATUS_NOT_SUPPORTED);
3650
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003651 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003652
3653 expected_len = sizeof(*cp) + key_count *
3654 sizeof(struct mgmt_ltk_info);
3655 if (expected_len != len) {
3656 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003657 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003658 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003659 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003660 }
3661
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003662 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003663
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003664 for (i = 0; i < key_count; i++) {
3665 struct mgmt_ltk_info *key = &cp->keys[i];
3666
Johan Hedberg3f706b72013-01-20 14:27:16 +02003667 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003668 return cmd_status(sk, hdev->id,
3669 MGMT_OP_LOAD_LONG_TERM_KEYS,
3670 MGMT_STATUS_INVALID_PARAMS);
3671 }
3672
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003673 hci_dev_lock(hdev);
3674
3675 hci_smp_ltks_clear(hdev);
3676
3677 for (i = 0; i < key_count; i++) {
3678 struct mgmt_ltk_info *key = &cp->keys[i];
3679 u8 type;
3680
3681 if (key->master)
3682 type = HCI_SMP_LTK;
3683 else
3684 type = HCI_SMP_LTK_SLAVE;
3685
Hemant Gupta4596fde2012-04-16 14:57:40 +05303686 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003687 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003688 type, 0, key->authenticated, key->val,
3689 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003690 }
3691
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003692 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3693 NULL, 0);
3694
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003695 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003696
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003697 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003698}
3699
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003700static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003701 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3702 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003703 bool var_len;
3704 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003705} mgmt_handlers[] = {
3706 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003707 { read_version, false, MGMT_READ_VERSION_SIZE },
3708 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3709 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3710 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3711 { set_powered, false, MGMT_SETTING_SIZE },
3712 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3713 { set_connectable, false, MGMT_SETTING_SIZE },
3714 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3715 { set_pairable, false, MGMT_SETTING_SIZE },
3716 { set_link_security, false, MGMT_SETTING_SIZE },
3717 { set_ssp, false, MGMT_SETTING_SIZE },
3718 { set_hs, false, MGMT_SETTING_SIZE },
3719 { set_le, false, MGMT_SETTING_SIZE },
3720 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3721 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3722 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3723 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3724 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3725 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3726 { disconnect, false, MGMT_DISCONNECT_SIZE },
3727 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3728 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3729 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3730 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3731 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3732 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3733 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3734 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3735 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3736 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3737 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3738 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3739 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3740 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3741 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3742 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3743 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3744 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3745 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003746 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003747 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003748 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003749 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003750 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003751};
3752
3753
Johan Hedberg03811012010-12-08 00:21:06 +02003754int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3755{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003756 void *buf;
3757 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003758 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003759 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003760 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003761 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003762 int err;
3763
3764 BT_DBG("got %zu bytes", msglen);
3765
3766 if (msglen < sizeof(*hdr))
3767 return -EINVAL;
3768
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003769 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003770 if (!buf)
3771 return -ENOMEM;
3772
3773 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3774 err = -EFAULT;
3775 goto done;
3776 }
3777
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003778 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003779 opcode = __le16_to_cpu(hdr->opcode);
3780 index = __le16_to_cpu(hdr->index);
3781 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003782
3783 if (len != msglen - sizeof(*hdr)) {
3784 err = -EINVAL;
3785 goto done;
3786 }
3787
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003788 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003789 hdev = hci_dev_get(index);
3790 if (!hdev) {
3791 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003792 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003793 goto done;
3794 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003795
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02003796 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
3797 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003798 err = cmd_status(sk, index, opcode,
3799 MGMT_STATUS_INVALID_INDEX);
3800 goto done;
3801 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003802 }
3803
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003804 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003805 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003806 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003807 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003808 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003809 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003810 }
3811
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003812 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003813 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003814 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003815 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003816 goto done;
3817 }
3818
Johan Hedbergbe22b542012-03-01 22:24:41 +02003819 handler = &mgmt_handlers[opcode];
3820
3821 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003822 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003823 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003824 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003825 goto done;
3826 }
3827
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003828 if (hdev)
3829 mgmt_init_hdev(sk, hdev);
3830
3831 cp = buf + sizeof(*hdr);
3832
Johan Hedbergbe22b542012-03-01 22:24:41 +02003833 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003834 if (err < 0)
3835 goto done;
3836
Johan Hedberg03811012010-12-08 00:21:06 +02003837 err = msglen;
3838
3839done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003840 if (hdev)
3841 hci_dev_put(hdev);
3842
Johan Hedberg03811012010-12-08 00:21:06 +02003843 kfree(buf);
3844 return err;
3845}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003846
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003847void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003848{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003849 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003850 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003851
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003852 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003853}
3854
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003855void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003856{
Johan Hedberg5f159032012-03-02 03:13:19 +02003857 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003858
Marcel Holtmann1514b892013-10-06 08:25:01 -07003859 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003860 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003861
Johan Hedberg744cf192011-11-08 20:40:14 +02003862 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003863
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003864 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003865}
3866
Johan Hedberg890ea892013-03-15 17:06:52 -05003867static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003868{
Johan Hedberg890ea892013-03-15 17:06:52 -05003869 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003870 u8 scan = 0;
3871
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003872 /* Ensure that fast connectable is disabled. This function will
3873 * not do anything if the page scan parameters are already what
3874 * they should be.
3875 */
3876 write_fast_connectable(req, false);
3877
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003878 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3879 scan |= SCAN_PAGE;
3880 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3881 scan |= SCAN_INQUIRY;
3882
Johan Hedberg890ea892013-03-15 17:06:52 -05003883 if (scan)
3884 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003885}
3886
Johan Hedberg229ab392013-03-15 17:06:53 -05003887static void powered_complete(struct hci_dev *hdev, u8 status)
3888{
3889 struct cmd_lookup match = { NULL, hdev };
3890
3891 BT_DBG("status 0x%02x", status);
3892
3893 hci_dev_lock(hdev);
3894
3895 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3896
3897 new_settings(hdev, match.sk);
3898
3899 hci_dev_unlock(hdev);
3900
3901 if (match.sk)
3902 sock_put(match.sk);
3903}
3904
Johan Hedberg70da6242013-03-15 17:06:51 -05003905static int powered_update_hci(struct hci_dev *hdev)
3906{
Johan Hedberg890ea892013-03-15 17:06:52 -05003907 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003908 u8 link_sec;
3909
Johan Hedberg890ea892013-03-15 17:06:52 -05003910 hci_req_init(&req, hdev);
3911
Johan Hedberg70da6242013-03-15 17:06:51 -05003912 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3913 !lmp_host_ssp_capable(hdev)) {
3914 u8 ssp = 1;
3915
Johan Hedberg890ea892013-03-15 17:06:52 -05003916 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003917 }
3918
Johan Hedbergc73eee92013-04-19 18:35:21 +03003919 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3920 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003921 struct hci_cp_write_le_host_supported cp;
3922
3923 cp.le = 1;
3924 cp.simul = lmp_le_br_capable(hdev);
3925
3926 /* Check first if we already have the right
3927 * host state (host features set)
3928 */
3929 if (cp.le != lmp_host_le_capable(hdev) ||
3930 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003931 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3932 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003933
3934 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3935 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003936 }
3937
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003938 if (lmp_le_capable(hdev)) {
3939 /* Set random address to static address if configured */
3940 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3941 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3942 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003943
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003944 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3945 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003946 }
3947
Johan Hedberg70da6242013-03-15 17:06:51 -05003948 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3949 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003950 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3951 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003952
3953 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003954 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3955 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003956 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003957 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003958 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003959 }
3960
Johan Hedberg229ab392013-03-15 17:06:53 -05003961 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003962}
3963
Johan Hedberg744cf192011-11-08 20:40:14 +02003964int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003965{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003966 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003967 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3968 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003969 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003970
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003971 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3972 return 0;
3973
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003974 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003975 if (powered_update_hci(hdev) == 0)
3976 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003977
Johan Hedberg229ab392013-03-15 17:06:53 -05003978 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3979 &match);
3980 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003981 }
3982
Johan Hedberg229ab392013-03-15 17:06:53 -05003983 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3984 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3985
3986 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3987 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3988 zero_cod, sizeof(zero_cod), NULL);
3989
3990new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003991 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003992
3993 if (match.sk)
3994 sock_put(match.sk);
3995
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003996 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003997}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003998
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003999void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004000{
4001 struct pending_cmd *cmd;
4002 u8 status;
4003
4004 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4005 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004006 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004007
4008 if (err == -ERFKILL)
4009 status = MGMT_STATUS_RFKILLED;
4010 else
4011 status = MGMT_STATUS_FAILED;
4012
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004013 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004014
4015 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004016}
4017
Johan Hedberg744cf192011-11-08 20:40:14 +02004018int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004019{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004020 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004021 bool changed = false;
4022 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004023
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004024 if (discoverable) {
4025 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4026 changed = true;
4027 } else {
4028 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4029 changed = true;
4030 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004031
Johan Hedberged9b5f22012-02-21 20:47:06 +02004032 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004033 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004034
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004035 if (changed)
4036 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004037
Johan Hedberg73f22f62010-12-29 16:00:25 +02004038 if (match.sk)
4039 sock_put(match.sk);
4040
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004041 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004042}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004043
Johan Hedberg744cf192011-11-08 20:40:14 +02004044int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004045{
Johan Hedberg2b76f452013-03-15 17:07:04 -05004046 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004047 bool changed = false;
4048 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004049
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004050 if (connectable) {
4051 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4052 changed = true;
4053 } else {
4054 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4055 changed = true;
4056 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004057
Johan Hedberg2b76f452013-03-15 17:07:04 -05004058 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004059
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004060 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05004061 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004062
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004063 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004064}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004065
Johan Hedberg744cf192011-11-08 20:40:14 +02004066int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004067{
Johan Hedbergca69b792011-11-11 18:10:00 +02004068 u8 mgmt_err = mgmt_status(status);
4069
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004070 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004071 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004072 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004073
4074 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004075 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004076 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004077
4078 return 0;
4079}
4080
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004081int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4082 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004083{
Johan Hedberg86742e12011-11-07 23:13:38 +02004084 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004085
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004086 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004087
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004088 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004089 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004090 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004091 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004092 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004093 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004094
Johan Hedberg744cf192011-11-08 20:40:14 +02004095 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004096}
Johan Hedbergf7520542011-01-20 12:34:39 +02004097
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004098int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4099{
4100 struct mgmt_ev_new_long_term_key ev;
4101
4102 memset(&ev, 0, sizeof(ev));
4103
4104 ev.store_hint = persistent;
4105 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004106 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004107 ev.key.authenticated = key->authenticated;
4108 ev.key.enc_size = key->enc_size;
4109 ev.key.ediv = key->ediv;
4110
4111 if (key->type == HCI_SMP_LTK)
4112 ev.key.master = 1;
4113
4114 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4115 memcpy(ev.key.val, key->val, sizeof(key->val));
4116
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004117 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4118 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004119}
4120
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004121void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4122 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4123 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004124{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004125 char buf[512];
4126 struct mgmt_ev_device_connected *ev = (void *) buf;
4127 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004128
Johan Hedbergb644ba32012-01-17 21:48:47 +02004129 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004130 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004131
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004132 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004133
Johan Hedbergb644ba32012-01-17 21:48:47 +02004134 if (name_len > 0)
4135 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004136 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004137
4138 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004139 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004140 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004141
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004142 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004143
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004144 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4145 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004146}
4147
Johan Hedberg8962ee72011-01-20 12:40:27 +02004148static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4149{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004150 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004151 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004152 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004153
Johan Hedberg88c3df12012-02-09 14:27:38 +02004154 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4155 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004156
Johan Hedbergaee9b212012-02-18 15:07:59 +02004157 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004158 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004159
4160 *sk = cmd->sk;
4161 sock_hold(*sk);
4162
Johan Hedberga664b5b2011-02-19 12:06:02 -03004163 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004164}
4165
Johan Hedberg124f6e32012-02-09 13:50:12 +02004166static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004167{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004168 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004169 struct mgmt_cp_unpair_device *cp = cmd->param;
4170 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004171
4172 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004173 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4174 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004175
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004176 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4177
Johan Hedbergaee9b212012-02-18 15:07:59 +02004178 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004179
4180 mgmt_pending_remove(cmd);
4181}
4182
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004183void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4184 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004185{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004186 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004187 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004188
Johan Hedberg744cf192011-11-08 20:40:14 +02004189 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004190
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004191 bacpy(&ev.addr.bdaddr, bdaddr);
4192 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4193 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004194
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004195 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004196
4197 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004198 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004199
Johan Hedberg124f6e32012-02-09 13:50:12 +02004200 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004201 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004202}
4203
Marcel Holtmann78929242013-10-06 23:55:47 -07004204void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4205 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004206{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004207 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004208 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004209
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004210 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4211 hdev);
4212
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004213 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004214 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004215 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004216
Johan Hedberg88c3df12012-02-09 14:27:38 +02004217 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004218 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004219
Marcel Holtmann78929242013-10-06 23:55:47 -07004220 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4221 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004222
Johan Hedberga664b5b2011-02-19 12:06:02 -03004223 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004224}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004225
Marcel Holtmann445608d2013-10-06 23:55:48 -07004226void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4227 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004228{
4229 struct mgmt_ev_connect_failed ev;
4230
Johan Hedberg4c659c32011-11-07 23:13:39 +02004231 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004232 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004233 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004234
Marcel Holtmann445608d2013-10-06 23:55:48 -07004235 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004236}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004237
Johan Hedberg744cf192011-11-08 20:40:14 +02004238int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004239{
4240 struct mgmt_ev_pin_code_request ev;
4241
Johan Hedbergd8457692012-02-17 14:24:57 +02004242 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004243 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004244 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004245
Johan Hedberg744cf192011-11-08 20:40:14 +02004246 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004247 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004248}
4249
Johan Hedberg744cf192011-11-08 20:40:14 +02004250int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004251 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004252{
4253 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004254 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004255 int err;
4256
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004257 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004258 if (!cmd)
4259 return -ENOENT;
4260
Johan Hedbergd8457692012-02-17 14:24:57 +02004261 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004262 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004263
Johan Hedbergaee9b212012-02-18 15:07:59 +02004264 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004265 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004266
Johan Hedberga664b5b2011-02-19 12:06:02 -03004267 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004268
4269 return err;
4270}
4271
Johan Hedberg744cf192011-11-08 20:40:14 +02004272int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004273 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004274{
4275 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004276 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004277 int err;
4278
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004279 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004280 if (!cmd)
4281 return -ENOENT;
4282
Johan Hedbergd8457692012-02-17 14:24:57 +02004283 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004284 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004285
Johan Hedbergaee9b212012-02-18 15:07:59 +02004286 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004287 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004288
Johan Hedberga664b5b2011-02-19 12:06:02 -03004289 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004290
4291 return err;
4292}
Johan Hedberga5c29682011-02-19 12:05:57 -03004293
Johan Hedberg744cf192011-11-08 20:40:14 +02004294int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004295 u8 link_type, u8 addr_type, __le32 value,
4296 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004297{
4298 struct mgmt_ev_user_confirm_request ev;
4299
Johan Hedberg744cf192011-11-08 20:40:14 +02004300 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004301
Johan Hedberg272d90d2012-02-09 15:26:12 +02004302 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004303 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004304 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004305 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004306
Johan Hedberg744cf192011-11-08 20:40:14 +02004307 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004308 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004309}
4310
Johan Hedberg272d90d2012-02-09 15:26:12 +02004311int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004312 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004313{
4314 struct mgmt_ev_user_passkey_request ev;
4315
4316 BT_DBG("%s", hdev->name);
4317
Johan Hedberg272d90d2012-02-09 15:26:12 +02004318 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004319 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004320
4321 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004322 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004323}
4324
Brian Gix0df4c182011-11-16 13:53:13 -08004325static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004326 u8 link_type, u8 addr_type, u8 status,
4327 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004328{
4329 struct pending_cmd *cmd;
4330 struct mgmt_rp_user_confirm_reply rp;
4331 int err;
4332
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004333 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004334 if (!cmd)
4335 return -ENOENT;
4336
Johan Hedberg272d90d2012-02-09 15:26:12 +02004337 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004338 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004339 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004340 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004341
Johan Hedberga664b5b2011-02-19 12:06:02 -03004342 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004343
4344 return err;
4345}
4346
Johan Hedberg744cf192011-11-08 20:40:14 +02004347int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004348 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004349{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004350 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004351 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004352}
4353
Johan Hedberg272d90d2012-02-09 15:26:12 +02004354int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004355 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004356{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004357 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004358 status,
4359 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004360}
Johan Hedberg2a611692011-02-19 12:06:00 -03004361
Brian Gix604086b2011-11-23 08:28:33 -08004362int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004363 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004364{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004365 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004366 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004367}
4368
Johan Hedberg272d90d2012-02-09 15:26:12 +02004369int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004370 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004371{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004372 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004373 status,
4374 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004375}
4376
Johan Hedberg92a25252012-09-06 18:39:26 +03004377int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4378 u8 link_type, u8 addr_type, u32 passkey,
4379 u8 entered)
4380{
4381 struct mgmt_ev_passkey_notify ev;
4382
4383 BT_DBG("%s", hdev->name);
4384
4385 bacpy(&ev.addr.bdaddr, bdaddr);
4386 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4387 ev.passkey = __cpu_to_le32(passkey);
4388 ev.entered = entered;
4389
4390 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4391}
4392
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004393int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004394 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004395{
4396 struct mgmt_ev_auth_failed ev;
4397
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004398 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004399 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004400 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004401
Johan Hedberg744cf192011-11-08 20:40:14 +02004402 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004403}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004404
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004405int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4406{
4407 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004408 bool changed = false;
4409 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004410
4411 if (status) {
4412 u8 mgmt_err = mgmt_status(status);
4413 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004414 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004415 return 0;
4416 }
4417
Johan Hedberg47990ea2012-02-22 11:58:37 +02004418 if (test_bit(HCI_AUTH, &hdev->flags)) {
4419 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4420 changed = true;
4421 } else {
4422 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4423 changed = true;
4424 }
4425
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004426 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004427 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004428
Johan Hedberg47990ea2012-02-22 11:58:37 +02004429 if (changed)
4430 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004431
4432 if (match.sk)
4433 sock_put(match.sk);
4434
4435 return err;
4436}
4437
Johan Hedberg890ea892013-03-15 17:06:52 -05004438static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004439{
Johan Hedberg890ea892013-03-15 17:06:52 -05004440 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004441 struct hci_cp_write_eir cp;
4442
Johan Hedberg976eb202012-10-24 21:12:01 +03004443 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004444 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004445
Johan Hedbergc80da272012-02-22 15:38:48 +02004446 memset(hdev->eir, 0, sizeof(hdev->eir));
4447
Johan Hedbergcacaf522012-02-21 00:52:42 +02004448 memset(&cp, 0, sizeof(cp));
4449
Johan Hedberg890ea892013-03-15 17:06:52 -05004450 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004451}
4452
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004453int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004454{
4455 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004456 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004457 bool changed = false;
4458 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004459
4460 if (status) {
4461 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004462
4463 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004464 &hdev->dev_flags)) {
4465 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004466 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004467 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004468
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004469 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4470 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004471
4472 return err;
4473 }
4474
4475 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004476 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004477 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004478 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4479 if (!changed)
4480 changed = test_and_clear_bit(HCI_HS_ENABLED,
4481 &hdev->dev_flags);
4482 else
4483 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004484 }
4485
4486 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4487
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004488 if (changed)
4489 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004490
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004491 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004492 sock_put(match.sk);
4493
Johan Hedberg890ea892013-03-15 17:06:52 -05004494 hci_req_init(&req, hdev);
4495
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004496 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004497 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004498 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004499 clear_eir(&req);
4500
4501 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004502
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004503 return err;
4504}
4505
Johan Hedberg92da6092013-03-15 17:06:55 -05004506static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004507{
4508 struct cmd_lookup *match = data;
4509
Johan Hedberg90e70452012-02-23 23:09:40 +02004510 if (match->sk == NULL) {
4511 match->sk = cmd->sk;
4512 sock_hold(match->sk);
4513 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004514}
4515
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004516int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004517 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004518{
Johan Hedberg90e70452012-02-23 23:09:40 +02004519 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4520 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004521
Johan Hedberg92da6092013-03-15 17:06:55 -05004522 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4523 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4524 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004525
4526 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004527 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4528 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004529
4530 if (match.sk)
4531 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004532
4533 return err;
4534}
4535
Johan Hedberg744cf192011-11-08 20:40:14 +02004536int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004537{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004538 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004539 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004540
Johan Hedberg13928972013-03-15 17:07:00 -05004541 if (status)
4542 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004543
4544 memset(&ev, 0, sizeof(ev));
4545 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004546 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004547
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004548 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004549 if (!cmd) {
4550 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004551
Johan Hedberg13928972013-03-15 17:07:00 -05004552 /* If this is a HCI command related to powering on the
4553 * HCI dev don't send any mgmt signals.
4554 */
4555 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4556 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004557 }
4558
Johan Hedberg13928972013-03-15 17:07:00 -05004559 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4560 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004561}
Szymon Jancc35938b2011-03-22 13:12:21 +01004562
Johan Hedberg744cf192011-11-08 20:40:14 +02004563int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004564 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004565{
4566 struct pending_cmd *cmd;
4567 int err;
4568
Johan Hedberg744cf192011-11-08 20:40:14 +02004569 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004570
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004571 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004572 if (!cmd)
4573 return -ENOENT;
4574
4575 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004576 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4577 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004578 } else {
4579 struct mgmt_rp_read_local_oob_data rp;
4580
4581 memcpy(rp.hash, hash, sizeof(rp.hash));
4582 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4583
Johan Hedberg744cf192011-11-08 20:40:14 +02004584 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004585 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4586 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004587 }
4588
4589 mgmt_pending_remove(cmd);
4590
4591 return err;
4592}
Johan Hedberge17acd42011-03-30 23:57:16 +03004593
Marcel Holtmann901801b2013-10-06 23:55:51 -07004594void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4595 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4596 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004597{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004598 char buf[512];
4599 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004600 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004601
Andre Guedes12602d02013-04-30 15:29:40 -03004602 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004603 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004604
Johan Hedberg1dc06092012-01-15 21:01:23 +02004605 /* Leave 5 bytes for a potential CoD field */
4606 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004607 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004608
Johan Hedberg1dc06092012-01-15 21:01:23 +02004609 memset(buf, 0, sizeof(buf));
4610
Johan Hedberge319d2e2012-01-15 19:51:59 +02004611 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004612 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004613 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004614 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304615 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004616 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304617 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004618
Johan Hedberg1dc06092012-01-15 21:01:23 +02004619 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004620 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004621
Johan Hedberg1dc06092012-01-15 21:01:23 +02004622 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4623 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004624 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004625
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004626 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004627 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004628
Marcel Holtmann901801b2013-10-06 23:55:51 -07004629 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004630}
Johan Hedberga88a9652011-03-30 13:18:12 +03004631
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004632void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4633 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004634{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004635 struct mgmt_ev_device_found *ev;
4636 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4637 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004638
Johan Hedbergb644ba32012-01-17 21:48:47 +02004639 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004640
Johan Hedbergb644ba32012-01-17 21:48:47 +02004641 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004642
Johan Hedbergb644ba32012-01-17 21:48:47 +02004643 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004644 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004645 ev->rssi = rssi;
4646
4647 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004648 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004649
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004650 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004651
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004652 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004653}
Johan Hedberg314b2382011-04-27 10:29:57 -04004654
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004655void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004656{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004657 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004658 struct pending_cmd *cmd;
4659
Andre Guedes343fb142011-11-22 17:14:19 -03004660 BT_DBG("%s discovering %u", hdev->name, discovering);
4661
Johan Hedberg164a6e72011-11-01 17:06:44 +02004662 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004663 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004664 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004665 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004666
4667 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004668 u8 type = hdev->discovery.type;
4669
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004670 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4671 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004672 mgmt_pending_remove(cmd);
4673 }
4674
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004675 memset(&ev, 0, sizeof(ev));
4676 ev.type = hdev->discovery.type;
4677 ev.discovering = discovering;
4678
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004679 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004680}
Antti Julku5e762442011-08-25 16:48:02 +03004681
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004682int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004683{
4684 struct pending_cmd *cmd;
4685 struct mgmt_ev_device_blocked ev;
4686
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004687 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004688
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004689 bacpy(&ev.addr.bdaddr, bdaddr);
4690 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004691
Johan Hedberg744cf192011-11-08 20:40:14 +02004692 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004693 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004694}
4695
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004696int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004697{
4698 struct pending_cmd *cmd;
4699 struct mgmt_ev_device_unblocked ev;
4700
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004701 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004702
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004703 bacpy(&ev.addr.bdaddr, bdaddr);
4704 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004705
Johan Hedberg744cf192011-11-08 20:40:14 +02004706 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004707 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004708}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004709
4710static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4711{
4712 BT_DBG("%s status %u", hdev->name, status);
4713
4714 /* Clear the advertising mgmt setting if we failed to re-enable it */
4715 if (status) {
4716 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004717 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004718 }
4719}
4720
4721void mgmt_reenable_advertising(struct hci_dev *hdev)
4722{
4723 struct hci_request req;
4724
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004725 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004726 return;
4727
4728 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4729 return;
4730
4731 hci_req_init(&req, hdev);
4732 enable_advertising(&req);
4733
4734 /* If this fails we have no option but to let user space know
4735 * that we've disabled advertising.
4736 */
4737 if (hci_req_run(&req, adv_enable_complete) < 0) {
4738 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004739 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004740 }
4741}