blob: aa59490044aa41b4fd7fbe85f26510848e1c0967 [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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200202
Andre Guedes790eff42012-06-07 19:05:46 -0300203 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200219 kfree_skb(skb);
220
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300221 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200222}
223
Johan Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Guedesed3fa312012-07-24 15:03:46 -0300366 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300367 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500368 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
369 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300370 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200371 settings |= MGMT_SETTING_BREDR;
372 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700373
374 if (lmp_ssp_capable(hdev)) {
375 settings |= MGMT_SETTING_SSP;
376 settings |= MGMT_SETTING_HS;
377 }
Marcel Holtmann848566b2013-10-01 22:59:22 -0700378 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100379
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300380 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200381 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300382 settings |= MGMT_SETTING_ADVERTISING;
383 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200384
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200385 return settings;
386}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388static u32 get_current_settings(struct hci_dev *hdev)
389{
390 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200391
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200392 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100393 settings |= MGMT_SETTING_POWERED;
394
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200395 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200396 settings |= MGMT_SETTING_CONNECTABLE;
397
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500398 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
399 settings |= MGMT_SETTING_FAST_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
Johan Hedberg56f87902013-10-02 13:43:13 +0300407 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_BREDR;
409
Johan Hedberg06199cf2012-02-22 16:37:11 +0200410 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200412
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200422 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300423 settings |= MGMT_SETTING_ADVERTISING;
424
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200426}
427
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300428#define PNP_INFO_SVCLASS_ID 0x1200
429
Johan Hedberg213202e2013-01-27 00:31:33 +0200430static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
431{
432 u8 *ptr = data, *uuids_start = NULL;
433 struct bt_uuid *uuid;
434
435 if (len < 4)
436 return ptr;
437
438 list_for_each_entry(uuid, &hdev->uuids, list) {
439 u16 uuid16;
440
441 if (uuid->size != 16)
442 continue;
443
444 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
445 if (uuid16 < 0x1100)
446 continue;
447
448 if (uuid16 == PNP_INFO_SVCLASS_ID)
449 continue;
450
451 if (!uuids_start) {
452 uuids_start = ptr;
453 uuids_start[0] = 1;
454 uuids_start[1] = EIR_UUID16_ALL;
455 ptr += 2;
456 }
457
458 /* Stop if not enough space to put next UUID */
459 if ((ptr - data) + sizeof(u16) > len) {
460 uuids_start[1] = EIR_UUID16_SOME;
461 break;
462 }
463
464 *ptr++ = (uuid16 & 0x00ff);
465 *ptr++ = (uuid16 & 0xff00) >> 8;
466 uuids_start[0] += sizeof(uuid16);
467 }
468
469 return ptr;
470}
471
Johan Hedbergcdf19632013-01-27 00:31:34 +0200472static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
473{
474 u8 *ptr = data, *uuids_start = NULL;
475 struct bt_uuid *uuid;
476
477 if (len < 6)
478 return ptr;
479
480 list_for_each_entry(uuid, &hdev->uuids, list) {
481 if (uuid->size != 32)
482 continue;
483
484 if (!uuids_start) {
485 uuids_start = ptr;
486 uuids_start[0] = 1;
487 uuids_start[1] = EIR_UUID32_ALL;
488 ptr += 2;
489 }
490
491 /* Stop if not enough space to put next UUID */
492 if ((ptr - data) + sizeof(u32) > len) {
493 uuids_start[1] = EIR_UUID32_SOME;
494 break;
495 }
496
497 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
498 ptr += sizeof(u32);
499 uuids_start[0] += sizeof(u32);
500 }
501
502 return ptr;
503}
504
Johan Hedbergc00d5752013-01-27 00:31:35 +0200505static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
506{
507 u8 *ptr = data, *uuids_start = NULL;
508 struct bt_uuid *uuid;
509
510 if (len < 18)
511 return ptr;
512
513 list_for_each_entry(uuid, &hdev->uuids, list) {
514 if (uuid->size != 128)
515 continue;
516
517 if (!uuids_start) {
518 uuids_start = ptr;
519 uuids_start[0] = 1;
520 uuids_start[1] = EIR_UUID128_ALL;
521 ptr += 2;
522 }
523
524 /* Stop if not enough space to put next UUID */
525 if ((ptr - data) + 16 > len) {
526 uuids_start[1] = EIR_UUID128_SOME;
527 break;
528 }
529
530 memcpy(ptr, uuid->uuid, 16);
531 ptr += 16;
532 uuids_start[0] += 16;
533 }
534
535 return ptr;
536}
537
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300538static void create_eir(struct hci_dev *hdev, u8 *data)
539{
540 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300541 size_t name_len;
542
543 name_len = strlen(hdev->dev_name);
544
545 if (name_len > 0) {
546 /* EIR Data type */
547 if (name_len > 48) {
548 name_len = 48;
549 ptr[1] = EIR_NAME_SHORT;
550 } else
551 ptr[1] = EIR_NAME_COMPLETE;
552
553 /* EIR Data length */
554 ptr[0] = name_len + 1;
555
556 memcpy(ptr + 2, hdev->dev_name, name_len);
557
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300558 ptr += (name_len + 2);
559 }
560
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100561 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700562 ptr[0] = 2;
563 ptr[1] = EIR_TX_POWER;
564 ptr[2] = (u8) hdev->inq_tx_power;
565
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700566 ptr += 3;
567 }
568
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700569 if (hdev->devid_source > 0) {
570 ptr[0] = 9;
571 ptr[1] = EIR_DEVICE_ID;
572
573 put_unaligned_le16(hdev->devid_source, ptr + 2);
574 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
575 put_unaligned_le16(hdev->devid_product, ptr + 6);
576 put_unaligned_le16(hdev->devid_version, ptr + 8);
577
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700578 ptr += 10;
579 }
580
Johan Hedberg213202e2013-01-27 00:31:33 +0200581 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200582 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200583 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300584}
585
Johan Hedberg890ea892013-03-15 17:06:52 -0500586static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300587{
Johan Hedberg890ea892013-03-15 17:06:52 -0500588 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300589 struct hci_cp_write_eir cp;
590
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200591 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500592 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200593
Johan Hedberg976eb202012-10-24 21:12:01 +0300594 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500595 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300596
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200597 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500598 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300599
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200600 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500601 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300602
603 memset(&cp, 0, sizeof(cp));
604
605 create_eir(hdev, cp.data);
606
607 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500608 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300609
610 memcpy(hdev->eir, cp.data, sizeof(cp.data));
611
Johan Hedberg890ea892013-03-15 17:06:52 -0500612 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300613}
614
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200615static u8 get_service_classes(struct hci_dev *hdev)
616{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300617 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200618 u8 val = 0;
619
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300620 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200621 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200622
623 return val;
624}
625
Johan Hedberg890ea892013-03-15 17:06:52 -0500626static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200627{
Johan Hedberg890ea892013-03-15 17:06:52 -0500628 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200629 u8 cod[3];
630
631 BT_DBG("%s", hdev->name);
632
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200633 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500634 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200635
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200636 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500637 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200638
639 cod[0] = hdev->minor_class;
640 cod[1] = hdev->major_class;
641 cod[2] = get_service_classes(hdev);
642
643 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500644 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200645
Johan Hedberg890ea892013-03-15 17:06:52 -0500646 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200647}
648
Johan Hedberg7d785252011-12-15 00:47:39 +0200649static void service_cache_off(struct work_struct *work)
650{
651 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300652 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500653 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200654
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200655 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200656 return;
657
Johan Hedberg890ea892013-03-15 17:06:52 -0500658 hci_req_init(&req, hdev);
659
Johan Hedberg7d785252011-12-15 00:47:39 +0200660 hci_dev_lock(hdev);
661
Johan Hedberg890ea892013-03-15 17:06:52 -0500662 update_eir(&req);
663 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200664
665 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500666
667 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200668}
669
Johan Hedberg6a919082012-02-28 06:17:26 +0200670static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200671{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200672 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200673 return;
674
Johan Hedberg4f87da82012-03-02 19:55:56 +0200675 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200676
Johan Hedberg4f87da82012-03-02 19:55:56 +0200677 /* Non-mgmt controlled devices get this bit set
678 * implicitly so that pairing works for them, however
679 * for mgmt we require user-space to explicitly enable
680 * it
681 */
682 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200683}
684
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200685static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300686 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200687{
688 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200689
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200690 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200691
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300692 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200693
Johan Hedberg03811012010-12-08 00:21:06 +0200694 memset(&rp, 0, sizeof(rp));
695
Johan Hedberg03811012010-12-08 00:21:06 +0200696 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200697
698 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200699 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200700
701 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
702 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
703
704 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200705
706 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200707 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200708
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300709 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200710
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200711 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300712 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200713}
714
715static void mgmt_pending_free(struct pending_cmd *cmd)
716{
717 sock_put(cmd->sk);
718 kfree(cmd->param);
719 kfree(cmd);
720}
721
722static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300723 struct hci_dev *hdev, void *data,
724 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200725{
726 struct pending_cmd *cmd;
727
Andre Guedes12b94562012-06-07 19:05:45 -0300728 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200729 if (!cmd)
730 return NULL;
731
732 cmd->opcode = opcode;
733 cmd->index = hdev->id;
734
Andre Guedes12b94562012-06-07 19:05:45 -0300735 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200736 if (!cmd->param) {
737 kfree(cmd);
738 return NULL;
739 }
740
741 if (data)
742 memcpy(cmd->param, data, len);
743
744 cmd->sk = sk;
745 sock_hold(sk);
746
747 list_add(&cmd->list, &hdev->mgmt_pending);
748
749 return cmd;
750}
751
752static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300753 void (*cb)(struct pending_cmd *cmd,
754 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300755 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200756{
Andre Guedesa3d09352013-02-01 11:21:30 -0300757 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200758
Andre Guedesa3d09352013-02-01 11:21:30 -0300759 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200760 if (opcode > 0 && cmd->opcode != opcode)
761 continue;
762
763 cb(cmd, data);
764 }
765}
766
767static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
768{
769 struct pending_cmd *cmd;
770
771 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
772 if (cmd->opcode == opcode)
773 return cmd;
774 }
775
776 return NULL;
777}
778
779static void mgmt_pending_remove(struct pending_cmd *cmd)
780{
781 list_del(&cmd->list);
782 mgmt_pending_free(cmd);
783}
784
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200785static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200786{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200787 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200788
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200789 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300790 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200791}
792
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200793static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300794 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200795{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300796 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200797 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200798 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200799
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200800 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200801
Johan Hedberga7e80f22013-01-09 16:05:19 +0200802 if (cp->val != 0x00 && cp->val != 0x01)
803 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
804 MGMT_STATUS_INVALID_PARAMS);
805
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300806 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200807
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300808 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
809 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
810 MGMT_STATUS_BUSY);
811 goto failed;
812 }
813
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100814 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
815 cancel_delayed_work(&hdev->power_off);
816
817 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200818 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
819 data, len);
820 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100821 goto failed;
822 }
823 }
824
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200825 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200826 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200827 goto failed;
828 }
829
Johan Hedberg03811012010-12-08 00:21:06 +0200830 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
831 if (!cmd) {
832 err = -ENOMEM;
833 goto failed;
834 }
835
836 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200837 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200838 else
Johan Hedberg19202572013-01-14 22:33:51 +0200839 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200840
841 err = 0;
842
843failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300844 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200845 return err;
846}
847
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300848static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
849 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200850{
851 struct sk_buff *skb;
852 struct mgmt_hdr *hdr;
853
Andre Guedes790eff42012-06-07 19:05:46 -0300854 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200855 if (!skb)
856 return -ENOMEM;
857
858 hdr = (void *) skb_put(skb, sizeof(*hdr));
859 hdr->opcode = cpu_to_le16(event);
860 if (hdev)
861 hdr->index = cpu_to_le16(hdev->id);
862 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530863 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200864 hdr->len = cpu_to_le16(data_len);
865
866 if (data)
867 memcpy(skb_put(skb, data_len), data, data_len);
868
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100869 /* Time stamp */
870 __net_timestamp(skb);
871
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200872 hci_send_to_control(skb, skip_sk);
873 kfree_skb(skb);
874
875 return 0;
876}
877
878static int new_settings(struct hci_dev *hdev, struct sock *skip)
879{
880 __le32 ev;
881
882 ev = cpu_to_le32(get_current_settings(hdev));
883
884 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
885}
886
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300887struct cmd_lookup {
888 struct sock *sk;
889 struct hci_dev *hdev;
890 u8 mgmt_status;
891};
892
893static void settings_rsp(struct pending_cmd *cmd, void *data)
894{
895 struct cmd_lookup *match = data;
896
897 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
898
899 list_del(&cmd->list);
900
901 if (match->sk == NULL) {
902 match->sk = cmd->sk;
903 sock_hold(match->sk);
904 }
905
906 mgmt_pending_free(cmd);
907}
908
909static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
910{
911 u8 *status = data;
912
913 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
914 mgmt_pending_remove(cmd);
915}
916
Johan Hedberge6fe7982013-10-02 15:45:22 +0300917static u8 mgmt_bredr_support(struct hci_dev *hdev)
918{
919 if (!lmp_bredr_capable(hdev))
920 return MGMT_STATUS_NOT_SUPPORTED;
921 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
922 return MGMT_STATUS_REJECTED;
923 else
924 return MGMT_STATUS_SUCCESS;
925}
926
927static u8 mgmt_le_support(struct hci_dev *hdev)
928{
929 if (!lmp_le_capable(hdev))
930 return MGMT_STATUS_NOT_SUPPORTED;
931 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
932 return MGMT_STATUS_REJECTED;
933 else
934 return MGMT_STATUS_SUCCESS;
935}
936
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200937static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300938 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200939{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300940 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200941 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200942 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +0300943 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +0200944 int err;
945
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200946 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200947
Johan Hedberge6fe7982013-10-02 15:45:22 +0300948 status = mgmt_bredr_support(hdev);
949 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +0300950 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +0300951 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +0300952
Johan Hedberga7e80f22013-01-09 16:05:19 +0200953 if (cp->val != 0x00 && cp->val != 0x01)
954 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
955 MGMT_STATUS_INVALID_PARAMS);
956
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700957 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100958 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200959 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300960 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200961
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300962 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200963
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200964 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200965 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300966 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200967 goto failed;
968 }
969
970 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300971 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200972 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300973 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200974 goto failed;
975 }
976
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200977 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200978 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300979 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200980 goto failed;
981 }
982
983 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200984 bool changed = false;
985
986 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
987 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
988 changed = true;
989 }
990
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200991 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200992 if (err < 0)
993 goto failed;
994
995 if (changed)
996 err = new_settings(hdev, sk);
997
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200998 goto failed;
999 }
1000
1001 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001002 if (hdev->discov_timeout > 0) {
1003 cancel_delayed_work(&hdev->discov_off);
1004 hdev->discov_timeout = 0;
1005 }
1006
1007 if (cp->val && timeout > 0) {
1008 hdev->discov_timeout = timeout;
1009 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1010 msecs_to_jiffies(hdev->discov_timeout * 1000));
1011 }
1012
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001013 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02001014 goto failed;
1015 }
1016
1017 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1018 if (!cmd) {
1019 err = -ENOMEM;
1020 goto failed;
1021 }
1022
1023 scan = SCAN_PAGE;
1024
1025 if (cp->val)
1026 scan |= SCAN_INQUIRY;
1027 else
1028 cancel_delayed_work(&hdev->discov_off);
1029
1030 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1031 if (err < 0)
1032 mgmt_pending_remove(cmd);
1033
Johan Hedberg03811012010-12-08 00:21:06 +02001034 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001035 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001036
1037failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001038 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001039 return err;
1040}
1041
Johan Hedberg406d7802013-03-15 17:07:09 -05001042static void write_fast_connectable(struct hci_request *req, bool enable)
1043{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001044 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001045 struct hci_cp_write_page_scan_activity acp;
1046 u8 type;
1047
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001048 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1049 return;
1050
Johan Hedberg406d7802013-03-15 17:07:09 -05001051 if (enable) {
1052 type = PAGE_SCAN_TYPE_INTERLACED;
1053
1054 /* 160 msec page scan interval */
1055 acp.interval = __constant_cpu_to_le16(0x0100);
1056 } else {
1057 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1058
1059 /* default 1.28 sec page scan */
1060 acp.interval = __constant_cpu_to_le16(0x0800);
1061 }
1062
1063 acp.window = __constant_cpu_to_le16(0x0012);
1064
Johan Hedbergbd98b992013-03-15 17:07:13 -05001065 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1066 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1067 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1068 sizeof(acp), &acp);
1069
1070 if (hdev->page_scan_type != type)
1071 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001072}
1073
Johan Hedberg2b76f452013-03-15 17:07:04 -05001074static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1075{
1076 struct pending_cmd *cmd;
1077
1078 BT_DBG("status 0x%02x", status);
1079
1080 hci_dev_lock(hdev);
1081
1082 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1083 if (!cmd)
1084 goto unlock;
1085
1086 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1087
1088 mgmt_pending_remove(cmd);
1089
1090unlock:
1091 hci_dev_unlock(hdev);
1092}
1093
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001094static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001095 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001096{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001097 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001098 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001099 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001100 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001101 int err;
1102
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001103 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001104
Johan Hedberge6fe7982013-10-02 15:45:22 +03001105 status = mgmt_bredr_support(hdev);
1106 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001107 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001108 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001109
Johan Hedberga7e80f22013-01-09 16:05:19 +02001110 if (cp->val != 0x00 && cp->val != 0x01)
1111 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1112 MGMT_STATUS_INVALID_PARAMS);
1113
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001114 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001115
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001116 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001117 bool changed = false;
1118
1119 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1120 changed = true;
1121
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001122 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001123 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001124 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001125 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1126 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1127 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001128
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001129 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001130 if (err < 0)
1131 goto failed;
1132
1133 if (changed)
1134 err = new_settings(hdev, sk);
1135
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001136 goto failed;
1137 }
1138
1139 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001140 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001141 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001142 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001143 goto failed;
1144 }
1145
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001146 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001147 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001148 goto failed;
1149 }
1150
1151 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1152 if (!cmd) {
1153 err = -ENOMEM;
1154 goto failed;
1155 }
1156
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001157 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001158 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001159 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001160 scan = 0;
1161
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001162 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001163 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001164 cancel_delayed_work(&hdev->discov_off);
1165 }
1166
Johan Hedberg2b76f452013-03-15 17:07:04 -05001167 hci_req_init(&req, hdev);
1168
1169 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1170
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001171 /* If we're going from non-connectable to connectable or
1172 * vice-versa when fast connectable is enabled ensure that fast
1173 * connectable gets disabled. write_fast_connectable won't do
1174 * anything if the page scan parameters are already what they
1175 * should be.
1176 */
1177 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001178 write_fast_connectable(&req, false);
1179
Johan Hedberg2b76f452013-03-15 17:07:04 -05001180 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001181 if (err < 0)
1182 mgmt_pending_remove(cmd);
1183
1184failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001185 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001186 return err;
1187}
1188
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001189static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001190 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001191{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001192 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001193 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001194 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001195
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001196 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001197
Johan Hedberga7e80f22013-01-09 16:05:19 +02001198 if (cp->val != 0x00 && cp->val != 0x01)
1199 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1200 MGMT_STATUS_INVALID_PARAMS);
1201
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001202 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001203
1204 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001205 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001206 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001207 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001208
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001209 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001210 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001211 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001212
Marcel Holtmann55594352013-10-06 16:11:57 -07001213 if (changed)
1214 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001215
Marcel Holtmann55594352013-10-06 16:11:57 -07001216unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001217 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001218 return err;
1219}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001220
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001221static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1222 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001223{
1224 struct mgmt_mode *cp = data;
1225 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001226 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001227 int err;
1228
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001229 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001230
Johan Hedberge6fe7982013-10-02 15:45:22 +03001231 status = mgmt_bredr_support(hdev);
1232 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001233 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001234 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001235
Johan Hedberga7e80f22013-01-09 16:05:19 +02001236 if (cp->val != 0x00 && cp->val != 0x01)
1237 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1238 MGMT_STATUS_INVALID_PARAMS);
1239
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001240 hci_dev_lock(hdev);
1241
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001242 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001243 bool changed = false;
1244
1245 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001246 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001247 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1248 changed = true;
1249 }
1250
1251 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1252 if (err < 0)
1253 goto failed;
1254
1255 if (changed)
1256 err = new_settings(hdev, sk);
1257
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001258 goto failed;
1259 }
1260
1261 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001262 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001263 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001264 goto failed;
1265 }
1266
1267 val = !!cp->val;
1268
1269 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1270 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1271 goto failed;
1272 }
1273
1274 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1275 if (!cmd) {
1276 err = -ENOMEM;
1277 goto failed;
1278 }
1279
1280 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1281 if (err < 0) {
1282 mgmt_pending_remove(cmd);
1283 goto failed;
1284 }
1285
1286failed:
1287 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001288 return err;
1289}
1290
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001291static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001292{
1293 struct mgmt_mode *cp = data;
1294 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001295 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001296 int err;
1297
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001298 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001299
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001300 status = mgmt_bredr_support(hdev);
1301 if (status)
1302 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1303
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001304 if (!lmp_ssp_capable(hdev))
1305 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1306 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001307
Johan Hedberga7e80f22013-01-09 16:05:19 +02001308 if (cp->val != 0x00 && cp->val != 0x01)
1309 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1310 MGMT_STATUS_INVALID_PARAMS);
1311
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001312 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001313
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001314 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001315 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001316
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001317 if (cp->val) {
1318 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1319 &hdev->dev_flags);
1320 } else {
1321 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1322 &hdev->dev_flags);
1323 if (!changed)
1324 changed = test_and_clear_bit(HCI_HS_ENABLED,
1325 &hdev->dev_flags);
1326 else
1327 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001328 }
1329
1330 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1331 if (err < 0)
1332 goto failed;
1333
1334 if (changed)
1335 err = new_settings(hdev, sk);
1336
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001337 goto failed;
1338 }
1339
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001340 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1341 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001342 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1343 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001344 goto failed;
1345 }
1346
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001347 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001348 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1349 goto failed;
1350 }
1351
1352 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1353 if (!cmd) {
1354 err = -ENOMEM;
1355 goto failed;
1356 }
1357
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001358 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001359 if (err < 0) {
1360 mgmt_pending_remove(cmd);
1361 goto failed;
1362 }
1363
1364failed:
1365 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001366 return err;
1367}
1368
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001369static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001370{
1371 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001372 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001373 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001374 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001375
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001376 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001377
Johan Hedberge6fe7982013-10-02 15:45:22 +03001378 status = mgmt_bredr_support(hdev);
1379 if (status)
1380 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001381
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001382 if (!lmp_ssp_capable(hdev))
1383 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1384 MGMT_STATUS_NOT_SUPPORTED);
1385
1386 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1387 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1388 MGMT_STATUS_REJECTED);
1389
Johan Hedberga7e80f22013-01-09 16:05:19 +02001390 if (cp->val != 0x00 && cp->val != 0x01)
1391 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1392 MGMT_STATUS_INVALID_PARAMS);
1393
Marcel Holtmannee392692013-10-01 22:59:23 -07001394 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001395
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001396 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001397 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001398 } else {
1399 if (hdev_is_powered(hdev)) {
1400 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1401 MGMT_STATUS_REJECTED);
1402 goto unlock;
1403 }
1404
Marcel Holtmannee392692013-10-01 22:59:23 -07001405 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001406 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001407
1408 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1409 if (err < 0)
1410 goto unlock;
1411
1412 if (changed)
1413 err = new_settings(hdev, sk);
1414
1415unlock:
1416 hci_dev_unlock(hdev);
1417 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001418}
1419
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001420static void enable_advertising(struct hci_request *req)
1421{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001422 struct hci_dev *hdev = req->hdev;
1423 struct hci_cp_le_set_adv_param cp;
1424 u8 enable = 0x01;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001425
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001426 memset(&cp, 0, sizeof(cp));
1427 cp.min_interval = __constant_cpu_to_le16(0x0800);
1428 cp.max_interval = __constant_cpu_to_le16(0x0800);
1429 cp.type = LE_ADV_IND;
1430 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1431 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1432 else
1433 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1434 cp.channel_map = 0x07;
1435
1436 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1437
1438 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001439}
1440
1441static void disable_advertising(struct hci_request *req)
1442{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001443 u8 enable = 0x00;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001444
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001445 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001446}
1447
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001448static void le_enable_complete(struct hci_dev *hdev, u8 status)
1449{
1450 struct cmd_lookup match = { NULL, hdev };
1451
1452 if (status) {
1453 u8 mgmt_err = mgmt_status(status);
1454
1455 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1456 &mgmt_err);
1457 return;
1458 }
1459
1460 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1461
1462 new_settings(hdev, match.sk);
1463
1464 if (match.sk)
1465 sock_put(match.sk);
1466}
1467
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001468static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001469{
1470 struct mgmt_mode *cp = data;
1471 struct hci_cp_write_le_host_supported hci_cp;
1472 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001473 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001474 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001475 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001476
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001477 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001478
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001479 if (!lmp_le_capable(hdev))
1480 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1481 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001482
Johan Hedberga7e80f22013-01-09 16:05:19 +02001483 if (cp->val != 0x00 && cp->val != 0x01)
1484 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1485 MGMT_STATUS_INVALID_PARAMS);
1486
Johan Hedbergc73eee92013-04-19 18:35:21 +03001487 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001488 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001489 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1490 MGMT_STATUS_REJECTED);
1491
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001492 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001493
1494 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001495 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001496
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001497 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001498 bool changed = false;
1499
1500 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1501 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1502 changed = true;
1503 }
1504
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001505 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1506 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001507 changed = true;
1508 }
1509
Johan Hedberg06199cf2012-02-22 16:37:11 +02001510 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1511 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001512 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001513
1514 if (changed)
1515 err = new_settings(hdev, sk);
1516
Johan Hedberg1de028c2012-02-29 19:55:35 -08001517 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001518 }
1519
Johan Hedberg4375f102013-09-25 13:26:10 +03001520 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1521 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001522 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001523 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001524 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001525 }
1526
1527 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1528 if (!cmd) {
1529 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001530 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001531 }
1532
1533 memset(&hci_cp, 0, sizeof(hci_cp));
1534
1535 if (val) {
1536 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001537 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001538 }
1539
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001540 hci_req_init(&req, hdev);
1541
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001542 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1543 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001544
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001545 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1546 &hci_cp);
1547
1548 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301549 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001550 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001551
Johan Hedberg1de028c2012-02-29 19:55:35 -08001552unlock:
1553 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001554 return err;
1555}
1556
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001557/* This is a helper function to test for pending mgmt commands that can
1558 * cause CoD or EIR HCI commands. We can only allow one such pending
1559 * mgmt command at a time since otherwise we cannot easily track what
1560 * the current values are, will be, and based on that calculate if a new
1561 * HCI command needs to be sent and if yes with what value.
1562 */
1563static bool pending_eir_or_class(struct hci_dev *hdev)
1564{
1565 struct pending_cmd *cmd;
1566
1567 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1568 switch (cmd->opcode) {
1569 case MGMT_OP_ADD_UUID:
1570 case MGMT_OP_REMOVE_UUID:
1571 case MGMT_OP_SET_DEV_CLASS:
1572 case MGMT_OP_SET_POWERED:
1573 return true;
1574 }
1575 }
1576
1577 return false;
1578}
1579
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001580static const u8 bluetooth_base_uuid[] = {
1581 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1582 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1583};
1584
1585static u8 get_uuid_size(const u8 *uuid)
1586{
1587 u32 val;
1588
1589 if (memcmp(uuid, bluetooth_base_uuid, 12))
1590 return 128;
1591
1592 val = get_unaligned_le32(&uuid[12]);
1593 if (val > 0xffff)
1594 return 32;
1595
1596 return 16;
1597}
1598
Johan Hedberg92da6092013-03-15 17:06:55 -05001599static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1600{
1601 struct pending_cmd *cmd;
1602
1603 hci_dev_lock(hdev);
1604
1605 cmd = mgmt_pending_find(mgmt_op, hdev);
1606 if (!cmd)
1607 goto unlock;
1608
1609 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1610 hdev->dev_class, 3);
1611
1612 mgmt_pending_remove(cmd);
1613
1614unlock:
1615 hci_dev_unlock(hdev);
1616}
1617
1618static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1619{
1620 BT_DBG("status 0x%02x", status);
1621
1622 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1623}
1624
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001625static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001626{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001627 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001628 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001629 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001630 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001631 int err;
1632
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001633 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001634
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001635 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001636
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001637 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001638 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001639 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001640 goto failed;
1641 }
1642
Andre Guedes92c4c202012-06-07 19:05:44 -03001643 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001644 if (!uuid) {
1645 err = -ENOMEM;
1646 goto failed;
1647 }
1648
1649 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001650 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001651 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001652
Johan Hedbergde66aa62013-01-27 00:31:27 +02001653 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001654
Johan Hedberg890ea892013-03-15 17:06:52 -05001655 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001656
Johan Hedberg890ea892013-03-15 17:06:52 -05001657 update_class(&req);
1658 update_eir(&req);
1659
Johan Hedberg92da6092013-03-15 17:06:55 -05001660 err = hci_req_run(&req, add_uuid_complete);
1661 if (err < 0) {
1662 if (err != -ENODATA)
1663 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001664
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001665 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001666 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001667 goto failed;
1668 }
1669
1670 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001671 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001672 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001673 goto failed;
1674 }
1675
1676 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001677
1678failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001679 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001680 return err;
1681}
1682
Johan Hedberg24b78d02012-02-23 23:24:30 +02001683static bool enable_service_cache(struct hci_dev *hdev)
1684{
1685 if (!hdev_is_powered(hdev))
1686 return false;
1687
1688 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001689 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1690 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001691 return true;
1692 }
1693
1694 return false;
1695}
1696
Johan Hedberg92da6092013-03-15 17:06:55 -05001697static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1698{
1699 BT_DBG("status 0x%02x", status);
1700
1701 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1702}
1703
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001704static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001705 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001706{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001707 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001708 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001709 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001710 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 -05001711 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001712 int err, found;
1713
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001714 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001715
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001716 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001717
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001718 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001719 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001720 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001721 goto unlock;
1722 }
1723
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001724 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1725 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001726
Johan Hedberg24b78d02012-02-23 23:24:30 +02001727 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001728 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001729 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001730 goto unlock;
1731 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001732
Johan Hedberg9246a862012-02-23 21:33:16 +02001733 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001734 }
1735
1736 found = 0;
1737
Johan Hedberg056341c2013-01-27 00:31:30 +02001738 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001739 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1740 continue;
1741
1742 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001743 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001744 found++;
1745 }
1746
1747 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001748 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001749 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001750 goto unlock;
1751 }
1752
Johan Hedberg9246a862012-02-23 21:33:16 +02001753update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001754 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001755
Johan Hedberg890ea892013-03-15 17:06:52 -05001756 update_class(&req);
1757 update_eir(&req);
1758
Johan Hedberg92da6092013-03-15 17:06:55 -05001759 err = hci_req_run(&req, remove_uuid_complete);
1760 if (err < 0) {
1761 if (err != -ENODATA)
1762 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001763
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001764 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001765 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001766 goto unlock;
1767 }
1768
1769 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001770 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001771 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001772 goto unlock;
1773 }
1774
1775 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001776
1777unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001778 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001779 return err;
1780}
1781
Johan Hedberg92da6092013-03-15 17:06:55 -05001782static void set_class_complete(struct hci_dev *hdev, u8 status)
1783{
1784 BT_DBG("status 0x%02x", status);
1785
1786 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1787}
1788
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001789static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001790 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001791{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001792 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001793 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001794 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001795 int err;
1796
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001797 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001798
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001799 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001800 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1801 MGMT_STATUS_NOT_SUPPORTED);
1802
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001803 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001804
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001805 if (pending_eir_or_class(hdev)) {
1806 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1807 MGMT_STATUS_BUSY);
1808 goto unlock;
1809 }
1810
1811 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1812 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1813 MGMT_STATUS_INVALID_PARAMS);
1814 goto unlock;
1815 }
1816
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001817 hdev->major_class = cp->major;
1818 hdev->minor_class = cp->minor;
1819
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001820 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001821 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001822 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001823 goto unlock;
1824 }
1825
Johan Hedberg890ea892013-03-15 17:06:52 -05001826 hci_req_init(&req, hdev);
1827
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001828 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001829 hci_dev_unlock(hdev);
1830 cancel_delayed_work_sync(&hdev->service_cache);
1831 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001832 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001833 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001834
Johan Hedberg890ea892013-03-15 17:06:52 -05001835 update_class(&req);
1836
Johan Hedberg92da6092013-03-15 17:06:55 -05001837 err = hci_req_run(&req, set_class_complete);
1838 if (err < 0) {
1839 if (err != -ENODATA)
1840 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001841
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001842 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001843 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001844 goto unlock;
1845 }
1846
1847 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001848 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001849 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001850 goto unlock;
1851 }
1852
1853 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001854
Johan Hedbergb5235a62012-02-21 14:32:24 +02001855unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001856 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001857 return err;
1858}
1859
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001860static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001861 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001862{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001863 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001864 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001865 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001866
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001867 BT_DBG("request for %s", hdev->name);
1868
1869 if (!lmp_bredr_capable(hdev))
1870 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1871 MGMT_STATUS_NOT_SUPPORTED);
1872
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001873 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001874
Johan Hedberg86742e12011-11-07 23:13:38 +02001875 expected_len = sizeof(*cp) + key_count *
1876 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001877 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001878 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001879 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001880 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001881 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001882 }
1883
Johan Hedberg4ae14302013-01-20 14:27:13 +02001884 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1885 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1886 MGMT_STATUS_INVALID_PARAMS);
1887
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001888 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001889 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001890
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001891 for (i = 0; i < key_count; i++) {
1892 struct mgmt_link_key_info *key = &cp->keys[i];
1893
1894 if (key->addr.type != BDADDR_BREDR)
1895 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1896 MGMT_STATUS_INVALID_PARAMS);
1897 }
1898
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001899 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001900
1901 hci_link_keys_clear(hdev);
1902
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001903 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001904 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001905 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001906 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001907
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001908 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001909 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001910
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001911 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001912 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001913 }
1914
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001915 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001916
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001917 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001918
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001919 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001920}
1921
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001922static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001923 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001924{
1925 struct mgmt_ev_device_unpaired ev;
1926
1927 bacpy(&ev.addr.bdaddr, bdaddr);
1928 ev.addr.type = addr_type;
1929
1930 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001931 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001932}
1933
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001934static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001935 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001936{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001937 struct mgmt_cp_unpair_device *cp = data;
1938 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001939 struct hci_cp_disconnect dc;
1940 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001941 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001942 int err;
1943
Johan Hedberga8a1d192011-11-10 15:54:38 +02001944 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001945 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1946 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001947
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001948 if (!bdaddr_type_is_valid(cp->addr.type))
1949 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1950 MGMT_STATUS_INVALID_PARAMS,
1951 &rp, sizeof(rp));
1952
Johan Hedberg118da702013-01-20 14:27:20 +02001953 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1954 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1955 MGMT_STATUS_INVALID_PARAMS,
1956 &rp, sizeof(rp));
1957
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001958 hci_dev_lock(hdev);
1959
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001960 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001961 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001962 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001963 goto unlock;
1964 }
1965
Andre Guedes591f47f2012-04-24 21:02:49 -03001966 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001967 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1968 else
1969 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001970
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001971 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001972 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001973 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001974 goto unlock;
1975 }
1976
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001977 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001978 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001979 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001980 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001981 else
1982 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001983 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001984 } else {
1985 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001986 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001987
Johan Hedberga8a1d192011-11-10 15:54:38 +02001988 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001989 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001990 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001991 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001992 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001993 }
1994
Johan Hedberg124f6e32012-02-09 13:50:12 +02001995 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001996 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001997 if (!cmd) {
1998 err = -ENOMEM;
1999 goto unlock;
2000 }
2001
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002002 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002003 dc.reason = 0x13; /* Remote User Terminated Connection */
2004 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2005 if (err < 0)
2006 mgmt_pending_remove(cmd);
2007
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002008unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002009 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002010 return err;
2011}
2012
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002013static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002014 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002015{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002016 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002017 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002018 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002019 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002020 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002021 int err;
2022
2023 BT_DBG("");
2024
Johan Hedberg06a63b12013-01-20 14:27:21 +02002025 memset(&rp, 0, sizeof(rp));
2026 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2027 rp.addr.type = cp->addr.type;
2028
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002029 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002030 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2031 MGMT_STATUS_INVALID_PARAMS,
2032 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002033
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002034 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002035
2036 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002037 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2038 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002039 goto failed;
2040 }
2041
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002042 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002043 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2044 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002045 goto failed;
2046 }
2047
Andre Guedes591f47f2012-04-24 21:02:49 -03002048 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002049 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2050 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002051 else
2052 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002053
Vishal Agarwalf9607272012-06-13 05:32:43 +05302054 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002055 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2056 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002057 goto failed;
2058 }
2059
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002060 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002061 if (!cmd) {
2062 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002063 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002064 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002065
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002066 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002067 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002068
2069 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2070 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002071 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002072
2073failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002074 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002075 return err;
2076}
2077
Andre Guedes57c14772012-04-24 21:02:50 -03002078static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002079{
2080 switch (link_type) {
2081 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002082 switch (addr_type) {
2083 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002084 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002085
Johan Hedberg48264f02011-11-09 13:58:58 +02002086 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002087 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002088 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002089 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002090
Johan Hedberg4c659c32011-11-07 23:13:39 +02002091 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002092 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002093 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002094 }
2095}
2096
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002097static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2098 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002099{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002100 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002101 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002102 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002103 int err;
2104 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002105
2106 BT_DBG("");
2107
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002108 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002109
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002110 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002111 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002112 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002113 goto unlock;
2114 }
2115
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002116 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002117 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2118 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002119 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002120 }
2121
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002122 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002123 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002124 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002125 err = -ENOMEM;
2126 goto unlock;
2127 }
2128
Johan Hedberg2784eb42011-01-21 13:56:35 +02002129 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002130 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002131 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2132 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002133 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002134 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002135 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002136 continue;
2137 i++;
2138 }
2139
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002140 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002141
Johan Hedberg4c659c32011-11-07 23:13:39 +02002142 /* Recalculate length in case of filtered SCO connections, etc */
2143 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002144
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002145 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002146 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002147
Johan Hedberga38528f2011-01-22 06:46:43 +02002148 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002149
2150unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002151 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002152 return err;
2153}
2154
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002155static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002156 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002157{
2158 struct pending_cmd *cmd;
2159 int err;
2160
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002161 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002162 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002163 if (!cmd)
2164 return -ENOMEM;
2165
Johan Hedbergd8457692012-02-17 14:24:57 +02002166 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002167 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002168 if (err < 0)
2169 mgmt_pending_remove(cmd);
2170
2171 return err;
2172}
2173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002174static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002175 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002176{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002177 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002178 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002179 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002180 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002181 int err;
2182
2183 BT_DBG("");
2184
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002185 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002186
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002187 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002188 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002189 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002190 goto failed;
2191 }
2192
Johan Hedbergd8457692012-02-17 14:24:57 +02002193 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002194 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002195 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002196 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002197 goto failed;
2198 }
2199
2200 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002201 struct mgmt_cp_pin_code_neg_reply ncp;
2202
2203 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002204
2205 BT_ERR("PIN code is not 16 bytes long");
2206
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002207 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002208 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002209 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002210 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002211
2212 goto failed;
2213 }
2214
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002215 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002216 if (!cmd) {
2217 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002218 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002219 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002220
Johan Hedbergd8457692012-02-17 14:24:57 +02002221 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002222 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002223 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002224
2225 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2226 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002227 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002228
2229failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002230 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002231 return err;
2232}
2233
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002234static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2235 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002236{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002237 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002238
2239 BT_DBG("");
2240
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002241 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002242
2243 hdev->io_capability = cp->io_capability;
2244
2245 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002246 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002247
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002248 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002249
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002250 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2251 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002252}
2253
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002254static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002255{
2256 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002257 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002258
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002259 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002260 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2261 continue;
2262
Johan Hedberge9a416b2011-02-19 12:05:56 -03002263 if (cmd->user_data != conn)
2264 continue;
2265
2266 return cmd;
2267 }
2268
2269 return NULL;
2270}
2271
2272static void pairing_complete(struct pending_cmd *cmd, u8 status)
2273{
2274 struct mgmt_rp_pair_device rp;
2275 struct hci_conn *conn = cmd->user_data;
2276
Johan Hedbergba4e5642011-11-11 00:07:34 +02002277 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002278 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002279
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002280 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002281 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002282
2283 /* So we don't get further callbacks for this connection */
2284 conn->connect_cfm_cb = NULL;
2285 conn->security_cfm_cb = NULL;
2286 conn->disconn_cfm_cb = NULL;
2287
David Herrmann76a68ba2013-04-06 20:28:37 +02002288 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002289
Johan Hedberga664b5b2011-02-19 12:06:02 -03002290 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002291}
2292
2293static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2294{
2295 struct pending_cmd *cmd;
2296
2297 BT_DBG("status %u", status);
2298
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002299 cmd = find_pairing(conn);
2300 if (!cmd)
2301 BT_DBG("Unable to find a pending command");
2302 else
Johan Hedberge2113262012-02-18 15:20:03 +02002303 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002304}
2305
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302306static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2307{
2308 struct pending_cmd *cmd;
2309
2310 BT_DBG("status %u", status);
2311
2312 if (!status)
2313 return;
2314
2315 cmd = find_pairing(conn);
2316 if (!cmd)
2317 BT_DBG("Unable to find a pending command");
2318 else
2319 pairing_complete(cmd, mgmt_status(status));
2320}
2321
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002322static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002323 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002324{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002325 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002326 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002327 struct pending_cmd *cmd;
2328 u8 sec_level, auth_type;
2329 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002330 int err;
2331
2332 BT_DBG("");
2333
Szymon Jancf950a30e2013-01-18 12:48:07 +01002334 memset(&rp, 0, sizeof(rp));
2335 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2336 rp.addr.type = cp->addr.type;
2337
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002338 if (!bdaddr_type_is_valid(cp->addr.type))
2339 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2340 MGMT_STATUS_INVALID_PARAMS,
2341 &rp, sizeof(rp));
2342
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002343 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002344
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002345 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002346 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2347 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002348 goto unlock;
2349 }
2350
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002351 sec_level = BT_SECURITY_MEDIUM;
2352 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002353 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002354 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002355 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002356
Andre Guedes591f47f2012-04-24 21:02:49 -03002357 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002358 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2359 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002360 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002361 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2362 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002363
Ville Tervo30e76272011-02-22 16:10:53 -03002364 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002365 int status;
2366
2367 if (PTR_ERR(conn) == -EBUSY)
2368 status = MGMT_STATUS_BUSY;
2369 else
2370 status = MGMT_STATUS_CONNECT_FAILED;
2371
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002372 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002373 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002374 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002375 goto unlock;
2376 }
2377
2378 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002379 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002380 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002381 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002382 goto unlock;
2383 }
2384
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002385 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002386 if (!cmd) {
2387 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002388 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002389 goto unlock;
2390 }
2391
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002392 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002393 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002394 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302395 else
2396 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002397
Johan Hedberge9a416b2011-02-19 12:05:56 -03002398 conn->security_cfm_cb = pairing_complete_cb;
2399 conn->disconn_cfm_cb = pairing_complete_cb;
2400 conn->io_capability = cp->io_cap;
2401 cmd->user_data = conn;
2402
2403 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002404 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002405 pairing_complete(cmd, 0);
2406
2407 err = 0;
2408
2409unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002410 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002411 return err;
2412}
2413
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002414static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2415 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002416{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002417 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002418 struct pending_cmd *cmd;
2419 struct hci_conn *conn;
2420 int err;
2421
2422 BT_DBG("");
2423
Johan Hedberg28424702012-02-02 04:02:29 +02002424 hci_dev_lock(hdev);
2425
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002426 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002427 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002428 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002429 goto unlock;
2430 }
2431
Johan Hedberg28424702012-02-02 04:02:29 +02002432 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2433 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002434 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002435 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002436 goto unlock;
2437 }
2438
2439 conn = cmd->user_data;
2440
2441 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002442 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002443 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002444 goto unlock;
2445 }
2446
2447 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2448
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002449 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002450 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002451unlock:
2452 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002453 return err;
2454}
2455
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002456static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002457 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002458 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002459{
Johan Hedberga5c29682011-02-19 12:05:57 -03002460 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002461 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002462 int err;
2463
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002464 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002465
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002466 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002467 err = cmd_complete(sk, hdev->id, mgmt_op,
2468 MGMT_STATUS_NOT_POWERED, addr,
2469 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002470 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002471 }
2472
Johan Hedberg1707c602013-03-15 17:07:15 -05002473 if (addr->type == BDADDR_BREDR)
2474 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002475 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002476 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002477
Johan Hedberg272d90d2012-02-09 15:26:12 +02002478 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002479 err = cmd_complete(sk, hdev->id, mgmt_op,
2480 MGMT_STATUS_NOT_CONNECTED, addr,
2481 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002482 goto done;
2483 }
2484
Johan Hedberg1707c602013-03-15 17:07:15 -05002485 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002486 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002487 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002488
Brian Gix5fe57d92011-12-21 16:12:13 -08002489 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002490 err = cmd_complete(sk, hdev->id, mgmt_op,
2491 MGMT_STATUS_SUCCESS, addr,
2492 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002493 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002494 err = cmd_complete(sk, hdev->id, mgmt_op,
2495 MGMT_STATUS_FAILED, addr,
2496 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002497
Brian Gix47c15e22011-11-16 13:53:14 -08002498 goto done;
2499 }
2500
Johan Hedberg1707c602013-03-15 17:07:15 -05002501 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002502 if (!cmd) {
2503 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002504 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002505 }
2506
Brian Gix0df4c182011-11-16 13:53:13 -08002507 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002508 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2509 struct hci_cp_user_passkey_reply cp;
2510
Johan Hedberg1707c602013-03-15 17:07:15 -05002511 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002512 cp.passkey = passkey;
2513 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2514 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002515 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2516 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002517
Johan Hedberga664b5b2011-02-19 12:06:02 -03002518 if (err < 0)
2519 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002520
Brian Gix0df4c182011-11-16 13:53:13 -08002521done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002522 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002523 return err;
2524}
2525
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302526static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2527 void *data, u16 len)
2528{
2529 struct mgmt_cp_pin_code_neg_reply *cp = data;
2530
2531 BT_DBG("");
2532
Johan Hedberg1707c602013-03-15 17:07:15 -05002533 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302534 MGMT_OP_PIN_CODE_NEG_REPLY,
2535 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2536}
2537
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002538static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2539 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002540{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002541 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002542
2543 BT_DBG("");
2544
2545 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002546 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002547 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002548
Johan Hedberg1707c602013-03-15 17:07:15 -05002549 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002550 MGMT_OP_USER_CONFIRM_REPLY,
2551 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002552}
2553
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002554static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002555 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002556{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002557 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002558
2559 BT_DBG("");
2560
Johan Hedberg1707c602013-03-15 17:07:15 -05002561 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002562 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2563 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002564}
2565
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002566static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2567 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002568{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002569 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002570
2571 BT_DBG("");
2572
Johan Hedberg1707c602013-03-15 17:07:15 -05002573 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002574 MGMT_OP_USER_PASSKEY_REPLY,
2575 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002576}
2577
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002578static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002579 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002580{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002581 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002582
2583 BT_DBG("");
2584
Johan Hedberg1707c602013-03-15 17:07:15 -05002585 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002586 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2587 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002588}
2589
Johan Hedberg13928972013-03-15 17:07:00 -05002590static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002591{
Johan Hedberg13928972013-03-15 17:07:00 -05002592 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002593 struct hci_cp_write_local_name cp;
2594
Johan Hedberg13928972013-03-15 17:07:00 -05002595 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002596
Johan Hedberg890ea892013-03-15 17:06:52 -05002597 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002598}
2599
Johan Hedberg13928972013-03-15 17:07:00 -05002600static void set_name_complete(struct hci_dev *hdev, u8 status)
2601{
2602 struct mgmt_cp_set_local_name *cp;
2603 struct pending_cmd *cmd;
2604
2605 BT_DBG("status 0x%02x", status);
2606
2607 hci_dev_lock(hdev);
2608
2609 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2610 if (!cmd)
2611 goto unlock;
2612
2613 cp = cmd->param;
2614
2615 if (status)
2616 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2617 mgmt_status(status));
2618 else
2619 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2620 cp, sizeof(*cp));
2621
2622 mgmt_pending_remove(cmd);
2623
2624unlock:
2625 hci_dev_unlock(hdev);
2626}
2627
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002628static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002629 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002630{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002631 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002632 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002633 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002634 int err;
2635
2636 BT_DBG("");
2637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002638 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002639
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002640 /* If the old values are the same as the new ones just return a
2641 * direct command complete event.
2642 */
2643 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2644 !memcmp(hdev->short_name, cp->short_name,
2645 sizeof(hdev->short_name))) {
2646 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2647 data, len);
2648 goto failed;
2649 }
2650
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002651 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002652
Johan Hedbergb5235a62012-02-21 14:32:24 +02002653 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002654 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002655
2656 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002657 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002658 if (err < 0)
2659 goto failed;
2660
2661 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002662 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002663
Johan Hedbergb5235a62012-02-21 14:32:24 +02002664 goto failed;
2665 }
2666
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002667 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002668 if (!cmd) {
2669 err = -ENOMEM;
2670 goto failed;
2671 }
2672
Johan Hedberg13928972013-03-15 17:07:00 -05002673 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2674
Johan Hedberg890ea892013-03-15 17:06:52 -05002675 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002676
2677 if (lmp_bredr_capable(hdev)) {
2678 update_name(&req);
2679 update_eir(&req);
2680 }
2681
2682 if (lmp_le_capable(hdev))
2683 hci_update_ad(&req);
2684
Johan Hedberg13928972013-03-15 17:07:00 -05002685 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002686 if (err < 0)
2687 mgmt_pending_remove(cmd);
2688
2689failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002690 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002691 return err;
2692}
2693
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002694static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002695 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002696{
Szymon Jancc35938b2011-03-22 13:12:21 +01002697 struct pending_cmd *cmd;
2698 int err;
2699
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002700 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002701
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002702 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002703
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002704 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002705 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002706 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002707 goto unlock;
2708 }
2709
Andre Guedes9a1a1992012-07-24 15:03:48 -03002710 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002711 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002712 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002713 goto unlock;
2714 }
2715
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002716 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002717 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002718 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002719 goto unlock;
2720 }
2721
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002722 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002723 if (!cmd) {
2724 err = -ENOMEM;
2725 goto unlock;
2726 }
2727
2728 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2729 if (err < 0)
2730 mgmt_pending_remove(cmd);
2731
2732unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002733 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002734 return err;
2735}
2736
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002737static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002738 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002739{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002740 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002741 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002742 int err;
2743
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002744 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002745
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002746 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002747
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002748 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002749 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002750 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002751 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002752 else
Szymon Janca6785be2012-12-13 15:11:21 +01002753 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002754
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002755 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002756 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002757
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002758 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002759 return err;
2760}
2761
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002762static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002763 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002764{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002765 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002766 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002767 int err;
2768
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002769 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002770
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002771 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002772
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002773 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002774 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002775 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002776 else
Szymon Janca6785be2012-12-13 15:11:21 +01002777 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002778
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002779 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002780 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002781
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002782 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002783 return err;
2784}
2785
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002786static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2787{
2788 struct pending_cmd *cmd;
2789 u8 type;
2790 int err;
2791
2792 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2793
2794 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2795 if (!cmd)
2796 return -ENOENT;
2797
2798 type = hdev->discovery.type;
2799
2800 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2801 &type, sizeof(type));
2802 mgmt_pending_remove(cmd);
2803
2804 return err;
2805}
2806
Andre Guedes7c307722013-04-30 15:29:28 -03002807static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2808{
2809 BT_DBG("status %d", status);
2810
2811 if (status) {
2812 hci_dev_lock(hdev);
2813 mgmt_start_discovery_failed(hdev, status);
2814 hci_dev_unlock(hdev);
2815 return;
2816 }
2817
2818 hci_dev_lock(hdev);
2819 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2820 hci_dev_unlock(hdev);
2821
2822 switch (hdev->discovery.type) {
2823 case DISCOV_TYPE_LE:
2824 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002825 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002826 break;
2827
2828 case DISCOV_TYPE_INTERLEAVED:
2829 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002830 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002831 break;
2832
2833 case DISCOV_TYPE_BREDR:
2834 break;
2835
2836 default:
2837 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2838 }
2839}
2840
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002841static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002842 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002843{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002844 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002845 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002846 struct hci_cp_le_set_scan_param param_cp;
2847 struct hci_cp_le_set_scan_enable enable_cp;
2848 struct hci_cp_inquiry inq_cp;
2849 struct hci_request req;
2850 /* General inquiry access code (GIAC) */
2851 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002852 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002853 int err;
2854
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002855 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002856
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002857 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002858
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002859 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002860 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002861 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002862 goto failed;
2863 }
2864
Andre Guedes642be6c2012-03-21 00:03:37 -03002865 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2866 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2867 MGMT_STATUS_BUSY);
2868 goto failed;
2869 }
2870
Johan Hedbergff9ef572012-01-04 14:23:45 +02002871 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002872 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002873 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002874 goto failed;
2875 }
2876
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002877 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002878 if (!cmd) {
2879 err = -ENOMEM;
2880 goto failed;
2881 }
2882
Andre Guedes4aab14e2012-02-17 20:39:36 -03002883 hdev->discovery.type = cp->type;
2884
Andre Guedes7c307722013-04-30 15:29:28 -03002885 hci_req_init(&req, hdev);
2886
Andre Guedes4aab14e2012-02-17 20:39:36 -03002887 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002888 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002889 status = mgmt_bredr_support(hdev);
2890 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002891 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002892 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002893 mgmt_pending_remove(cmd);
2894 goto failed;
2895 }
2896
Andre Guedes7c307722013-04-30 15:29:28 -03002897 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2898 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2899 MGMT_STATUS_BUSY);
2900 mgmt_pending_remove(cmd);
2901 goto failed;
2902 }
2903
2904 hci_inquiry_cache_flush(hdev);
2905
2906 memset(&inq_cp, 0, sizeof(inq_cp));
2907 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002908 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002909 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002910 break;
2911
2912 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002913 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002914 status = mgmt_le_support(hdev);
2915 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002916 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002917 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002918 mgmt_pending_remove(cmd);
2919 goto failed;
2920 }
2921
Andre Guedes7c307722013-04-30 15:29:28 -03002922 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002923 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002924 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2925 MGMT_STATUS_NOT_SUPPORTED);
2926 mgmt_pending_remove(cmd);
2927 goto failed;
2928 }
2929
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002930 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002931 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2932 MGMT_STATUS_REJECTED);
2933 mgmt_pending_remove(cmd);
2934 goto failed;
2935 }
2936
2937 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2938 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2939 MGMT_STATUS_BUSY);
2940 mgmt_pending_remove(cmd);
2941 goto failed;
2942 }
2943
2944 memset(&param_cp, 0, sizeof(param_cp));
2945 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002946 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2947 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002948 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2949 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2950 else
2951 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002952 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2953 &param_cp);
2954
2955 memset(&enable_cp, 0, sizeof(enable_cp));
2956 enable_cp.enable = LE_SCAN_ENABLE;
2957 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2958 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2959 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002960 break;
2961
Andre Guedesf39799f2012-02-17 20:39:35 -03002962 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002963 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2964 MGMT_STATUS_INVALID_PARAMS);
2965 mgmt_pending_remove(cmd);
2966 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002967 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002968
Andre Guedes7c307722013-04-30 15:29:28 -03002969 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002970 if (err < 0)
2971 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002972 else
2973 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002974
2975failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002976 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002977 return err;
2978}
2979
Andre Guedes1183fdc2013-04-30 15:29:35 -03002980static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2981{
2982 struct pending_cmd *cmd;
2983 int err;
2984
2985 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2986 if (!cmd)
2987 return -ENOENT;
2988
2989 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2990 &hdev->discovery.type, sizeof(hdev->discovery.type));
2991 mgmt_pending_remove(cmd);
2992
2993 return err;
2994}
2995
Andre Guedes0e05bba2013-04-30 15:29:33 -03002996static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2997{
2998 BT_DBG("status %d", status);
2999
3000 hci_dev_lock(hdev);
3001
3002 if (status) {
3003 mgmt_stop_discovery_failed(hdev, status);
3004 goto unlock;
3005 }
3006
3007 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3008
3009unlock:
3010 hci_dev_unlock(hdev);
3011}
3012
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003013static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003014 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003015{
Johan Hedbergd9306502012-02-20 23:25:18 +02003016 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003017 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003018 struct hci_cp_remote_name_req_cancel cp;
3019 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003020 struct hci_request req;
3021 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003022 int err;
3023
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003024 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003025
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003026 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003027
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003028 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003029 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003030 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3031 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003032 goto unlock;
3033 }
3034
3035 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003036 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003037 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3038 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003039 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003040 }
3041
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003042 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003043 if (!cmd) {
3044 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003045 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003046 }
3047
Andre Guedes0e05bba2013-04-30 15:29:33 -03003048 hci_req_init(&req, hdev);
3049
Andre Guedese0d9727e2012-03-20 15:15:36 -03003050 switch (hdev->discovery.state) {
3051 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003052 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3053 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3054 } else {
3055 cancel_delayed_work(&hdev->le_scan_disable);
3056
3057 memset(&enable_cp, 0, sizeof(enable_cp));
3058 enable_cp.enable = LE_SCAN_DISABLE;
3059 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3060 sizeof(enable_cp), &enable_cp);
3061 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003062
Andre Guedese0d9727e2012-03-20 15:15:36 -03003063 break;
3064
3065 case DISCOVERY_RESOLVING:
3066 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003067 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003068 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003069 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003070 err = cmd_complete(sk, hdev->id,
3071 MGMT_OP_STOP_DISCOVERY, 0,
3072 &mgmt_cp->type,
3073 sizeof(mgmt_cp->type));
3074 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3075 goto unlock;
3076 }
3077
3078 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003079 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3080 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003081
3082 break;
3083
3084 default:
3085 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003086
3087 mgmt_pending_remove(cmd);
3088 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3089 MGMT_STATUS_FAILED, &mgmt_cp->type,
3090 sizeof(mgmt_cp->type));
3091 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003092 }
3093
Andre Guedes0e05bba2013-04-30 15:29:33 -03003094 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003095 if (err < 0)
3096 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003097 else
3098 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003099
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003100unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003101 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003102 return err;
3103}
3104
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003105static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003106 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003107{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003108 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003109 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003110 int err;
3111
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003112 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003113
Johan Hedberg561aafb2012-01-04 13:31:59 +02003114 hci_dev_lock(hdev);
3115
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003116 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003117 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003118 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003119 goto failed;
3120 }
3121
Johan Hedberga198e7b2012-02-17 14:27:06 +02003122 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003123 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003124 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003125 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003126 goto failed;
3127 }
3128
3129 if (cp->name_known) {
3130 e->name_state = NAME_KNOWN;
3131 list_del(&e->list);
3132 } else {
3133 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003134 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003135 }
3136
Johan Hedberge3846622013-01-09 15:29:33 +02003137 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3138 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003139
3140failed:
3141 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003142 return err;
3143}
3144
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003145static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003146 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003147{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003148 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003149 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003150 int err;
3151
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003152 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003153
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003154 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003155 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3156 MGMT_STATUS_INVALID_PARAMS,
3157 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003158
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003159 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003160
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003161 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003162 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003163 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003164 else
Szymon Janca6785be2012-12-13 15:11:21 +01003165 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003166
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003167 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003168 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003169
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003170 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003171
3172 return err;
3173}
3174
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003175static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003176 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003177{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003178 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003179 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003180 int err;
3181
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003182 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003183
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003184 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003185 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3186 MGMT_STATUS_INVALID_PARAMS,
3187 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003188
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003189 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003190
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003191 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003192 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003193 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003194 else
Szymon Janca6785be2012-12-13 15:11:21 +01003195 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003196
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003197 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003198 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003199
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003200 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003201
3202 return err;
3203}
3204
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003205static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3206 u16 len)
3207{
3208 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003209 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003210 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003211 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003212
3213 BT_DBG("%s", hdev->name);
3214
Szymon Jancc72d4b82012-03-16 16:02:57 +01003215 source = __le16_to_cpu(cp->source);
3216
3217 if (source > 0x0002)
3218 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3219 MGMT_STATUS_INVALID_PARAMS);
3220
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003221 hci_dev_lock(hdev);
3222
Szymon Jancc72d4b82012-03-16 16:02:57 +01003223 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003224 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3225 hdev->devid_product = __le16_to_cpu(cp->product);
3226 hdev->devid_version = __le16_to_cpu(cp->version);
3227
3228 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3229
Johan Hedberg890ea892013-03-15 17:06:52 -05003230 hci_req_init(&req, hdev);
3231 update_eir(&req);
3232 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003233
3234 hci_dev_unlock(hdev);
3235
3236 return err;
3237}
3238
Johan Hedberg4375f102013-09-25 13:26:10 +03003239static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3240{
3241 struct cmd_lookup match = { NULL, hdev };
3242
3243 if (status) {
3244 u8 mgmt_err = mgmt_status(status);
3245
3246 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3247 cmd_status_rsp, &mgmt_err);
3248 return;
3249 }
3250
3251 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3252 &match);
3253
3254 new_settings(hdev, match.sk);
3255
3256 if (match.sk)
3257 sock_put(match.sk);
3258}
3259
Marcel Holtmann21b51872013-10-10 09:47:53 -07003260static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3261 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003262{
3263 struct mgmt_mode *cp = data;
3264 struct pending_cmd *cmd;
3265 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003266 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003267 int err;
3268
3269 BT_DBG("request for %s", hdev->name);
3270
Johan Hedberge6fe7982013-10-02 15:45:22 +03003271 status = mgmt_le_support(hdev);
3272 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003273 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003274 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003275
3276 if (cp->val != 0x00 && cp->val != 0x01)
3277 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3278 MGMT_STATUS_INVALID_PARAMS);
3279
3280 hci_dev_lock(hdev);
3281
3282 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003283 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003284
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003285 /* The following conditions are ones which mean that we should
3286 * not do any HCI communication but directly send a mgmt
3287 * response to user space (after toggling the flag if
3288 * necessary).
3289 */
3290 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003291 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003292 bool changed = false;
3293
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003294 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3295 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003296 changed = true;
3297 }
3298
3299 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3300 if (err < 0)
3301 goto unlock;
3302
3303 if (changed)
3304 err = new_settings(hdev, sk);
3305
3306 goto unlock;
3307 }
3308
3309 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3310 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3311 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3312 MGMT_STATUS_BUSY);
3313 goto unlock;
3314 }
3315
3316 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3317 if (!cmd) {
3318 err = -ENOMEM;
3319 goto unlock;
3320 }
3321
3322 hci_req_init(&req, hdev);
3323
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003324 if (val)
3325 enable_advertising(&req);
3326 else
3327 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003328
3329 err = hci_req_run(&req, set_advertising_complete);
3330 if (err < 0)
3331 mgmt_pending_remove(cmd);
3332
3333unlock:
3334 hci_dev_unlock(hdev);
3335 return err;
3336}
3337
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003338static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3339 void *data, u16 len)
3340{
3341 struct mgmt_cp_set_static_address *cp = data;
3342 int err;
3343
3344 BT_DBG("%s", hdev->name);
3345
Marcel Holtmann62af4442013-10-02 22:10:32 -07003346 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003347 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003348 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003349
3350 if (hdev_is_powered(hdev))
3351 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3352 MGMT_STATUS_REJECTED);
3353
3354 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3355 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3356 return cmd_status(sk, hdev->id,
3357 MGMT_OP_SET_STATIC_ADDRESS,
3358 MGMT_STATUS_INVALID_PARAMS);
3359
3360 /* Two most significant bits shall be set */
3361 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3362 return cmd_status(sk, hdev->id,
3363 MGMT_OP_SET_STATIC_ADDRESS,
3364 MGMT_STATUS_INVALID_PARAMS);
3365 }
3366
3367 hci_dev_lock(hdev);
3368
3369 bacpy(&hdev->static_addr, &cp->bdaddr);
3370
3371 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3372
3373 hci_dev_unlock(hdev);
3374
3375 return err;
3376}
3377
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003378static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3379 void *data, u16 len)
3380{
3381 struct mgmt_cp_set_scan_params *cp = data;
3382 __u16 interval, window;
3383 int err;
3384
3385 BT_DBG("%s", hdev->name);
3386
3387 if (!lmp_le_capable(hdev))
3388 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3389 MGMT_STATUS_NOT_SUPPORTED);
3390
3391 interval = __le16_to_cpu(cp->interval);
3392
3393 if (interval < 0x0004 || interval > 0x4000)
3394 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3395 MGMT_STATUS_INVALID_PARAMS);
3396
3397 window = __le16_to_cpu(cp->window);
3398
3399 if (window < 0x0004 || window > 0x4000)
3400 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3401 MGMT_STATUS_INVALID_PARAMS);
3402
3403 hci_dev_lock(hdev);
3404
3405 hdev->le_scan_interval = interval;
3406 hdev->le_scan_window = window;
3407
3408 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3409
3410 hci_dev_unlock(hdev);
3411
3412 return err;
3413}
3414
Johan Hedberg33e38b32013-03-15 17:07:05 -05003415static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3416{
3417 struct pending_cmd *cmd;
3418
3419 BT_DBG("status 0x%02x", status);
3420
3421 hci_dev_lock(hdev);
3422
3423 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3424 if (!cmd)
3425 goto unlock;
3426
3427 if (status) {
3428 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3429 mgmt_status(status));
3430 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003431 struct mgmt_mode *cp = cmd->param;
3432
3433 if (cp->val)
3434 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3435 else
3436 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3437
Johan Hedberg33e38b32013-03-15 17:07:05 -05003438 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3439 new_settings(hdev, cmd->sk);
3440 }
3441
3442 mgmt_pending_remove(cmd);
3443
3444unlock:
3445 hci_dev_unlock(hdev);
3446}
3447
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003448static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003449 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003450{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003451 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003452 struct pending_cmd *cmd;
3453 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003454 int err;
3455
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003456 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003457
Johan Hedberg56f87902013-10-02 13:43:13 +03003458 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3459 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003460 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3461 MGMT_STATUS_NOT_SUPPORTED);
3462
Johan Hedberga7e80f22013-01-09 16:05:19 +02003463 if (cp->val != 0x00 && cp->val != 0x01)
3464 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3465 MGMT_STATUS_INVALID_PARAMS);
3466
Johan Hedberg5400c042012-02-21 16:40:33 +02003467 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003468 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003469 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003470
3471 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003472 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003473 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003474
3475 hci_dev_lock(hdev);
3476
Johan Hedberg05cbf292013-03-15 17:07:07 -05003477 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3478 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3479 MGMT_STATUS_BUSY);
3480 goto unlock;
3481 }
3482
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003483 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3484 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3485 hdev);
3486 goto unlock;
3487 }
3488
Johan Hedberg33e38b32013-03-15 17:07:05 -05003489 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3490 data, len);
3491 if (!cmd) {
3492 err = -ENOMEM;
3493 goto unlock;
3494 }
3495
3496 hci_req_init(&req, hdev);
3497
Johan Hedberg406d7802013-03-15 17:07:09 -05003498 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003499
3500 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003501 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003502 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003503 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003504 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003505 }
3506
Johan Hedberg33e38b32013-03-15 17:07:05 -05003507unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003508 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003509
Antti Julkuf6422ec2011-06-22 13:11:56 +03003510 return err;
3511}
3512
Johan Hedberg0663ca22013-10-02 13:43:14 +03003513static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3514{
3515 struct pending_cmd *cmd;
3516
3517 BT_DBG("status 0x%02x", status);
3518
3519 hci_dev_lock(hdev);
3520
3521 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3522 if (!cmd)
3523 goto unlock;
3524
3525 if (status) {
3526 u8 mgmt_err = mgmt_status(status);
3527
3528 /* We need to restore the flag if related HCI commands
3529 * failed.
3530 */
3531 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3532
3533 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3534 } else {
3535 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3536 new_settings(hdev, cmd->sk);
3537 }
3538
3539 mgmt_pending_remove(cmd);
3540
3541unlock:
3542 hci_dev_unlock(hdev);
3543}
3544
3545static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3546{
3547 struct mgmt_mode *cp = data;
3548 struct pending_cmd *cmd;
3549 struct hci_request req;
3550 int err;
3551
3552 BT_DBG("request for %s", hdev->name);
3553
3554 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3555 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3556 MGMT_STATUS_NOT_SUPPORTED);
3557
3558 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3559 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3560 MGMT_STATUS_REJECTED);
3561
3562 if (cp->val != 0x00 && cp->val != 0x01)
3563 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3564 MGMT_STATUS_INVALID_PARAMS);
3565
3566 hci_dev_lock(hdev);
3567
3568 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3569 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3570 goto unlock;
3571 }
3572
3573 if (!hdev_is_powered(hdev)) {
3574 if (!cp->val) {
3575 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3576 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3577 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3578 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3579 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3580 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3581 }
3582
3583 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3584
3585 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3586 if (err < 0)
3587 goto unlock;
3588
3589 err = new_settings(hdev, sk);
3590 goto unlock;
3591 }
3592
3593 /* Reject disabling when powered on */
3594 if (!cp->val) {
3595 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3596 MGMT_STATUS_REJECTED);
3597 goto unlock;
3598 }
3599
3600 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3601 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3602 MGMT_STATUS_BUSY);
3603 goto unlock;
3604 }
3605
3606 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3607 if (!cmd) {
3608 err = -ENOMEM;
3609 goto unlock;
3610 }
3611
3612 /* We need to flip the bit already here so that hci_update_ad
3613 * generates the correct flags.
3614 */
3615 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3616
3617 hci_req_init(&req, hdev);
3618 hci_update_ad(&req);
3619 err = hci_req_run(&req, set_bredr_complete);
3620 if (err < 0)
3621 mgmt_pending_remove(cmd);
3622
3623unlock:
3624 hci_dev_unlock(hdev);
3625 return err;
3626}
3627
Johan Hedberg3f706b72013-01-20 14:27:16 +02003628static bool ltk_is_valid(struct mgmt_ltk_info *key)
3629{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003630 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3631 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003632 if (key->master != 0x00 && key->master != 0x01)
3633 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003634 if (!bdaddr_type_is_le(key->addr.type))
3635 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003636 return true;
3637}
3638
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003639static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003640 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003641{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003642 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3643 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003644 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003645
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003646 BT_DBG("request for %s", hdev->name);
3647
3648 if (!lmp_le_capable(hdev))
3649 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3650 MGMT_STATUS_NOT_SUPPORTED);
3651
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003652 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003653
3654 expected_len = sizeof(*cp) + key_count *
3655 sizeof(struct mgmt_ltk_info);
3656 if (expected_len != len) {
3657 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003658 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003659 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003660 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003661 }
3662
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003663 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003664
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003665 for (i = 0; i < key_count; i++) {
3666 struct mgmt_ltk_info *key = &cp->keys[i];
3667
Johan Hedberg3f706b72013-01-20 14:27:16 +02003668 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003669 return cmd_status(sk, hdev->id,
3670 MGMT_OP_LOAD_LONG_TERM_KEYS,
3671 MGMT_STATUS_INVALID_PARAMS);
3672 }
3673
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003674 hci_dev_lock(hdev);
3675
3676 hci_smp_ltks_clear(hdev);
3677
3678 for (i = 0; i < key_count; i++) {
3679 struct mgmt_ltk_info *key = &cp->keys[i];
3680 u8 type;
3681
3682 if (key->master)
3683 type = HCI_SMP_LTK;
3684 else
3685 type = HCI_SMP_LTK_SLAVE;
3686
Hemant Gupta4596fde2012-04-16 14:57:40 +05303687 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003688 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003689 type, 0, key->authenticated, key->val,
3690 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003691 }
3692
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003693 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3694 NULL, 0);
3695
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003696 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003697
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003698 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003699}
3700
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003701static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003702 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3703 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003704 bool var_len;
3705 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003706} mgmt_handlers[] = {
3707 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003708 { read_version, false, MGMT_READ_VERSION_SIZE },
3709 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3710 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3711 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3712 { set_powered, false, MGMT_SETTING_SIZE },
3713 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3714 { set_connectable, false, MGMT_SETTING_SIZE },
3715 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3716 { set_pairable, false, MGMT_SETTING_SIZE },
3717 { set_link_security, false, MGMT_SETTING_SIZE },
3718 { set_ssp, false, MGMT_SETTING_SIZE },
3719 { set_hs, false, MGMT_SETTING_SIZE },
3720 { set_le, false, MGMT_SETTING_SIZE },
3721 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3722 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3723 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3724 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3725 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3726 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3727 { disconnect, false, MGMT_DISCONNECT_SIZE },
3728 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3729 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3730 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3731 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3732 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3733 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3734 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3735 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3736 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3737 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3738 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3739 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3740 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3741 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3742 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3743 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3744 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3745 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3746 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003747 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003748 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003749 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003750 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003751 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003752};
3753
3754
Johan Hedberg03811012010-12-08 00:21:06 +02003755int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3756{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003757 void *buf;
3758 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003759 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003760 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003761 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003762 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003763 int err;
3764
3765 BT_DBG("got %zu bytes", msglen);
3766
3767 if (msglen < sizeof(*hdr))
3768 return -EINVAL;
3769
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003770 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003771 if (!buf)
3772 return -ENOMEM;
3773
3774 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3775 err = -EFAULT;
3776 goto done;
3777 }
3778
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003779 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003780 opcode = __le16_to_cpu(hdr->opcode);
3781 index = __le16_to_cpu(hdr->index);
3782 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003783
3784 if (len != msglen - sizeof(*hdr)) {
3785 err = -EINVAL;
3786 goto done;
3787 }
3788
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003789 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003790 hdev = hci_dev_get(index);
3791 if (!hdev) {
3792 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003793 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003794 goto done;
3795 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003796
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02003797 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
3798 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003799 err = cmd_status(sk, index, opcode,
3800 MGMT_STATUS_INVALID_INDEX);
3801 goto done;
3802 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003803 }
3804
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003805 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003806 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003807 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003808 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003809 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003810 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003811 }
3812
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003813 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003814 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003815 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003816 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003817 goto done;
3818 }
3819
Johan Hedbergbe22b542012-03-01 22:24:41 +02003820 handler = &mgmt_handlers[opcode];
3821
3822 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003823 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003824 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003825 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003826 goto done;
3827 }
3828
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003829 if (hdev)
3830 mgmt_init_hdev(sk, hdev);
3831
3832 cp = buf + sizeof(*hdr);
3833
Johan Hedbergbe22b542012-03-01 22:24:41 +02003834 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003835 if (err < 0)
3836 goto done;
3837
Johan Hedberg03811012010-12-08 00:21:06 +02003838 err = msglen;
3839
3840done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003841 if (hdev)
3842 hci_dev_put(hdev);
3843
Johan Hedberg03811012010-12-08 00:21:06 +02003844 kfree(buf);
3845 return err;
3846}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003847
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003848void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003849{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003850 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003851 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003852
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003853 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003854}
3855
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003856void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003857{
Johan Hedberg5f159032012-03-02 03:13:19 +02003858 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003859
Marcel Holtmann1514b892013-10-06 08:25:01 -07003860 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003861 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003862
Johan Hedberg744cf192011-11-08 20:40:14 +02003863 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003864
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003865 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003866}
3867
Johan Hedberg890ea892013-03-15 17:06:52 -05003868static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003869{
Johan Hedberg890ea892013-03-15 17:06:52 -05003870 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003871 u8 scan = 0;
3872
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003873 /* Ensure that fast connectable is disabled. This function will
3874 * not do anything if the page scan parameters are already what
3875 * they should be.
3876 */
3877 write_fast_connectable(req, false);
3878
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003879 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3880 scan |= SCAN_PAGE;
3881 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3882 scan |= SCAN_INQUIRY;
3883
Johan Hedberg890ea892013-03-15 17:06:52 -05003884 if (scan)
3885 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003886}
3887
Johan Hedberg229ab392013-03-15 17:06:53 -05003888static void powered_complete(struct hci_dev *hdev, u8 status)
3889{
3890 struct cmd_lookup match = { NULL, hdev };
3891
3892 BT_DBG("status 0x%02x", status);
3893
3894 hci_dev_lock(hdev);
3895
3896 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3897
3898 new_settings(hdev, match.sk);
3899
3900 hci_dev_unlock(hdev);
3901
3902 if (match.sk)
3903 sock_put(match.sk);
3904}
3905
Johan Hedberg70da6242013-03-15 17:06:51 -05003906static int powered_update_hci(struct hci_dev *hdev)
3907{
Johan Hedberg890ea892013-03-15 17:06:52 -05003908 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003909 u8 link_sec;
3910
Johan Hedberg890ea892013-03-15 17:06:52 -05003911 hci_req_init(&req, hdev);
3912
Johan Hedberg70da6242013-03-15 17:06:51 -05003913 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3914 !lmp_host_ssp_capable(hdev)) {
3915 u8 ssp = 1;
3916
Johan Hedberg890ea892013-03-15 17:06:52 -05003917 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003918 }
3919
Johan Hedbergc73eee92013-04-19 18:35:21 +03003920 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3921 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003922 struct hci_cp_write_le_host_supported cp;
3923
3924 cp.le = 1;
3925 cp.simul = lmp_le_br_capable(hdev);
3926
3927 /* Check first if we already have the right
3928 * host state (host features set)
3929 */
3930 if (cp.le != lmp_host_le_capable(hdev) ||
3931 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003932 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3933 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003934
3935 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3936 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003937 }
3938
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003939 if (lmp_le_capable(hdev)) {
3940 /* Set random address to static address if configured */
3941 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3942 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3943 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003944
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003945 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3946 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003947 }
3948
Johan Hedberg70da6242013-03-15 17:06:51 -05003949 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3950 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003951 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3952 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003953
3954 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003955 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3956 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003957 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003958 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003959 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003960 }
3961
Johan Hedberg229ab392013-03-15 17:06:53 -05003962 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003963}
3964
Johan Hedberg744cf192011-11-08 20:40:14 +02003965int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003966{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003967 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003968 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3969 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003970 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003971
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003972 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3973 return 0;
3974
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003975 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003976 if (powered_update_hci(hdev) == 0)
3977 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003978
Johan Hedberg229ab392013-03-15 17:06:53 -05003979 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3980 &match);
3981 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003982 }
3983
Johan Hedberg229ab392013-03-15 17:06:53 -05003984 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3985 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3986
3987 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3988 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3989 zero_cod, sizeof(zero_cod), NULL);
3990
3991new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003992 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003993
3994 if (match.sk)
3995 sock_put(match.sk);
3996
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003997 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003998}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003999
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004000void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004001{
4002 struct pending_cmd *cmd;
4003 u8 status;
4004
4005 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4006 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004007 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004008
4009 if (err == -ERFKILL)
4010 status = MGMT_STATUS_RFKILLED;
4011 else
4012 status = MGMT_STATUS_FAILED;
4013
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004014 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004015
4016 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004017}
4018
Johan Hedberg744cf192011-11-08 20:40:14 +02004019int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004020{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004021 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004022 bool changed = false;
4023 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004024
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004025 if (discoverable) {
4026 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4027 changed = true;
4028 } else {
4029 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
4030 changed = true;
4031 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02004032
Johan Hedberged9b5f22012-02-21 20:47:06 +02004033 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004034 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004035
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004036 if (changed)
4037 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004038
Johan Hedberg73f22f62010-12-29 16:00:25 +02004039 if (match.sk)
4040 sock_put(match.sk);
4041
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004042 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004043}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004044
Johan Hedberg744cf192011-11-08 20:40:14 +02004045int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004046{
Johan Hedberg2b76f452013-03-15 17:07:04 -05004047 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004048 bool changed = false;
4049 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004050
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004051 if (connectable) {
4052 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4053 changed = true;
4054 } else {
4055 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4056 changed = true;
4057 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004058
Johan Hedberg2b76f452013-03-15 17:07:04 -05004059 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004060
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004061 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05004062 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004063
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004064 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004065}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004066
Johan Hedberg744cf192011-11-08 20:40:14 +02004067int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004068{
Johan Hedbergca69b792011-11-11 18:10:00 +02004069 u8 mgmt_err = mgmt_status(status);
4070
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004071 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004072 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004073 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004074
4075 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004076 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004077 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004078
4079 return 0;
4080}
4081
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004082int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4083 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004084{
Johan Hedberg86742e12011-11-07 23:13:38 +02004085 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004086
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004087 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004088
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004089 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004090 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004091 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004092 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004093 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004094 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004095
Johan Hedberg744cf192011-11-08 20:40:14 +02004096 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004097}
Johan Hedbergf7520542011-01-20 12:34:39 +02004098
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004099int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4100{
4101 struct mgmt_ev_new_long_term_key ev;
4102
4103 memset(&ev, 0, sizeof(ev));
4104
4105 ev.store_hint = persistent;
4106 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004107 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004108 ev.key.authenticated = key->authenticated;
4109 ev.key.enc_size = key->enc_size;
4110 ev.key.ediv = key->ediv;
4111
4112 if (key->type == HCI_SMP_LTK)
4113 ev.key.master = 1;
4114
4115 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4116 memcpy(ev.key.val, key->val, sizeof(key->val));
4117
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004118 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4119 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004120}
4121
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004122void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4123 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4124 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004125{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004126 char buf[512];
4127 struct mgmt_ev_device_connected *ev = (void *) buf;
4128 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004129
Johan Hedbergb644ba32012-01-17 21:48:47 +02004130 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004131 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004132
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004133 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004134
Johan Hedbergb644ba32012-01-17 21:48:47 +02004135 if (name_len > 0)
4136 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004137 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004138
4139 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004140 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004141 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004142
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004143 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004144
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004145 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4146 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004147}
4148
Johan Hedberg8962ee72011-01-20 12:40:27 +02004149static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4150{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004151 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004152 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004153 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004154
Johan Hedberg88c3df12012-02-09 14:27:38 +02004155 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4156 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004157
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004158 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004159 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004160
4161 *sk = cmd->sk;
4162 sock_hold(*sk);
4163
Johan Hedberga664b5b2011-02-19 12:06:02 -03004164 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004165}
4166
Johan Hedberg124f6e32012-02-09 13:50:12 +02004167static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004168{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004169 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004170 struct mgmt_cp_unpair_device *cp = cmd->param;
4171 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004172
4173 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004174 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4175 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004176
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004177 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4178
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004179 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004180
4181 mgmt_pending_remove(cmd);
4182}
4183
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004184void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4185 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004186{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004187 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004188 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004189
Johan Hedberg744cf192011-11-08 20:40:14 +02004190 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004191
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004192 bacpy(&ev.addr.bdaddr, bdaddr);
4193 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4194 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004195
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004196 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004197
4198 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004199 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004200
Johan Hedberg124f6e32012-02-09 13:50:12 +02004201 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004202 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004203}
4204
Marcel Holtmann78929242013-10-06 23:55:47 -07004205void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4206 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004207{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004208 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004209 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004210
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004211 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4212 hdev);
4213
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004214 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004215 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004216 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004217
Johan Hedberg88c3df12012-02-09 14:27:38 +02004218 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004219 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004220
Marcel Holtmann78929242013-10-06 23:55:47 -07004221 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4222 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004223
Johan Hedberga664b5b2011-02-19 12:06:02 -03004224 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004225}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004226
Marcel Holtmann445608d2013-10-06 23:55:48 -07004227void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4228 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004229{
4230 struct mgmt_ev_connect_failed ev;
4231
Johan Hedberg4c659c32011-11-07 23:13:39 +02004232 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004233 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004234 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004235
Marcel Holtmann445608d2013-10-06 23:55:48 -07004236 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004237}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004238
Johan Hedberg744cf192011-11-08 20:40:14 +02004239int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004240{
4241 struct mgmt_ev_pin_code_request ev;
4242
Johan Hedbergd8457692012-02-17 14:24:57 +02004243 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004244 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004245 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004246
Johan Hedberg744cf192011-11-08 20:40:14 +02004247 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004248 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004249}
4250
Johan Hedberg744cf192011-11-08 20:40:14 +02004251int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004252 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004253{
4254 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004255 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004256 int err;
4257
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004258 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004259 if (!cmd)
4260 return -ENOENT;
4261
Johan Hedbergd8457692012-02-17 14:24:57 +02004262 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004263 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004264
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004265 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004266 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004267
Johan Hedberga664b5b2011-02-19 12:06:02 -03004268 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004269
4270 return err;
4271}
4272
Johan Hedberg744cf192011-11-08 20:40:14 +02004273int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004274 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004275{
4276 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004277 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004278 int err;
4279
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004280 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004281 if (!cmd)
4282 return -ENOENT;
4283
Johan Hedbergd8457692012-02-17 14:24:57 +02004284 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004285 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004286
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004287 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004288 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004289
Johan Hedberga664b5b2011-02-19 12:06:02 -03004290 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004291
4292 return err;
4293}
Johan Hedberga5c29682011-02-19 12:05:57 -03004294
Johan Hedberg744cf192011-11-08 20:40:14 +02004295int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004296 u8 link_type, u8 addr_type, __le32 value,
4297 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004298{
4299 struct mgmt_ev_user_confirm_request ev;
4300
Johan Hedberg744cf192011-11-08 20:40:14 +02004301 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004302
Johan Hedberg272d90d2012-02-09 15:26:12 +02004303 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004304 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004305 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02004306 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004307
Johan Hedberg744cf192011-11-08 20:40:14 +02004308 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004309 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004310}
4311
Johan Hedberg272d90d2012-02-09 15:26:12 +02004312int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004313 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004314{
4315 struct mgmt_ev_user_passkey_request ev;
4316
4317 BT_DBG("%s", hdev->name);
4318
Johan Hedberg272d90d2012-02-09 15:26:12 +02004319 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004320 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004321
4322 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004323 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004324}
4325
Brian Gix0df4c182011-11-16 13:53:13 -08004326static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004327 u8 link_type, u8 addr_type, u8 status,
4328 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004329{
4330 struct pending_cmd *cmd;
4331 struct mgmt_rp_user_confirm_reply rp;
4332 int err;
4333
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004334 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004335 if (!cmd)
4336 return -ENOENT;
4337
Johan Hedberg272d90d2012-02-09 15:26:12 +02004338 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004339 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004340 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004341 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004342
Johan Hedberga664b5b2011-02-19 12:06:02 -03004343 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004344
4345 return err;
4346}
4347
Johan Hedberg744cf192011-11-08 20:40:14 +02004348int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004349 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004350{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004351 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004352 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004353}
4354
Johan Hedberg272d90d2012-02-09 15:26:12 +02004355int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004356 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004357{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004358 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004359 status,
4360 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004361}
Johan Hedberg2a611692011-02-19 12:06:00 -03004362
Brian Gix604086b2011-11-23 08:28:33 -08004363int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004364 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004365{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004366 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004367 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004368}
4369
Johan Hedberg272d90d2012-02-09 15:26:12 +02004370int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004371 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004372{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004373 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004374 status,
4375 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004376}
4377
Johan Hedberg92a25252012-09-06 18:39:26 +03004378int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4379 u8 link_type, u8 addr_type, u32 passkey,
4380 u8 entered)
4381{
4382 struct mgmt_ev_passkey_notify ev;
4383
4384 BT_DBG("%s", hdev->name);
4385
4386 bacpy(&ev.addr.bdaddr, bdaddr);
4387 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4388 ev.passkey = __cpu_to_le32(passkey);
4389 ev.entered = entered;
4390
4391 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4392}
4393
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004394int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004395 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004396{
4397 struct mgmt_ev_auth_failed ev;
4398
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004399 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004400 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004401 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004402
Johan Hedberg744cf192011-11-08 20:40:14 +02004403 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004404}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004405
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004406int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4407{
4408 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004409 bool changed = false;
4410 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004411
4412 if (status) {
4413 u8 mgmt_err = mgmt_status(status);
4414 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004415 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004416 return 0;
4417 }
4418
Johan Hedberg47990ea2012-02-22 11:58:37 +02004419 if (test_bit(HCI_AUTH, &hdev->flags)) {
4420 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4421 changed = true;
4422 } else {
4423 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4424 changed = true;
4425 }
4426
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004427 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004428 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004429
Johan Hedberg47990ea2012-02-22 11:58:37 +02004430 if (changed)
4431 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004432
4433 if (match.sk)
4434 sock_put(match.sk);
4435
4436 return err;
4437}
4438
Johan Hedberg890ea892013-03-15 17:06:52 -05004439static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004440{
Johan Hedberg890ea892013-03-15 17:06:52 -05004441 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004442 struct hci_cp_write_eir cp;
4443
Johan Hedberg976eb202012-10-24 21:12:01 +03004444 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004445 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004446
Johan Hedbergc80da272012-02-22 15:38:48 +02004447 memset(hdev->eir, 0, sizeof(hdev->eir));
4448
Johan Hedbergcacaf522012-02-21 00:52:42 +02004449 memset(&cp, 0, sizeof(cp));
4450
Johan Hedberg890ea892013-03-15 17:06:52 -05004451 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004452}
4453
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004454int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004455{
4456 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004457 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004458 bool changed = false;
4459 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004460
4461 if (status) {
4462 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004463
4464 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004465 &hdev->dev_flags)) {
4466 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004467 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004468 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004469
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004470 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4471 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004472
4473 return err;
4474 }
4475
4476 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004477 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004478 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004479 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4480 if (!changed)
4481 changed = test_and_clear_bit(HCI_HS_ENABLED,
4482 &hdev->dev_flags);
4483 else
4484 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004485 }
4486
4487 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4488
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004489 if (changed)
4490 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004491
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004492 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004493 sock_put(match.sk);
4494
Johan Hedberg890ea892013-03-15 17:06:52 -05004495 hci_req_init(&req, hdev);
4496
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004497 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004498 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004499 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004500 clear_eir(&req);
4501
4502 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004503
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004504 return err;
4505}
4506
Johan Hedberg92da6092013-03-15 17:06:55 -05004507static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004508{
4509 struct cmd_lookup *match = data;
4510
Johan Hedberg90e70452012-02-23 23:09:40 +02004511 if (match->sk == NULL) {
4512 match->sk = cmd->sk;
4513 sock_hold(match->sk);
4514 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004515}
4516
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004517int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004518 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004519{
Johan Hedberg90e70452012-02-23 23:09:40 +02004520 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4521 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004522
Johan Hedberg92da6092013-03-15 17:06:55 -05004523 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4524 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4525 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004526
4527 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004528 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4529 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004530
4531 if (match.sk)
4532 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004533
4534 return err;
4535}
4536
Johan Hedberg744cf192011-11-08 20:40:14 +02004537int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004538{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004539 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004540 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004541
Johan Hedberg13928972013-03-15 17:07:00 -05004542 if (status)
4543 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004544
4545 memset(&ev, 0, sizeof(ev));
4546 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004547 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004548
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004549 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004550 if (!cmd) {
4551 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004552
Johan Hedberg13928972013-03-15 17:07:00 -05004553 /* If this is a HCI command related to powering on the
4554 * HCI dev don't send any mgmt signals.
4555 */
4556 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4557 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004558 }
4559
Johan Hedberg13928972013-03-15 17:07:00 -05004560 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4561 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004562}
Szymon Jancc35938b2011-03-22 13:12:21 +01004563
Johan Hedberg744cf192011-11-08 20:40:14 +02004564int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004565 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004566{
4567 struct pending_cmd *cmd;
4568 int err;
4569
Johan Hedberg744cf192011-11-08 20:40:14 +02004570 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004571
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004572 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004573 if (!cmd)
4574 return -ENOENT;
4575
4576 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004577 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4578 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004579 } else {
4580 struct mgmt_rp_read_local_oob_data rp;
4581
4582 memcpy(rp.hash, hash, sizeof(rp.hash));
4583 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4584
Johan Hedberg744cf192011-11-08 20:40:14 +02004585 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004586 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4587 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004588 }
4589
4590 mgmt_pending_remove(cmd);
4591
4592 return err;
4593}
Johan Hedberge17acd42011-03-30 23:57:16 +03004594
Marcel Holtmann901801b2013-10-06 23:55:51 -07004595void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4596 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4597 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004598{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004599 char buf[512];
4600 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004601 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004602
Andre Guedes12602d02013-04-30 15:29:40 -03004603 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004604 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004605
Johan Hedberg1dc06092012-01-15 21:01:23 +02004606 /* Leave 5 bytes for a potential CoD field */
4607 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004608 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004609
Johan Hedberg1dc06092012-01-15 21:01:23 +02004610 memset(buf, 0, sizeof(buf));
4611
Johan Hedberge319d2e2012-01-15 19:51:59 +02004612 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004613 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004614 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004615 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304616 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004617 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304618 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004619
Johan Hedberg1dc06092012-01-15 21:01:23 +02004620 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004621 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004622
Johan Hedberg1dc06092012-01-15 21:01:23 +02004623 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4624 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004625 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004626
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004627 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004628 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004629
Marcel Holtmann901801b2013-10-06 23:55:51 -07004630 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004631}
Johan Hedberga88a9652011-03-30 13:18:12 +03004632
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004633void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4634 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004635{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004636 struct mgmt_ev_device_found *ev;
4637 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4638 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004639
Johan Hedbergb644ba32012-01-17 21:48:47 +02004640 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004641
Johan Hedbergb644ba32012-01-17 21:48:47 +02004642 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004643
Johan Hedbergb644ba32012-01-17 21:48:47 +02004644 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004645 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004646 ev->rssi = rssi;
4647
4648 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004649 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004650
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004651 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004652
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004653 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004654}
Johan Hedberg314b2382011-04-27 10:29:57 -04004655
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004656void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004657{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004658 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004659 struct pending_cmd *cmd;
4660
Andre Guedes343fb142011-11-22 17:14:19 -03004661 BT_DBG("%s discovering %u", hdev->name, discovering);
4662
Johan Hedberg164a6e72011-11-01 17:06:44 +02004663 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004664 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004665 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004666 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004667
4668 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004669 u8 type = hdev->discovery.type;
4670
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004671 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4672 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004673 mgmt_pending_remove(cmd);
4674 }
4675
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004676 memset(&ev, 0, sizeof(ev));
4677 ev.type = hdev->discovery.type;
4678 ev.discovering = discovering;
4679
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004680 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004681}
Antti Julku5e762442011-08-25 16:48:02 +03004682
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004683int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004684{
4685 struct pending_cmd *cmd;
4686 struct mgmt_ev_device_blocked ev;
4687
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004688 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004689
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004690 bacpy(&ev.addr.bdaddr, bdaddr);
4691 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004692
Johan Hedberg744cf192011-11-08 20:40:14 +02004693 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004694 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004695}
4696
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004697int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004698{
4699 struct pending_cmd *cmd;
4700 struct mgmt_ev_device_unblocked ev;
4701
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004702 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004703
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004704 bacpy(&ev.addr.bdaddr, bdaddr);
4705 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004706
Johan Hedberg744cf192011-11-08 20:40:14 +02004707 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004708 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004709}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004710
4711static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4712{
4713 BT_DBG("%s status %u", hdev->name, status);
4714
4715 /* Clear the advertising mgmt setting if we failed to re-enable it */
4716 if (status) {
4717 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004718 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004719 }
4720}
4721
4722void mgmt_reenable_advertising(struct hci_dev *hdev)
4723{
4724 struct hci_request req;
4725
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004726 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004727 return;
4728
4729 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4730 return;
4731
4732 hci_req_init(&req, hdev);
4733 enable_advertising(&req);
4734
4735 /* If this fails we have no option but to let user space know
4736 * that we've disabled advertising.
4737 */
4738 if (hci_req_run(&req, adv_enable_complete) < 0) {
4739 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004740 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004741 }
4742}