blob: 292e81fcfa958a8b971bf81a280f6615c5300ad1 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070033
34#include "smp.h"
Johan Hedberg03811012010-12-08 00:21:06 +020035
Johan Hedberg2da9c552012-02-17 14:39:28 +020036#define MGMT_VERSION 1
Marcel Holtmann9ab8cf32013-10-02 05:18:31 -070037#define MGMT_REVISION 4
Johan Hedberg02d98122010-12-13 21:07:04 +020038
Johan Hedberge70bb2e2012-02-13 16:59:33 +020039static const u16 mgmt_commands[] = {
40 MGMT_OP_READ_INDEX_LIST,
41 MGMT_OP_READ_INFO,
42 MGMT_OP_SET_POWERED,
43 MGMT_OP_SET_DISCOVERABLE,
44 MGMT_OP_SET_CONNECTABLE,
45 MGMT_OP_SET_FAST_CONNECTABLE,
46 MGMT_OP_SET_PAIRABLE,
47 MGMT_OP_SET_LINK_SECURITY,
48 MGMT_OP_SET_SSP,
49 MGMT_OP_SET_HS,
50 MGMT_OP_SET_LE,
51 MGMT_OP_SET_DEV_CLASS,
52 MGMT_OP_SET_LOCAL_NAME,
53 MGMT_OP_ADD_UUID,
54 MGMT_OP_REMOVE_UUID,
55 MGMT_OP_LOAD_LINK_KEYS,
56 MGMT_OP_LOAD_LONG_TERM_KEYS,
57 MGMT_OP_DISCONNECT,
58 MGMT_OP_GET_CONNECTIONS,
59 MGMT_OP_PIN_CODE_REPLY,
60 MGMT_OP_PIN_CODE_NEG_REPLY,
61 MGMT_OP_SET_IO_CAPABILITY,
62 MGMT_OP_PAIR_DEVICE,
63 MGMT_OP_CANCEL_PAIR_DEVICE,
64 MGMT_OP_UNPAIR_DEVICE,
65 MGMT_OP_USER_CONFIRM_REPLY,
66 MGMT_OP_USER_CONFIRM_NEG_REPLY,
67 MGMT_OP_USER_PASSKEY_REPLY,
68 MGMT_OP_USER_PASSKEY_NEG_REPLY,
69 MGMT_OP_READ_LOCAL_OOB_DATA,
70 MGMT_OP_ADD_REMOTE_OOB_DATA,
71 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
72 MGMT_OP_START_DISCOVERY,
73 MGMT_OP_STOP_DISCOVERY,
74 MGMT_OP_CONFIRM_NAME,
75 MGMT_OP_BLOCK_DEVICE,
76 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070077 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030078 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030079 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070080 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070081 MGMT_OP_SET_SCAN_PARAMS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020082};
83
84static const u16 mgmt_events[] = {
85 MGMT_EV_CONTROLLER_ERROR,
86 MGMT_EV_INDEX_ADDED,
87 MGMT_EV_INDEX_REMOVED,
88 MGMT_EV_NEW_SETTINGS,
89 MGMT_EV_CLASS_OF_DEV_CHANGED,
90 MGMT_EV_LOCAL_NAME_CHANGED,
91 MGMT_EV_NEW_LINK_KEY,
92 MGMT_EV_NEW_LONG_TERM_KEY,
93 MGMT_EV_DEVICE_CONNECTED,
94 MGMT_EV_DEVICE_DISCONNECTED,
95 MGMT_EV_CONNECT_FAILED,
96 MGMT_EV_PIN_CODE_REQUEST,
97 MGMT_EV_USER_CONFIRM_REQUEST,
98 MGMT_EV_USER_PASSKEY_REQUEST,
99 MGMT_EV_AUTH_FAILED,
100 MGMT_EV_DEVICE_FOUND,
101 MGMT_EV_DISCOVERING,
102 MGMT_EV_DEVICE_BLOCKED,
103 MGMT_EV_DEVICE_UNBLOCKED,
104 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300105 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200106};
107
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800108#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200109
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200110#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
111 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
112
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200113struct pending_cmd {
114 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200115 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100117 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300119 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200120};
121
Johan Hedbergca69b792011-11-11 18:10:00 +0200122/* HCI to MGMT error code conversion table */
123static u8 mgmt_status_table[] = {
124 MGMT_STATUS_SUCCESS,
125 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
126 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
127 MGMT_STATUS_FAILED, /* Hardware Failure */
128 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
129 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
130 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
131 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
132 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
133 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
134 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
135 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
136 MGMT_STATUS_BUSY, /* Command Disallowed */
137 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
138 MGMT_STATUS_REJECTED, /* Rejected Security */
139 MGMT_STATUS_REJECTED, /* Rejected Personal */
140 MGMT_STATUS_TIMEOUT, /* Host Timeout */
141 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
142 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
143 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
144 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
145 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
146 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
147 MGMT_STATUS_BUSY, /* Repeated Attempts */
148 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
149 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
150 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
151 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
152 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
153 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
154 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
155 MGMT_STATUS_FAILED, /* Unspecified Error */
156 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
157 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
158 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
159 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
160 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
161 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
162 MGMT_STATUS_FAILED, /* Unit Link Key Used */
163 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
164 MGMT_STATUS_TIMEOUT, /* Instant Passed */
165 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
166 MGMT_STATUS_FAILED, /* Transaction Collision */
167 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
168 MGMT_STATUS_REJECTED, /* QoS Rejected */
169 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
170 MGMT_STATUS_REJECTED, /* Insufficient Security */
171 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
172 MGMT_STATUS_BUSY, /* Role Switch Pending */
173 MGMT_STATUS_FAILED, /* Slot Violation */
174 MGMT_STATUS_FAILED, /* Role Switch Failed */
175 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
176 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
177 MGMT_STATUS_BUSY, /* Host Busy Pairing */
178 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
179 MGMT_STATUS_BUSY, /* Controller Busy */
180 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
181 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
182 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
183 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
184 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
185};
186
187static u8 mgmt_status(u8 hci_status)
188{
189 if (hci_status < ARRAY_SIZE(mgmt_status_table))
190 return mgmt_status_table[hci_status];
191
192 return MGMT_STATUS_FAILED;
193}
194
Szymon Janc4e51eae2011-02-25 19:05:48 +0100195static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200196{
197 struct sk_buff *skb;
198 struct mgmt_hdr *hdr;
199 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300200 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200201
Szymon Janc34eb5252011-02-28 14:10:08 +0100202 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200203
Andre Guedes790eff42012-06-07 19:05:46 -0300204 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200205 if (!skb)
206 return -ENOMEM;
207
208 hdr = (void *) skb_put(skb, sizeof(*hdr));
209
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530210 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100211 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212 hdr->len = cpu_to_le16(sizeof(*ev));
213
214 ev = (void *) skb_put(skb, sizeof(*ev));
215 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200216 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200217
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300218 err = sock_queue_rcv_skb(sk, skb);
219 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200220 kfree_skb(skb);
221
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300222 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223}
224
Johan Hedbergaee9b212012-02-18 15:07:59 +0200225static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300226 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200227{
228 struct sk_buff *skb;
229 struct mgmt_hdr *hdr;
230 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300231 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200232
233 BT_DBG("sock %p", sk);
234
Andre Guedes790eff42012-06-07 19:05:46 -0300235 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200236 if (!skb)
237 return -ENOMEM;
238
239 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200240
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530241 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100242 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200243 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200244
Johan Hedberga38528f2011-01-22 06:46:43 +0200245 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200246 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200247 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100248
249 if (rp)
250 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300252 err = sock_queue_rcv_skb(sk, skb);
253 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200254 kfree_skb(skb);
255
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100256 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200257}
258
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300259static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
260 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200261{
262 struct mgmt_rp_read_version rp;
263
264 BT_DBG("sock %p", sk);
265
266 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200267 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200268
Johan Hedbergaee9b212012-02-18 15:07:59 +0200269 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300270 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200271}
272
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
274 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200275{
276 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200277 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
278 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200279 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200280 size_t rp_size;
281 int i, err;
282
283 BT_DBG("sock %p", sk);
284
285 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
286
287 rp = kmalloc(rp_size, GFP_KERNEL);
288 if (!rp)
289 return -ENOMEM;
290
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200291 rp->num_commands = __constant_cpu_to_le16(num_commands);
292 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200293
294 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
295 put_unaligned_le16(mgmt_commands[i], opcode);
296
297 for (i = 0; i < num_events; i++, opcode++)
298 put_unaligned_le16(mgmt_events[i], opcode);
299
Johan Hedbergaee9b212012-02-18 15:07:59 +0200300 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300301 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200302 kfree(rp);
303
304 return err;
305}
306
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300307static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
308 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200309{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200310 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200311 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200312 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300314 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315
316 BT_DBG("sock %p", sk);
317
318 read_lock(&hci_dev_list_lock);
319
320 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300321 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700322 if (d->dev_type == HCI_BREDR)
323 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324 }
325
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 rp_len = sizeof(*rp) + (2 * count);
327 rp = kmalloc(rp_len, GFP_ATOMIC);
328 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100329 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100331 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200332
Johan Hedberg476e44c2012-10-19 20:10:46 +0300333 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200334 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200335 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200336 continue;
337
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700338 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
339 continue;
340
Marcel Holtmann1514b892013-10-06 08:25:01 -0700341 if (d->dev_type == HCI_BREDR) {
342 rp->index[count++] = cpu_to_le16(d->id);
343 BT_DBG("Added hci%u", d->id);
344 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345 }
346
Johan Hedberg476e44c2012-10-19 20:10:46 +0300347 rp->num_controllers = cpu_to_le16(count);
348 rp_len = sizeof(*rp) + (2 * count);
349
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 read_unlock(&hci_dev_list_lock);
351
Johan Hedbergaee9b212012-02-18 15:07:59 +0200352 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300353 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
Johan Hedberga38528f2011-01-22 06:46:43 +0200355 kfree(rp);
356
357 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358}
359
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200360static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200361{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200366
Andre Guedesed3fa312012-07-24 15:03:46 -0300367 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300368 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500369 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
370 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300371 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 settings |= MGMT_SETTING_BREDR;
373 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700374
375 if (lmp_ssp_capable(hdev)) {
376 settings |= MGMT_SETTING_SSP;
377 settings |= MGMT_SETTING_HS;
378 }
Marcel Holtmann848566b2013-10-01 22:59:22 -0700379 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300381 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200382 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300383 settings |= MGMT_SETTING_ADVERTISING;
384 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200385
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200386 return settings;
387}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200388
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389static u32 get_current_settings(struct hci_dev *hdev)
390{
391 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200392
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200393 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100394 settings |= MGMT_SETTING_POWERED;
395
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200396 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200397 settings |= MGMT_SETTING_CONNECTABLE;
398
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500399 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
400 settings |= MGMT_SETTING_FAST_CONNECTABLE;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_DISCOVERABLE;
404
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200405 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_PAIRABLE;
407
Johan Hedberg56f87902013-10-02 13:43:13 +0300408 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_BREDR;
410
Johan Hedberg06199cf2012-02-22 16:37:11 +0200411 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200413
Johan Hedberg47990ea2012-02-22 11:58:37 +0200414 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200416
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200417 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200419
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200420 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
421 settings |= MGMT_SETTING_HS;
422
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200423 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300424 settings |= MGMT_SETTING_ADVERTISING;
425
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200426 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200427}
428
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300429#define PNP_INFO_SVCLASS_ID 0x1200
430
Johan Hedberg213202e2013-01-27 00:31:33 +0200431static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
432{
433 u8 *ptr = data, *uuids_start = NULL;
434 struct bt_uuid *uuid;
435
436 if (len < 4)
437 return ptr;
438
439 list_for_each_entry(uuid, &hdev->uuids, list) {
440 u16 uuid16;
441
442 if (uuid->size != 16)
443 continue;
444
445 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
446 if (uuid16 < 0x1100)
447 continue;
448
449 if (uuid16 == PNP_INFO_SVCLASS_ID)
450 continue;
451
452 if (!uuids_start) {
453 uuids_start = ptr;
454 uuids_start[0] = 1;
455 uuids_start[1] = EIR_UUID16_ALL;
456 ptr += 2;
457 }
458
459 /* Stop if not enough space to put next UUID */
460 if ((ptr - data) + sizeof(u16) > len) {
461 uuids_start[1] = EIR_UUID16_SOME;
462 break;
463 }
464
465 *ptr++ = (uuid16 & 0x00ff);
466 *ptr++ = (uuid16 & 0xff00) >> 8;
467 uuids_start[0] += sizeof(uuid16);
468 }
469
470 return ptr;
471}
472
Johan Hedbergcdf19632013-01-27 00:31:34 +0200473static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
474{
475 u8 *ptr = data, *uuids_start = NULL;
476 struct bt_uuid *uuid;
477
478 if (len < 6)
479 return ptr;
480
481 list_for_each_entry(uuid, &hdev->uuids, list) {
482 if (uuid->size != 32)
483 continue;
484
485 if (!uuids_start) {
486 uuids_start = ptr;
487 uuids_start[0] = 1;
488 uuids_start[1] = EIR_UUID32_ALL;
489 ptr += 2;
490 }
491
492 /* Stop if not enough space to put next UUID */
493 if ((ptr - data) + sizeof(u32) > len) {
494 uuids_start[1] = EIR_UUID32_SOME;
495 break;
496 }
497
498 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
499 ptr += sizeof(u32);
500 uuids_start[0] += sizeof(u32);
501 }
502
503 return ptr;
504}
505
Johan Hedbergc00d5752013-01-27 00:31:35 +0200506static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
507{
508 u8 *ptr = data, *uuids_start = NULL;
509 struct bt_uuid *uuid;
510
511 if (len < 18)
512 return ptr;
513
514 list_for_each_entry(uuid, &hdev->uuids, list) {
515 if (uuid->size != 128)
516 continue;
517
518 if (!uuids_start) {
519 uuids_start = ptr;
520 uuids_start[0] = 1;
521 uuids_start[1] = EIR_UUID128_ALL;
522 ptr += 2;
523 }
524
525 /* Stop if not enough space to put next UUID */
526 if ((ptr - data) + 16 > len) {
527 uuids_start[1] = EIR_UUID128_SOME;
528 break;
529 }
530
531 memcpy(ptr, uuid->uuid, 16);
532 ptr += 16;
533 uuids_start[0] += 16;
534 }
535
536 return ptr;
537}
538
Marcel Holtmann441ad2d2013-10-15 06:33:52 -0700539static u8 create_ad(struct hci_dev *hdev, u8 *ptr)
540{
541 u8 ad_len = 0, flags = 0;
542 size_t name_len;
543
544 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
545 flags |= LE_AD_GENERAL;
546
547 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
548 if (lmp_le_br_capable(hdev))
549 flags |= LE_AD_SIM_LE_BREDR_CTRL;
550 if (lmp_host_le_br_capable(hdev))
551 flags |= LE_AD_SIM_LE_BREDR_HOST;
552 } else {
553 flags |= LE_AD_NO_BREDR;
554 }
555
556 if (flags) {
557 BT_DBG("adv flags 0x%02x", flags);
558
559 ptr[0] = 2;
560 ptr[1] = EIR_FLAGS;
561 ptr[2] = flags;
562
563 ad_len += 3;
564 ptr += 3;
565 }
566
567 if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
568 ptr[0] = 2;
569 ptr[1] = EIR_TX_POWER;
570 ptr[2] = (u8) hdev->adv_tx_power;
571
572 ad_len += 3;
573 ptr += 3;
574 }
575
576 name_len = strlen(hdev->dev_name);
577 if (name_len > 0) {
578 size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
579
580 if (name_len > max_len) {
581 name_len = max_len;
582 ptr[1] = EIR_NAME_SHORT;
583 } else
584 ptr[1] = EIR_NAME_COMPLETE;
585
586 ptr[0] = name_len + 1;
587
588 memcpy(ptr + 2, hdev->dev_name, name_len);
589
590 ad_len += (name_len + 2);
591 ptr += (name_len + 2);
592 }
593
594 return ad_len;
595}
596
597static void update_ad(struct hci_request *req)
598{
599 struct hci_dev *hdev = req->hdev;
600 struct hci_cp_le_set_adv_data cp;
601 u8 len;
602
603 if (!lmp_le_capable(hdev))
604 return;
605
606 memset(&cp, 0, sizeof(cp));
607
608 len = create_ad(hdev, cp.data);
609
610 if (hdev->adv_data_len == len &&
611 memcmp(cp.data, hdev->adv_data, len) == 0)
612 return;
613
614 memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
615 hdev->adv_data_len = len;
616
617 cp.length = len;
618
619 hci_req_add(req, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
620}
621
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300622static void create_eir(struct hci_dev *hdev, u8 *data)
623{
624 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300625 size_t name_len;
626
627 name_len = strlen(hdev->dev_name);
628
629 if (name_len > 0) {
630 /* EIR Data type */
631 if (name_len > 48) {
632 name_len = 48;
633 ptr[1] = EIR_NAME_SHORT;
634 } else
635 ptr[1] = EIR_NAME_COMPLETE;
636
637 /* EIR Data length */
638 ptr[0] = name_len + 1;
639
640 memcpy(ptr + 2, hdev->dev_name, name_len);
641
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300642 ptr += (name_len + 2);
643 }
644
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100645 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700646 ptr[0] = 2;
647 ptr[1] = EIR_TX_POWER;
648 ptr[2] = (u8) hdev->inq_tx_power;
649
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700650 ptr += 3;
651 }
652
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700653 if (hdev->devid_source > 0) {
654 ptr[0] = 9;
655 ptr[1] = EIR_DEVICE_ID;
656
657 put_unaligned_le16(hdev->devid_source, ptr + 2);
658 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
659 put_unaligned_le16(hdev->devid_product, ptr + 6);
660 put_unaligned_le16(hdev->devid_version, ptr + 8);
661
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700662 ptr += 10;
663 }
664
Johan Hedberg213202e2013-01-27 00:31:33 +0200665 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200666 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200667 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300668}
669
Johan Hedberg890ea892013-03-15 17:06:52 -0500670static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300671{
Johan Hedberg890ea892013-03-15 17:06:52 -0500672 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300673 struct hci_cp_write_eir cp;
674
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200675 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500676 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200677
Johan Hedberg976eb202012-10-24 21:12:01 +0300678 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500679 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300680
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200681 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500682 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300683
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200684 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500685 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300686
687 memset(&cp, 0, sizeof(cp));
688
689 create_eir(hdev, cp.data);
690
691 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500692 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300693
694 memcpy(hdev->eir, cp.data, sizeof(cp.data));
695
Johan Hedberg890ea892013-03-15 17:06:52 -0500696 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300697}
698
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200699static u8 get_service_classes(struct hci_dev *hdev)
700{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300701 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200702 u8 val = 0;
703
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300704 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200705 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200706
707 return val;
708}
709
Johan Hedberg890ea892013-03-15 17:06:52 -0500710static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200711{
Johan Hedberg890ea892013-03-15 17:06:52 -0500712 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200713 u8 cod[3];
714
715 BT_DBG("%s", hdev->name);
716
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200717 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500718 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200719
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200720 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500721 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200722
723 cod[0] = hdev->minor_class;
724 cod[1] = hdev->major_class;
725 cod[2] = get_service_classes(hdev);
726
Marcel Holtmann6acd7db2013-10-15 06:33:53 -0700727 if (test_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags))
728 cod[1] |= 0x20;
729
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200730 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500731 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200732
Johan Hedberg890ea892013-03-15 17:06:52 -0500733 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200734}
735
Johan Hedberg7d785252011-12-15 00:47:39 +0200736static void service_cache_off(struct work_struct *work)
737{
738 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300739 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500740 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200741
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200742 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200743 return;
744
Johan Hedberg890ea892013-03-15 17:06:52 -0500745 hci_req_init(&req, hdev);
746
Johan Hedberg7d785252011-12-15 00:47:39 +0200747 hci_dev_lock(hdev);
748
Johan Hedberg890ea892013-03-15 17:06:52 -0500749 update_eir(&req);
750 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200751
752 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500753
754 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200755}
756
Johan Hedberg6a919082012-02-28 06:17:26 +0200757static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200758{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200759 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200760 return;
761
Johan Hedberg4f87da82012-03-02 19:55:56 +0200762 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200763
Johan Hedberg4f87da82012-03-02 19:55:56 +0200764 /* Non-mgmt controlled devices get this bit set
765 * implicitly so that pairing works for them, however
766 * for mgmt we require user-space to explicitly enable
767 * it
768 */
769 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200770}
771
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200772static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300773 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200774{
775 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200776
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200777 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200778
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300779 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200780
Johan Hedberg03811012010-12-08 00:21:06 +0200781 memset(&rp, 0, sizeof(rp));
782
Johan Hedberg03811012010-12-08 00:21:06 +0200783 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200784
785 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200786 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200787
788 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
789 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
790
791 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200792
793 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200794 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200795
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300796 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200797
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200798 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300799 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200800}
801
802static void mgmt_pending_free(struct pending_cmd *cmd)
803{
804 sock_put(cmd->sk);
805 kfree(cmd->param);
806 kfree(cmd);
807}
808
809static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300810 struct hci_dev *hdev, void *data,
811 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200812{
813 struct pending_cmd *cmd;
814
Andre Guedes12b94562012-06-07 19:05:45 -0300815 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200816 if (!cmd)
817 return NULL;
818
819 cmd->opcode = opcode;
820 cmd->index = hdev->id;
821
Andre Guedes12b94562012-06-07 19:05:45 -0300822 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200823 if (!cmd->param) {
824 kfree(cmd);
825 return NULL;
826 }
827
828 if (data)
829 memcpy(cmd->param, data, len);
830
831 cmd->sk = sk;
832 sock_hold(sk);
833
834 list_add(&cmd->list, &hdev->mgmt_pending);
835
836 return cmd;
837}
838
839static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300840 void (*cb)(struct pending_cmd *cmd,
841 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300842 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200843{
Andre Guedesa3d09352013-02-01 11:21:30 -0300844 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200845
Andre Guedesa3d09352013-02-01 11:21:30 -0300846 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200847 if (opcode > 0 && cmd->opcode != opcode)
848 continue;
849
850 cb(cmd, data);
851 }
852}
853
854static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
855{
856 struct pending_cmd *cmd;
857
858 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
859 if (cmd->opcode == opcode)
860 return cmd;
861 }
862
863 return NULL;
864}
865
866static void mgmt_pending_remove(struct pending_cmd *cmd)
867{
868 list_del(&cmd->list);
869 mgmt_pending_free(cmd);
870}
871
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200872static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200873{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200874 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200875
Johan Hedbergaee9b212012-02-18 15:07:59 +0200876 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300877 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200878}
879
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200880static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300881 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200882{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300883 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200884 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200885 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200886
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200887 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200888
Johan Hedberga7e80f22013-01-09 16:05:19 +0200889 if (cp->val != 0x00 && cp->val != 0x01)
890 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
891 MGMT_STATUS_INVALID_PARAMS);
892
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300893 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200894
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300895 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
896 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
897 MGMT_STATUS_BUSY);
898 goto failed;
899 }
900
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100901 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
902 cancel_delayed_work(&hdev->power_off);
903
904 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200905 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
906 data, len);
907 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100908 goto failed;
909 }
910 }
911
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200912 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200913 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200914 goto failed;
915 }
916
Johan Hedberg03811012010-12-08 00:21:06 +0200917 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
918 if (!cmd) {
919 err = -ENOMEM;
920 goto failed;
921 }
922
923 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200924 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200925 else
Johan Hedberg19202572013-01-14 22:33:51 +0200926 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200927
928 err = 0;
929
930failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300931 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200932 return err;
933}
934
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300935static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
936 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200937{
938 struct sk_buff *skb;
939 struct mgmt_hdr *hdr;
940
Andre Guedes790eff42012-06-07 19:05:46 -0300941 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200942 if (!skb)
943 return -ENOMEM;
944
945 hdr = (void *) skb_put(skb, sizeof(*hdr));
946 hdr->opcode = cpu_to_le16(event);
947 if (hdev)
948 hdr->index = cpu_to_le16(hdev->id);
949 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530950 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200951 hdr->len = cpu_to_le16(data_len);
952
953 if (data)
954 memcpy(skb_put(skb, data_len), data, data_len);
955
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100956 /* Time stamp */
957 __net_timestamp(skb);
958
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200959 hci_send_to_control(skb, skip_sk);
960 kfree_skb(skb);
961
962 return 0;
963}
964
965static int new_settings(struct hci_dev *hdev, struct sock *skip)
966{
967 __le32 ev;
968
969 ev = cpu_to_le32(get_current_settings(hdev));
970
971 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
972}
973
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300974struct cmd_lookup {
975 struct sock *sk;
976 struct hci_dev *hdev;
977 u8 mgmt_status;
978};
979
980static void settings_rsp(struct pending_cmd *cmd, void *data)
981{
982 struct cmd_lookup *match = data;
983
984 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
985
986 list_del(&cmd->list);
987
988 if (match->sk == NULL) {
989 match->sk = cmd->sk;
990 sock_hold(match->sk);
991 }
992
993 mgmt_pending_free(cmd);
994}
995
996static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
997{
998 u8 *status = data;
999
1000 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1001 mgmt_pending_remove(cmd);
1002}
1003
Johan Hedberge6fe7982013-10-02 15:45:22 +03001004static u8 mgmt_bredr_support(struct hci_dev *hdev)
1005{
1006 if (!lmp_bredr_capable(hdev))
1007 return MGMT_STATUS_NOT_SUPPORTED;
1008 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1009 return MGMT_STATUS_REJECTED;
1010 else
1011 return MGMT_STATUS_SUCCESS;
1012}
1013
1014static u8 mgmt_le_support(struct hci_dev *hdev)
1015{
1016 if (!lmp_le_capable(hdev))
1017 return MGMT_STATUS_NOT_SUPPORTED;
1018 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1019 return MGMT_STATUS_REJECTED;
1020 else
1021 return MGMT_STATUS_SUCCESS;
1022}
1023
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001024static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1025{
1026 struct pending_cmd *cmd;
1027 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001028 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001029 bool changed;
1030
1031 BT_DBG("status 0x%02x", status);
1032
1033 hci_dev_lock(hdev);
1034
1035 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1036 if (!cmd)
1037 goto unlock;
1038
1039 if (status) {
1040 u8 mgmt_err = mgmt_status(status);
1041 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001042 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001043 goto remove_cmd;
1044 }
1045
1046 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001047 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001048 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1049 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001050
1051 if (hdev->discov_timeout > 0) {
1052 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1053 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1054 to);
1055 }
1056 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001057 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1058 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001059 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001060
1061 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1062
1063 if (changed)
1064 new_settings(hdev, cmd->sk);
1065
Marcel Holtmann970ba522013-10-15 06:33:57 -07001066 /* When the discoverable mode gets changed, make sure
1067 * that class of device has the limited discoverable
1068 * bit correctly set.
1069 */
1070 hci_req_init(&req, hdev);
1071 update_class(&req);
1072 hci_req_run(&req, NULL);
1073
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001074remove_cmd:
1075 mgmt_pending_remove(cmd);
1076
1077unlock:
1078 hci_dev_unlock(hdev);
1079}
1080
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001081static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001082 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001083{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001084 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001085 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001086 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001087 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001088 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001089 int err;
1090
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001091 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001092
Johan Hedberge6fe7982013-10-02 15:45:22 +03001093 status = mgmt_bredr_support(hdev);
1094 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001095 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001096 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001097
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001098 if (cp->val != 0x00 && cp->val != 0x01 && cp->val != 0x02)
Johan Hedberga7e80f22013-01-09 16:05:19 +02001099 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1100 MGMT_STATUS_INVALID_PARAMS);
1101
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001102 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001103
1104 /* Disabling discoverable requires that no timeout is set,
1105 * and enabling limited discoverable requires a timeout.
1106 */
1107 if ((cp->val == 0x00 && timeout > 0) ||
1108 (cp->val == 0x02 && timeout == 0))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001109 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001110 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001111
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001112 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001113
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001114 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001115 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001116 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001117 goto failed;
1118 }
1119
1120 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001121 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001122 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001123 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001124 goto failed;
1125 }
1126
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001127 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001128 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001129 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001130 goto failed;
1131 }
1132
1133 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001134 bool changed = false;
1135
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001136 /* Setting limited discoverable when powered off is
1137 * not a valid operation since it requires a timeout
1138 * and so no need to check HCI_LIMITED_DISCOVERABLE.
1139 */
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001140 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1141 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1142 changed = true;
1143 }
1144
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001145 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001146 if (err < 0)
1147 goto failed;
1148
1149 if (changed)
1150 err = new_settings(hdev, sk);
1151
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001152 goto failed;
1153 }
1154
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001155 /* If the current mode is the same, then just update the timeout
1156 * value with the new value. And if only the timeout gets updated,
1157 * then no need for any HCI transactions.
1158 */
1159 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags) &&
1160 (cp->val == 0x02) == test_bit(HCI_LIMITED_DISCOVERABLE,
1161 &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001162 cancel_delayed_work(&hdev->discov_off);
1163 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001164
Marcel Holtmann36261542013-10-15 08:28:51 -07001165 if (cp->val && hdev->discov_timeout > 0) {
1166 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001167 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001168 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001169 }
1170
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001171 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001172 goto failed;
1173 }
1174
1175 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1176 if (!cmd) {
1177 err = -ENOMEM;
1178 goto failed;
1179 }
1180
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001181 /* Cancel any potential discoverable timeout that might be
1182 * still active and store new timeout value. The arming of
1183 * the timeout happens in the complete handler.
1184 */
1185 cancel_delayed_work(&hdev->discov_off);
1186 hdev->discov_timeout = timeout;
1187
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001188 hci_req_init(&req, hdev);
1189
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001190 scan = SCAN_PAGE;
1191
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001192 if (cp->val) {
1193 struct hci_cp_write_current_iac_lap hci_cp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001194
Marcel Holtmann310a3d42013-10-15 09:13:39 -07001195 if (cp->val == 0x02) {
1196 /* Limited discoverable mode */
1197 set_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1198
1199 hci_cp.num_iac = 2;
1200 hci_cp.iac_lap[0] = 0x00; /* LIAC */
1201 hci_cp.iac_lap[1] = 0x8b;
1202 hci_cp.iac_lap[2] = 0x9e;
1203 hci_cp.iac_lap[3] = 0x33; /* GIAC */
1204 hci_cp.iac_lap[4] = 0x8b;
1205 hci_cp.iac_lap[5] = 0x9e;
1206 } else {
1207 /* General discoverable mode */
1208 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1209
1210 hci_cp.num_iac = 1;
1211 hci_cp.iac_lap[0] = 0x33; /* GIAC */
1212 hci_cp.iac_lap[1] = 0x8b;
1213 hci_cp.iac_lap[2] = 0x9e;
1214 }
1215
1216 hci_req_add(&req, HCI_OP_WRITE_CURRENT_IAC_LAP,
1217 (hci_cp.num_iac * 3) + 1, &hci_cp);
1218
1219 scan |= SCAN_INQUIRY;
1220 } else {
1221 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
1222 }
1223
1224 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001225
1226 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001227 if (err < 0)
1228 mgmt_pending_remove(cmd);
1229
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001230failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001231 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001232 return err;
1233}
1234
Johan Hedberg406d7802013-03-15 17:07:09 -05001235static void write_fast_connectable(struct hci_request *req, bool enable)
1236{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001237 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001238 struct hci_cp_write_page_scan_activity acp;
1239 u8 type;
1240
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001241 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1242 return;
1243
Johan Hedberg406d7802013-03-15 17:07:09 -05001244 if (enable) {
1245 type = PAGE_SCAN_TYPE_INTERLACED;
1246
1247 /* 160 msec page scan interval */
1248 acp.interval = __constant_cpu_to_le16(0x0100);
1249 } else {
1250 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1251
1252 /* default 1.28 sec page scan */
1253 acp.interval = __constant_cpu_to_le16(0x0800);
1254 }
1255
1256 acp.window = __constant_cpu_to_le16(0x0012);
1257
Johan Hedbergbd98b992013-03-15 17:07:13 -05001258 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1259 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1260 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1261 sizeof(acp), &acp);
1262
1263 if (hdev->page_scan_type != type)
1264 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001265}
1266
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001267static u8 get_adv_type(struct hci_dev *hdev)
1268{
1269 struct pending_cmd *cmd;
1270 bool connectable;
1271
1272 /* If there's a pending mgmt command the flag will not yet have
1273 * it's final value, so check for this first.
1274 */
1275 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1276 if (cmd) {
1277 struct mgmt_mode *cp = cmd->param;
1278 connectable = !!cp->val;
1279 } else {
1280 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1281 }
1282
1283 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1284}
1285
Johan Hedberg95c66e72013-10-14 16:20:06 +03001286static void enable_advertising(struct hci_request *req)
1287{
1288 struct hci_dev *hdev = req->hdev;
1289 struct hci_cp_le_set_adv_param cp;
1290 u8 enable = 0x01;
1291
1292 memset(&cp, 0, sizeof(cp));
1293 cp.min_interval = __constant_cpu_to_le16(0x0800);
1294 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001295 cp.type = get_adv_type(hdev);
Johan Hedberg95c66e72013-10-14 16:20:06 +03001296 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1297 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1298 else
1299 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1300 cp.channel_map = 0x07;
1301
1302 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1303
1304 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1305}
1306
1307static void disable_advertising(struct hci_request *req)
1308{
1309 u8 enable = 0x00;
1310
1311 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1312}
1313
Johan Hedberg2b76f452013-03-15 17:07:04 -05001314static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1315{
1316 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001317 struct mgmt_mode *cp;
1318 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001319
1320 BT_DBG("status 0x%02x", status);
1321
1322 hci_dev_lock(hdev);
1323
1324 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1325 if (!cmd)
1326 goto unlock;
1327
Johan Hedberg37438c12013-10-14 16:20:05 +03001328 if (status) {
1329 u8 mgmt_err = mgmt_status(status);
1330 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1331 goto remove_cmd;
1332 }
1333
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001334 cp = cmd->param;
1335 if (cp->val)
1336 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1337 else
1338 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1339
Johan Hedberg2b76f452013-03-15 17:07:04 -05001340 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1341
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001342 if (changed)
1343 new_settings(hdev, cmd->sk);
1344
Johan Hedberg37438c12013-10-14 16:20:05 +03001345remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001346 mgmt_pending_remove(cmd);
1347
1348unlock:
1349 hci_dev_unlock(hdev);
1350}
1351
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001352static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001353 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001354{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001355 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001356 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001357 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001358 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001359 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001360
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001361 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001362
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001363 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1364 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001365 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001366 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001367
Johan Hedberga7e80f22013-01-09 16:05:19 +02001368 if (cp->val != 0x00 && cp->val != 0x01)
1369 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1370 MGMT_STATUS_INVALID_PARAMS);
1371
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001372 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001373
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001374 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001375 bool changed = false;
1376
1377 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1378 changed = true;
1379
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001380 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001381 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001382 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001383 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1384 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1385 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001386
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001387 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001388 if (err < 0)
1389 goto failed;
1390
1391 if (changed)
1392 err = new_settings(hdev, sk);
1393
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001394 goto failed;
1395 }
1396
1397 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001398 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001399 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001400 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001401 goto failed;
1402 }
1403
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001404 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1405 if (!cmd) {
1406 err = -ENOMEM;
1407 goto failed;
1408 }
1409
Johan Hedberg2b76f452013-03-15 17:07:04 -05001410 hci_req_init(&req, hdev);
1411
Johan Hedberg9b742462013-10-14 16:20:03 +03001412 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1413 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001414 if (cp->val) {
1415 scan = SCAN_PAGE;
1416 } else {
1417 scan = 0;
1418
1419 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001420 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001421 cancel_delayed_work(&hdev->discov_off);
1422 }
1423
1424 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1425 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001426
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001427 /* If we're going from non-connectable to connectable or
1428 * vice-versa when fast connectable is enabled ensure that fast
1429 * connectable gets disabled. write_fast_connectable won't do
1430 * anything if the page scan parameters are already what they
1431 * should be.
1432 */
1433 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001434 write_fast_connectable(&req, false);
1435
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001436 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1437 hci_conn_num(hdev, LE_LINK) == 0) {
1438 disable_advertising(&req);
1439 enable_advertising(&req);
1440 }
1441
Johan Hedberg2b76f452013-03-15 17:07:04 -05001442 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001443 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001444 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001445 if (err == -ENODATA)
1446 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1447 hdev);
1448 goto failed;
1449 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001450
1451failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001452 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001453 return err;
1454}
1455
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001456static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001457 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001458{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001459 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001460 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001461 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001462
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001463 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001464
Johan Hedberga7e80f22013-01-09 16:05:19 +02001465 if (cp->val != 0x00 && cp->val != 0x01)
1466 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1467 MGMT_STATUS_INVALID_PARAMS);
1468
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001469 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001470
1471 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001472 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001473 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001474 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001475
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001476 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001477 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001478 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001479
Marcel Holtmann55594352013-10-06 16:11:57 -07001480 if (changed)
1481 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001482
Marcel Holtmann55594352013-10-06 16:11:57 -07001483unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001484 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001485 return err;
1486}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001487
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001488static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1489 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001490{
1491 struct mgmt_mode *cp = data;
1492 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001493 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001494 int err;
1495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001496 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001497
Johan Hedberge6fe7982013-10-02 15:45:22 +03001498 status = mgmt_bredr_support(hdev);
1499 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001500 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001501 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001502
Johan Hedberga7e80f22013-01-09 16:05:19 +02001503 if (cp->val != 0x00 && cp->val != 0x01)
1504 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1505 MGMT_STATUS_INVALID_PARAMS);
1506
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001507 hci_dev_lock(hdev);
1508
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001509 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001510 bool changed = false;
1511
1512 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001513 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001514 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1515 changed = true;
1516 }
1517
1518 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1519 if (err < 0)
1520 goto failed;
1521
1522 if (changed)
1523 err = new_settings(hdev, sk);
1524
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001525 goto failed;
1526 }
1527
1528 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001529 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001530 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001531 goto failed;
1532 }
1533
1534 val = !!cp->val;
1535
1536 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1537 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1538 goto failed;
1539 }
1540
1541 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1542 if (!cmd) {
1543 err = -ENOMEM;
1544 goto failed;
1545 }
1546
1547 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1548 if (err < 0) {
1549 mgmt_pending_remove(cmd);
1550 goto failed;
1551 }
1552
1553failed:
1554 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001555 return err;
1556}
1557
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001558static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001559{
1560 struct mgmt_mode *cp = data;
1561 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001562 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001563 int err;
1564
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001565 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001566
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001567 status = mgmt_bredr_support(hdev);
1568 if (status)
1569 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1570
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001571 if (!lmp_ssp_capable(hdev))
1572 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1573 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001574
Johan Hedberga7e80f22013-01-09 16:05:19 +02001575 if (cp->val != 0x00 && cp->val != 0x01)
1576 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1577 MGMT_STATUS_INVALID_PARAMS);
1578
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001579 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001580
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001581 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001582 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001583
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001584 if (cp->val) {
1585 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1586 &hdev->dev_flags);
1587 } else {
1588 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1589 &hdev->dev_flags);
1590 if (!changed)
1591 changed = test_and_clear_bit(HCI_HS_ENABLED,
1592 &hdev->dev_flags);
1593 else
1594 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001595 }
1596
1597 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1598 if (err < 0)
1599 goto failed;
1600
1601 if (changed)
1602 err = new_settings(hdev, sk);
1603
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001604 goto failed;
1605 }
1606
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001607 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1608 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001609 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1610 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001611 goto failed;
1612 }
1613
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001614 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001615 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1616 goto failed;
1617 }
1618
1619 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1620 if (!cmd) {
1621 err = -ENOMEM;
1622 goto failed;
1623 }
1624
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001625 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001626 if (err < 0) {
1627 mgmt_pending_remove(cmd);
1628 goto failed;
1629 }
1630
1631failed:
1632 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001633 return err;
1634}
1635
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001636static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001637{
1638 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001639 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001640 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001641 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001642
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001643 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001644
Johan Hedberge6fe7982013-10-02 15:45:22 +03001645 status = mgmt_bredr_support(hdev);
1646 if (status)
1647 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001648
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001649 if (!lmp_ssp_capable(hdev))
1650 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1651 MGMT_STATUS_NOT_SUPPORTED);
1652
1653 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1654 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1655 MGMT_STATUS_REJECTED);
1656
Johan Hedberga7e80f22013-01-09 16:05:19 +02001657 if (cp->val != 0x00 && cp->val != 0x01)
1658 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1659 MGMT_STATUS_INVALID_PARAMS);
1660
Marcel Holtmannee392692013-10-01 22:59:23 -07001661 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001662
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001663 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001664 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001665 } else {
1666 if (hdev_is_powered(hdev)) {
1667 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1668 MGMT_STATUS_REJECTED);
1669 goto unlock;
1670 }
1671
Marcel Holtmannee392692013-10-01 22:59:23 -07001672 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001673 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001674
1675 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1676 if (err < 0)
1677 goto unlock;
1678
1679 if (changed)
1680 err = new_settings(hdev, sk);
1681
1682unlock:
1683 hci_dev_unlock(hdev);
1684 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001685}
1686
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001687static void le_enable_complete(struct hci_dev *hdev, u8 status)
1688{
1689 struct cmd_lookup match = { NULL, hdev };
1690
1691 if (status) {
1692 u8 mgmt_err = mgmt_status(status);
1693
1694 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1695 &mgmt_err);
1696 return;
1697 }
1698
1699 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1700
1701 new_settings(hdev, match.sk);
1702
1703 if (match.sk)
1704 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001705
1706 /* Make sure the controller has a good default for
1707 * advertising data. Restrict the update to when LE
1708 * has actually been enabled. During power on, the
1709 * update in powered_update_hci will take care of it.
1710 */
1711 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1712 struct hci_request req;
1713
1714 hci_dev_lock(hdev);
1715
1716 hci_req_init(&req, hdev);
1717 update_ad(&req);
1718 hci_req_run(&req, NULL);
1719
1720 hci_dev_unlock(hdev);
1721 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001722}
1723
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001724static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001725{
1726 struct mgmt_mode *cp = data;
1727 struct hci_cp_write_le_host_supported hci_cp;
1728 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001729 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001730 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001731 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001732
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001733 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001734
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001735 if (!lmp_le_capable(hdev))
1736 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1737 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001738
Johan Hedberga7e80f22013-01-09 16:05:19 +02001739 if (cp->val != 0x00 && cp->val != 0x01)
1740 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1741 MGMT_STATUS_INVALID_PARAMS);
1742
Johan Hedbergc73eee92013-04-19 18:35:21 +03001743 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001744 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001745 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1746 MGMT_STATUS_REJECTED);
1747
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001748 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001749
1750 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001751 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001752
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001753 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001754 bool changed = false;
1755
1756 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1757 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1758 changed = true;
1759 }
1760
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001761 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1762 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001763 changed = true;
1764 }
1765
Johan Hedberg06199cf2012-02-22 16:37:11 +02001766 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1767 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001768 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001769
1770 if (changed)
1771 err = new_settings(hdev, sk);
1772
Johan Hedberg1de028c2012-02-29 19:55:35 -08001773 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001774 }
1775
Johan Hedberg4375f102013-09-25 13:26:10 +03001776 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1777 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001778 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001779 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001780 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001781 }
1782
1783 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1784 if (!cmd) {
1785 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001786 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001787 }
1788
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001789 hci_req_init(&req, hdev);
1790
Johan Hedberg06199cf2012-02-22 16:37:11 +02001791 memset(&hci_cp, 0, sizeof(hci_cp));
1792
1793 if (val) {
1794 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001795 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001796 } else {
1797 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1798 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001799 }
1800
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001801 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1802 &hci_cp);
1803
1804 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301805 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001806 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001807
Johan Hedberg1de028c2012-02-29 19:55:35 -08001808unlock:
1809 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001810 return err;
1811}
1812
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001813/* This is a helper function to test for pending mgmt commands that can
1814 * cause CoD or EIR HCI commands. We can only allow one such pending
1815 * mgmt command at a time since otherwise we cannot easily track what
1816 * the current values are, will be, and based on that calculate if a new
1817 * HCI command needs to be sent and if yes with what value.
1818 */
1819static bool pending_eir_or_class(struct hci_dev *hdev)
1820{
1821 struct pending_cmd *cmd;
1822
1823 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1824 switch (cmd->opcode) {
1825 case MGMT_OP_ADD_UUID:
1826 case MGMT_OP_REMOVE_UUID:
1827 case MGMT_OP_SET_DEV_CLASS:
1828 case MGMT_OP_SET_POWERED:
1829 return true;
1830 }
1831 }
1832
1833 return false;
1834}
1835
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001836static const u8 bluetooth_base_uuid[] = {
1837 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1838 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1839};
1840
1841static u8 get_uuid_size(const u8 *uuid)
1842{
1843 u32 val;
1844
1845 if (memcmp(uuid, bluetooth_base_uuid, 12))
1846 return 128;
1847
1848 val = get_unaligned_le32(&uuid[12]);
1849 if (val > 0xffff)
1850 return 32;
1851
1852 return 16;
1853}
1854
Johan Hedberg92da6092013-03-15 17:06:55 -05001855static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1856{
1857 struct pending_cmd *cmd;
1858
1859 hci_dev_lock(hdev);
1860
1861 cmd = mgmt_pending_find(mgmt_op, hdev);
1862 if (!cmd)
1863 goto unlock;
1864
1865 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1866 hdev->dev_class, 3);
1867
1868 mgmt_pending_remove(cmd);
1869
1870unlock:
1871 hci_dev_unlock(hdev);
1872}
1873
1874static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1875{
1876 BT_DBG("status 0x%02x", status);
1877
1878 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1879}
1880
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001881static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001882{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001883 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001884 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001885 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001886 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001887 int err;
1888
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001889 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001890
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001891 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001892
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001893 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001894 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001895 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001896 goto failed;
1897 }
1898
Andre Guedes92c4c202012-06-07 19:05:44 -03001899 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001900 if (!uuid) {
1901 err = -ENOMEM;
1902 goto failed;
1903 }
1904
1905 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001906 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001907 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001908
Johan Hedbergde66aa62013-01-27 00:31:27 +02001909 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001910
Johan Hedberg890ea892013-03-15 17:06:52 -05001911 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001912
Johan Hedberg890ea892013-03-15 17:06:52 -05001913 update_class(&req);
1914 update_eir(&req);
1915
Johan Hedberg92da6092013-03-15 17:06:55 -05001916 err = hci_req_run(&req, add_uuid_complete);
1917 if (err < 0) {
1918 if (err != -ENODATA)
1919 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001920
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001921 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001922 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001923 goto failed;
1924 }
1925
1926 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001927 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001928 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001929 goto failed;
1930 }
1931
1932 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001933
1934failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001935 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001936 return err;
1937}
1938
Johan Hedberg24b78d02012-02-23 23:24:30 +02001939static bool enable_service_cache(struct hci_dev *hdev)
1940{
1941 if (!hdev_is_powered(hdev))
1942 return false;
1943
1944 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001945 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1946 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001947 return true;
1948 }
1949
1950 return false;
1951}
1952
Johan Hedberg92da6092013-03-15 17:06:55 -05001953static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1954{
1955 BT_DBG("status 0x%02x", status);
1956
1957 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1958}
1959
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001960static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001961 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001962{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001963 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001964 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001965 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001966 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 -05001967 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001968 int err, found;
1969
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001970 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001971
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001972 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001973
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001974 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001975 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001976 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001977 goto unlock;
1978 }
1979
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001980 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1981 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001982
Johan Hedberg24b78d02012-02-23 23:24:30 +02001983 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001984 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001985 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001986 goto unlock;
1987 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001988
Johan Hedberg9246a862012-02-23 21:33:16 +02001989 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001990 }
1991
1992 found = 0;
1993
Johan Hedberg056341c2013-01-27 00:31:30 +02001994 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001995 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1996 continue;
1997
1998 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001999 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002000 found++;
2001 }
2002
2003 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002004 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002005 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002006 goto unlock;
2007 }
2008
Johan Hedberg9246a862012-02-23 21:33:16 +02002009update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05002010 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002011
Johan Hedberg890ea892013-03-15 17:06:52 -05002012 update_class(&req);
2013 update_eir(&req);
2014
Johan Hedberg92da6092013-03-15 17:06:55 -05002015 err = hci_req_run(&req, remove_uuid_complete);
2016 if (err < 0) {
2017 if (err != -ENODATA)
2018 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002019
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002020 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002021 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002022 goto unlock;
2023 }
2024
2025 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002026 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002027 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002028 goto unlock;
2029 }
2030
2031 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002032
2033unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002034 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002035 return err;
2036}
2037
Johan Hedberg92da6092013-03-15 17:06:55 -05002038static void set_class_complete(struct hci_dev *hdev, u8 status)
2039{
2040 BT_DBG("status 0x%02x", status);
2041
2042 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
2043}
2044
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002045static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002046 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002047{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002048 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002049 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002050 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002051 int err;
2052
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002053 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002054
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002055 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002056 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2057 MGMT_STATUS_NOT_SUPPORTED);
2058
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002059 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002060
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002061 if (pending_eir_or_class(hdev)) {
2062 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2063 MGMT_STATUS_BUSY);
2064 goto unlock;
2065 }
2066
2067 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2068 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2069 MGMT_STATUS_INVALID_PARAMS);
2070 goto unlock;
2071 }
2072
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002073 hdev->major_class = cp->major;
2074 hdev->minor_class = cp->minor;
2075
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002076 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002077 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002078 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002079 goto unlock;
2080 }
2081
Johan Hedberg890ea892013-03-15 17:06:52 -05002082 hci_req_init(&req, hdev);
2083
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002084 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002085 hci_dev_unlock(hdev);
2086 cancel_delayed_work_sync(&hdev->service_cache);
2087 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002088 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002089 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002090
Johan Hedberg890ea892013-03-15 17:06:52 -05002091 update_class(&req);
2092
Johan Hedberg92da6092013-03-15 17:06:55 -05002093 err = hci_req_run(&req, set_class_complete);
2094 if (err < 0) {
2095 if (err != -ENODATA)
2096 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002097
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002098 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002099 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002100 goto unlock;
2101 }
2102
2103 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002104 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002105 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002106 goto unlock;
2107 }
2108
2109 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002110
Johan Hedbergb5235a62012-02-21 14:32:24 +02002111unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002112 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002113 return err;
2114}
2115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002116static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002117 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002118{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002119 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002120 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002121 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002122
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002123 BT_DBG("request for %s", hdev->name);
2124
2125 if (!lmp_bredr_capable(hdev))
2126 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2127 MGMT_STATUS_NOT_SUPPORTED);
2128
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002129 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002130
Johan Hedberg86742e12011-11-07 23:13:38 +02002131 expected_len = sizeof(*cp) + key_count *
2132 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002133 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002134 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002135 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002136 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002137 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002138 }
2139
Johan Hedberg4ae14302013-01-20 14:27:13 +02002140 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2141 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2142 MGMT_STATUS_INVALID_PARAMS);
2143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002144 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002145 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002146
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002147 for (i = 0; i < key_count; i++) {
2148 struct mgmt_link_key_info *key = &cp->keys[i];
2149
2150 if (key->addr.type != BDADDR_BREDR)
2151 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2152 MGMT_STATUS_INVALID_PARAMS);
2153 }
2154
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002155 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002156
2157 hci_link_keys_clear(hdev);
2158
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002159 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002160 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002161 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002162 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002163
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002164 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002165 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002166
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002167 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002168 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002169 }
2170
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002171 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002172
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002173 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002174
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002175 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002176}
2177
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002178static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002179 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002180{
2181 struct mgmt_ev_device_unpaired ev;
2182
2183 bacpy(&ev.addr.bdaddr, bdaddr);
2184 ev.addr.type = addr_type;
2185
2186 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002187 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002188}
2189
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002190static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002191 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002192{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002193 struct mgmt_cp_unpair_device *cp = data;
2194 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002195 struct hci_cp_disconnect dc;
2196 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002197 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002198 int err;
2199
Johan Hedberga8a1d192011-11-10 15:54:38 +02002200 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002201 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2202 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002203
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002204 if (!bdaddr_type_is_valid(cp->addr.type))
2205 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2206 MGMT_STATUS_INVALID_PARAMS,
2207 &rp, sizeof(rp));
2208
Johan Hedberg118da702013-01-20 14:27:20 +02002209 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2210 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2211 MGMT_STATUS_INVALID_PARAMS,
2212 &rp, sizeof(rp));
2213
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002214 hci_dev_lock(hdev);
2215
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002216 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002217 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002218 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002219 goto unlock;
2220 }
2221
Andre Guedes591f47f2012-04-24 21:02:49 -03002222 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002223 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2224 else
2225 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002226
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002227 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002228 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002229 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002230 goto unlock;
2231 }
2232
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002233 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002234 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002235 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002236 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002237 else
2238 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002239 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002240 } else {
2241 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002242 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002243
Johan Hedberga8a1d192011-11-10 15:54:38 +02002244 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002245 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002246 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002247 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002248 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002249 }
2250
Johan Hedberg124f6e32012-02-09 13:50:12 +02002251 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002252 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002253 if (!cmd) {
2254 err = -ENOMEM;
2255 goto unlock;
2256 }
2257
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002258 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002259 dc.reason = 0x13; /* Remote User Terminated Connection */
2260 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2261 if (err < 0)
2262 mgmt_pending_remove(cmd);
2263
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002264unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002265 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002266 return err;
2267}
2268
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002269static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002270 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002271{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002272 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002273 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002274 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002275 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002276 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002277 int err;
2278
2279 BT_DBG("");
2280
Johan Hedberg06a63b12013-01-20 14:27:21 +02002281 memset(&rp, 0, sizeof(rp));
2282 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2283 rp.addr.type = cp->addr.type;
2284
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002285 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002286 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2287 MGMT_STATUS_INVALID_PARAMS,
2288 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002289
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002290 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002291
2292 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002293 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2294 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002295 goto failed;
2296 }
2297
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002298 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002299 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2300 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002301 goto failed;
2302 }
2303
Andre Guedes591f47f2012-04-24 21:02:49 -03002304 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002305 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2306 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002307 else
2308 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002309
Vishal Agarwalf9607272012-06-13 05:32:43 +05302310 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002311 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2312 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002313 goto failed;
2314 }
2315
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002316 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002317 if (!cmd) {
2318 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002319 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002320 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002321
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002322 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002323 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002324
2325 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2326 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002327 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002328
2329failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002330 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002331 return err;
2332}
2333
Andre Guedes57c14772012-04-24 21:02:50 -03002334static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002335{
2336 switch (link_type) {
2337 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002338 switch (addr_type) {
2339 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002340 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002341
Johan Hedberg48264f02011-11-09 13:58:58 +02002342 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002343 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002344 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002345 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002346
Johan Hedberg4c659c32011-11-07 23:13:39 +02002347 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002348 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002349 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002350 }
2351}
2352
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002353static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2354 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002355{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002356 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002357 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002358 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002359 int err;
2360 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002361
2362 BT_DBG("");
2363
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002364 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002365
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002366 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002367 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002368 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002369 goto unlock;
2370 }
2371
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002372 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002373 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2374 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002375 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002376 }
2377
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002378 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002379 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002380 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002381 err = -ENOMEM;
2382 goto unlock;
2383 }
2384
Johan Hedberg2784eb42011-01-21 13:56:35 +02002385 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002386 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002387 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2388 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002389 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002390 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002391 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002392 continue;
2393 i++;
2394 }
2395
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002396 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002397
Johan Hedberg4c659c32011-11-07 23:13:39 +02002398 /* Recalculate length in case of filtered SCO connections, etc */
2399 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002400
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002401 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002402 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002403
Johan Hedberga38528f2011-01-22 06:46:43 +02002404 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002405
2406unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002407 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002408 return err;
2409}
2410
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002411static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002412 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002413{
2414 struct pending_cmd *cmd;
2415 int err;
2416
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002417 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002418 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002419 if (!cmd)
2420 return -ENOMEM;
2421
Johan Hedbergd8457692012-02-17 14:24:57 +02002422 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002423 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002424 if (err < 0)
2425 mgmt_pending_remove(cmd);
2426
2427 return err;
2428}
2429
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002430static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002431 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002432{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002433 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002434 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002435 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002436 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002437 int err;
2438
2439 BT_DBG("");
2440
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002441 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002442
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002443 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002444 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002445 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002446 goto failed;
2447 }
2448
Johan Hedbergd8457692012-02-17 14:24:57 +02002449 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002450 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002451 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002452 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002453 goto failed;
2454 }
2455
2456 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002457 struct mgmt_cp_pin_code_neg_reply ncp;
2458
2459 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002460
2461 BT_ERR("PIN code is not 16 bytes long");
2462
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002463 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002464 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002465 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002466 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002467
2468 goto failed;
2469 }
2470
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002471 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002472 if (!cmd) {
2473 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002474 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002475 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002476
Johan Hedbergd8457692012-02-17 14:24:57 +02002477 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002478 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002479 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002480
2481 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2482 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002483 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002484
2485failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002486 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002487 return err;
2488}
2489
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002490static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2491 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002492{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002493 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002494
2495 BT_DBG("");
2496
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002497 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002498
2499 hdev->io_capability = cp->io_capability;
2500
2501 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002502 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002503
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002504 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002505
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2507 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002508}
2509
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002510static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002511{
2512 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002513 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002514
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002515 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002516 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2517 continue;
2518
Johan Hedberge9a416b2011-02-19 12:05:56 -03002519 if (cmd->user_data != conn)
2520 continue;
2521
2522 return cmd;
2523 }
2524
2525 return NULL;
2526}
2527
2528static void pairing_complete(struct pending_cmd *cmd, u8 status)
2529{
2530 struct mgmt_rp_pair_device rp;
2531 struct hci_conn *conn = cmd->user_data;
2532
Johan Hedbergba4e5642011-11-11 00:07:34 +02002533 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002534 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002535
Johan Hedbergaee9b212012-02-18 15:07:59 +02002536 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002537 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002538
2539 /* So we don't get further callbacks for this connection */
2540 conn->connect_cfm_cb = NULL;
2541 conn->security_cfm_cb = NULL;
2542 conn->disconn_cfm_cb = NULL;
2543
David Herrmann76a68ba2013-04-06 20:28:37 +02002544 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002545
Johan Hedberga664b5b2011-02-19 12:06:02 -03002546 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002547}
2548
2549static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2550{
2551 struct pending_cmd *cmd;
2552
2553 BT_DBG("status %u", status);
2554
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002555 cmd = find_pairing(conn);
2556 if (!cmd)
2557 BT_DBG("Unable to find a pending command");
2558 else
Johan Hedberge2113262012-02-18 15:20:03 +02002559 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002560}
2561
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302562static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2563{
2564 struct pending_cmd *cmd;
2565
2566 BT_DBG("status %u", status);
2567
2568 if (!status)
2569 return;
2570
2571 cmd = find_pairing(conn);
2572 if (!cmd)
2573 BT_DBG("Unable to find a pending command");
2574 else
2575 pairing_complete(cmd, mgmt_status(status));
2576}
2577
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002578static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002579 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002580{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002581 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002582 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002583 struct pending_cmd *cmd;
2584 u8 sec_level, auth_type;
2585 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002586 int err;
2587
2588 BT_DBG("");
2589
Szymon Jancf950a30e2013-01-18 12:48:07 +01002590 memset(&rp, 0, sizeof(rp));
2591 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2592 rp.addr.type = cp->addr.type;
2593
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002594 if (!bdaddr_type_is_valid(cp->addr.type))
2595 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2596 MGMT_STATUS_INVALID_PARAMS,
2597 &rp, sizeof(rp));
2598
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002599 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002600
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002601 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002602 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2603 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002604 goto unlock;
2605 }
2606
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002607 sec_level = BT_SECURITY_MEDIUM;
2608 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002609 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002610 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002611 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002612
Andre Guedes591f47f2012-04-24 21:02:49 -03002613 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002614 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2615 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002616 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002617 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2618 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002619
Ville Tervo30e76272011-02-22 16:10:53 -03002620 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002621 int status;
2622
2623 if (PTR_ERR(conn) == -EBUSY)
2624 status = MGMT_STATUS_BUSY;
2625 else
2626 status = MGMT_STATUS_CONNECT_FAILED;
2627
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002628 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002629 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002630 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002631 goto unlock;
2632 }
2633
2634 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002635 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002636 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002637 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002638 goto unlock;
2639 }
2640
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002641 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002642 if (!cmd) {
2643 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002644 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002645 goto unlock;
2646 }
2647
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002648 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002649 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002650 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302651 else
2652 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002653
Johan Hedberge9a416b2011-02-19 12:05:56 -03002654 conn->security_cfm_cb = pairing_complete_cb;
2655 conn->disconn_cfm_cb = pairing_complete_cb;
2656 conn->io_capability = cp->io_cap;
2657 cmd->user_data = conn;
2658
2659 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002660 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002661 pairing_complete(cmd, 0);
2662
2663 err = 0;
2664
2665unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002666 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002667 return err;
2668}
2669
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002670static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2671 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002672{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002673 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002674 struct pending_cmd *cmd;
2675 struct hci_conn *conn;
2676 int err;
2677
2678 BT_DBG("");
2679
Johan Hedberg28424702012-02-02 04:02:29 +02002680 hci_dev_lock(hdev);
2681
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002682 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002683 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002684 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002685 goto unlock;
2686 }
2687
Johan Hedberg28424702012-02-02 04:02:29 +02002688 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2689 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002690 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002691 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002692 goto unlock;
2693 }
2694
2695 conn = cmd->user_data;
2696
2697 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002698 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002699 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002700 goto unlock;
2701 }
2702
2703 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2704
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002705 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002706 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002707unlock:
2708 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002709 return err;
2710}
2711
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002712static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002713 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002714 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002715{
Johan Hedberga5c29682011-02-19 12:05:57 -03002716 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002717 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002718 int err;
2719
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002720 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002721
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002722 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002723 err = cmd_complete(sk, hdev->id, mgmt_op,
2724 MGMT_STATUS_NOT_POWERED, addr,
2725 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002726 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002727 }
2728
Johan Hedberg1707c602013-03-15 17:07:15 -05002729 if (addr->type == BDADDR_BREDR)
2730 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002731 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002732 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002733
Johan Hedberg272d90d2012-02-09 15:26:12 +02002734 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002735 err = cmd_complete(sk, hdev->id, mgmt_op,
2736 MGMT_STATUS_NOT_CONNECTED, addr,
2737 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002738 goto done;
2739 }
2740
Johan Hedberg1707c602013-03-15 17:07:15 -05002741 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002742 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002743 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002744
Brian Gix5fe57d92011-12-21 16:12:13 -08002745 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002746 err = cmd_complete(sk, hdev->id, mgmt_op,
2747 MGMT_STATUS_SUCCESS, addr,
2748 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002749 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002750 err = cmd_complete(sk, hdev->id, mgmt_op,
2751 MGMT_STATUS_FAILED, addr,
2752 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002753
Brian Gix47c15e22011-11-16 13:53:14 -08002754 goto done;
2755 }
2756
Johan Hedberg1707c602013-03-15 17:07:15 -05002757 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002758 if (!cmd) {
2759 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002760 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002761 }
2762
Brian Gix0df4c182011-11-16 13:53:13 -08002763 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002764 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2765 struct hci_cp_user_passkey_reply cp;
2766
Johan Hedberg1707c602013-03-15 17:07:15 -05002767 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002768 cp.passkey = passkey;
2769 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2770 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002771 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2772 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002773
Johan Hedberga664b5b2011-02-19 12:06:02 -03002774 if (err < 0)
2775 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002776
Brian Gix0df4c182011-11-16 13:53:13 -08002777done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002778 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002779 return err;
2780}
2781
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302782static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2783 void *data, u16 len)
2784{
2785 struct mgmt_cp_pin_code_neg_reply *cp = data;
2786
2787 BT_DBG("");
2788
Johan Hedberg1707c602013-03-15 17:07:15 -05002789 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302790 MGMT_OP_PIN_CODE_NEG_REPLY,
2791 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2792}
2793
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002794static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2795 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002796{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002797 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002798
2799 BT_DBG("");
2800
2801 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002802 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002803 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002804
Johan Hedberg1707c602013-03-15 17:07:15 -05002805 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002806 MGMT_OP_USER_CONFIRM_REPLY,
2807 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002808}
2809
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002810static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002811 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002812{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002813 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002814
2815 BT_DBG("");
2816
Johan Hedberg1707c602013-03-15 17:07:15 -05002817 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002818 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2819 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002820}
2821
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002822static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2823 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002824{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002825 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002826
2827 BT_DBG("");
2828
Johan Hedberg1707c602013-03-15 17:07:15 -05002829 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002830 MGMT_OP_USER_PASSKEY_REPLY,
2831 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002832}
2833
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002834static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002835 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002836{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002837 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002838
2839 BT_DBG("");
2840
Johan Hedberg1707c602013-03-15 17:07:15 -05002841 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002842 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2843 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002844}
2845
Johan Hedberg13928972013-03-15 17:07:00 -05002846static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002847{
Johan Hedberg13928972013-03-15 17:07:00 -05002848 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002849 struct hci_cp_write_local_name cp;
2850
Johan Hedberg13928972013-03-15 17:07:00 -05002851 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002852
Johan Hedberg890ea892013-03-15 17:06:52 -05002853 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002854}
2855
Johan Hedberg13928972013-03-15 17:07:00 -05002856static void set_name_complete(struct hci_dev *hdev, u8 status)
2857{
2858 struct mgmt_cp_set_local_name *cp;
2859 struct pending_cmd *cmd;
2860
2861 BT_DBG("status 0x%02x", status);
2862
2863 hci_dev_lock(hdev);
2864
2865 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2866 if (!cmd)
2867 goto unlock;
2868
2869 cp = cmd->param;
2870
2871 if (status)
2872 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2873 mgmt_status(status));
2874 else
2875 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2876 cp, sizeof(*cp));
2877
2878 mgmt_pending_remove(cmd);
2879
2880unlock:
2881 hci_dev_unlock(hdev);
2882}
2883
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002884static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002885 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002886{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002887 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002888 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002889 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002890 int err;
2891
2892 BT_DBG("");
2893
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002894 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002895
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002896 /* If the old values are the same as the new ones just return a
2897 * direct command complete event.
2898 */
2899 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2900 !memcmp(hdev->short_name, cp->short_name,
2901 sizeof(hdev->short_name))) {
2902 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2903 data, len);
2904 goto failed;
2905 }
2906
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002907 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002908
Johan Hedbergb5235a62012-02-21 14:32:24 +02002909 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002910 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002911
2912 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002913 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002914 if (err < 0)
2915 goto failed;
2916
2917 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002918 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002919
Johan Hedbergb5235a62012-02-21 14:32:24 +02002920 goto failed;
2921 }
2922
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002923 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002924 if (!cmd) {
2925 err = -ENOMEM;
2926 goto failed;
2927 }
2928
Johan Hedberg13928972013-03-15 17:07:00 -05002929 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2930
Johan Hedberg890ea892013-03-15 17:06:52 -05002931 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002932
2933 if (lmp_bredr_capable(hdev)) {
2934 update_name(&req);
2935 update_eir(&req);
2936 }
2937
2938 if (lmp_le_capable(hdev))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002939 update_ad(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05002940
Johan Hedberg13928972013-03-15 17:07:00 -05002941 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002942 if (err < 0)
2943 mgmt_pending_remove(cmd);
2944
2945failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002946 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002947 return err;
2948}
2949
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002950static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002951 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002952{
Szymon Jancc35938b2011-03-22 13:12:21 +01002953 struct pending_cmd *cmd;
2954 int err;
2955
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002956 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002957
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002958 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002959
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002960 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002961 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002962 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002963 goto unlock;
2964 }
2965
Andre Guedes9a1a1992012-07-24 15:03:48 -03002966 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002967 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002968 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002969 goto unlock;
2970 }
2971
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002972 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002973 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002974 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002975 goto unlock;
2976 }
2977
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002978 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002979 if (!cmd) {
2980 err = -ENOMEM;
2981 goto unlock;
2982 }
2983
2984 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2985 if (err < 0)
2986 mgmt_pending_remove(cmd);
2987
2988unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002989 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002990 return err;
2991}
2992
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002993static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002994 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002995{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002996 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002997 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002998 int err;
2999
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003000 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003001
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003002 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003003
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003004 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003005 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01003006 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003007 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01003008 else
Szymon Janca6785be2012-12-13 15:11:21 +01003009 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003010
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003011 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003012 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003013
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003014 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003015 return err;
3016}
3017
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003018static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003019 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01003020{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003021 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003022 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01003023 int err;
3024
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003025 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01003026
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003027 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003028
Johan Hedberg664ce4c2012-02-09 15:44:09 +02003029 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01003030 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003031 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01003032 else
Szymon Janca6785be2012-12-13 15:11:21 +01003033 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02003034
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003035 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01003037
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003038 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01003039 return err;
3040}
3041
Andre Guedes41dc2bd2013-04-30 15:29:30 -03003042static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
3043{
3044 struct pending_cmd *cmd;
3045 u8 type;
3046 int err;
3047
3048 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3049
3050 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3051 if (!cmd)
3052 return -ENOENT;
3053
3054 type = hdev->discovery.type;
3055
3056 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3057 &type, sizeof(type));
3058 mgmt_pending_remove(cmd);
3059
3060 return err;
3061}
3062
Andre Guedes7c307722013-04-30 15:29:28 -03003063static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3064{
3065 BT_DBG("status %d", status);
3066
3067 if (status) {
3068 hci_dev_lock(hdev);
3069 mgmt_start_discovery_failed(hdev, status);
3070 hci_dev_unlock(hdev);
3071 return;
3072 }
3073
3074 hci_dev_lock(hdev);
3075 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3076 hci_dev_unlock(hdev);
3077
3078 switch (hdev->discovery.type) {
3079 case DISCOV_TYPE_LE:
3080 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003081 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003082 break;
3083
3084 case DISCOV_TYPE_INTERLEAVED:
3085 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003086 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003087 break;
3088
3089 case DISCOV_TYPE_BREDR:
3090 break;
3091
3092 default:
3093 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3094 }
3095}
3096
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003097static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003098 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003099{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003100 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003101 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003102 struct hci_cp_le_set_scan_param param_cp;
3103 struct hci_cp_le_set_scan_enable enable_cp;
3104 struct hci_cp_inquiry inq_cp;
3105 struct hci_request req;
3106 /* General inquiry access code (GIAC) */
3107 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003108 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003109 int err;
3110
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003111 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003112
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003113 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003114
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003115 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003116 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003117 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003118 goto failed;
3119 }
3120
Andre Guedes642be6c2012-03-21 00:03:37 -03003121 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3122 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3123 MGMT_STATUS_BUSY);
3124 goto failed;
3125 }
3126
Johan Hedbergff9ef572012-01-04 14:23:45 +02003127 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003128 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003129 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003130 goto failed;
3131 }
3132
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003133 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003134 if (!cmd) {
3135 err = -ENOMEM;
3136 goto failed;
3137 }
3138
Andre Guedes4aab14e2012-02-17 20:39:36 -03003139 hdev->discovery.type = cp->type;
3140
Andre Guedes7c307722013-04-30 15:29:28 -03003141 hci_req_init(&req, hdev);
3142
Andre Guedes4aab14e2012-02-17 20:39:36 -03003143 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003144 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003145 status = mgmt_bredr_support(hdev);
3146 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003147 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003148 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003149 mgmt_pending_remove(cmd);
3150 goto failed;
3151 }
3152
Andre Guedes7c307722013-04-30 15:29:28 -03003153 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3154 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3155 MGMT_STATUS_BUSY);
3156 mgmt_pending_remove(cmd);
3157 goto failed;
3158 }
3159
3160 hci_inquiry_cache_flush(hdev);
3161
3162 memset(&inq_cp, 0, sizeof(inq_cp));
3163 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003164 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003165 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003166 break;
3167
3168 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003169 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003170 status = mgmt_le_support(hdev);
3171 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003172 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003173 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003174 mgmt_pending_remove(cmd);
3175 goto failed;
3176 }
3177
Andre Guedes7c307722013-04-30 15:29:28 -03003178 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003179 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003180 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3181 MGMT_STATUS_NOT_SUPPORTED);
3182 mgmt_pending_remove(cmd);
3183 goto failed;
3184 }
3185
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003186 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003187 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3188 MGMT_STATUS_REJECTED);
3189 mgmt_pending_remove(cmd);
3190 goto failed;
3191 }
3192
3193 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3194 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3195 MGMT_STATUS_BUSY);
3196 mgmt_pending_remove(cmd);
3197 goto failed;
3198 }
3199
3200 memset(&param_cp, 0, sizeof(param_cp));
3201 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003202 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3203 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07003204 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
3205 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
3206 else
3207 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03003208 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3209 &param_cp);
3210
3211 memset(&enable_cp, 0, sizeof(enable_cp));
3212 enable_cp.enable = LE_SCAN_ENABLE;
3213 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3214 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3215 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003216 break;
3217
Andre Guedesf39799f2012-02-17 20:39:35 -03003218 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003219 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3220 MGMT_STATUS_INVALID_PARAMS);
3221 mgmt_pending_remove(cmd);
3222 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003223 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003224
Andre Guedes7c307722013-04-30 15:29:28 -03003225 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003226 if (err < 0)
3227 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003228 else
3229 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003230
3231failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003232 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003233 return err;
3234}
3235
Andre Guedes1183fdc2013-04-30 15:29:35 -03003236static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3237{
3238 struct pending_cmd *cmd;
3239 int err;
3240
3241 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3242 if (!cmd)
3243 return -ENOENT;
3244
3245 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3246 &hdev->discovery.type, sizeof(hdev->discovery.type));
3247 mgmt_pending_remove(cmd);
3248
3249 return err;
3250}
3251
Andre Guedes0e05bba2013-04-30 15:29:33 -03003252static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3253{
3254 BT_DBG("status %d", status);
3255
3256 hci_dev_lock(hdev);
3257
3258 if (status) {
3259 mgmt_stop_discovery_failed(hdev, status);
3260 goto unlock;
3261 }
3262
3263 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3264
3265unlock:
3266 hci_dev_unlock(hdev);
3267}
3268
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003269static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003270 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003271{
Johan Hedbergd9306502012-02-20 23:25:18 +02003272 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003273 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003274 struct hci_cp_remote_name_req_cancel cp;
3275 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003276 struct hci_request req;
3277 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003278 int err;
3279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003280 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003281
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003282 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003283
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003284 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003285 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003286 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3287 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003288 goto unlock;
3289 }
3290
3291 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003292 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003293 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3294 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003295 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003296 }
3297
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003298 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003299 if (!cmd) {
3300 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003301 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003302 }
3303
Andre Guedes0e05bba2013-04-30 15:29:33 -03003304 hci_req_init(&req, hdev);
3305
Andre Guedese0d9727e2012-03-20 15:15:36 -03003306 switch (hdev->discovery.state) {
3307 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003308 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3309 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3310 } else {
3311 cancel_delayed_work(&hdev->le_scan_disable);
3312
3313 memset(&enable_cp, 0, sizeof(enable_cp));
3314 enable_cp.enable = LE_SCAN_DISABLE;
3315 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3316 sizeof(enable_cp), &enable_cp);
3317 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003318
Andre Guedese0d9727e2012-03-20 15:15:36 -03003319 break;
3320
3321 case DISCOVERY_RESOLVING:
3322 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003323 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003324 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003325 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003326 err = cmd_complete(sk, hdev->id,
3327 MGMT_OP_STOP_DISCOVERY, 0,
3328 &mgmt_cp->type,
3329 sizeof(mgmt_cp->type));
3330 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3331 goto unlock;
3332 }
3333
3334 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003335 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3336 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003337
3338 break;
3339
3340 default:
3341 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003342
3343 mgmt_pending_remove(cmd);
3344 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3345 MGMT_STATUS_FAILED, &mgmt_cp->type,
3346 sizeof(mgmt_cp->type));
3347 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003348 }
3349
Andre Guedes0e05bba2013-04-30 15:29:33 -03003350 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003351 if (err < 0)
3352 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003353 else
3354 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003355
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003356unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003357 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003358 return err;
3359}
3360
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003361static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003362 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003363{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003364 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003365 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003366 int err;
3367
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003368 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003369
Johan Hedberg561aafb2012-01-04 13:31:59 +02003370 hci_dev_lock(hdev);
3371
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003372 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003373 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003374 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003375 goto failed;
3376 }
3377
Johan Hedberga198e7b2012-02-17 14:27:06 +02003378 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003379 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003380 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003381 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003382 goto failed;
3383 }
3384
3385 if (cp->name_known) {
3386 e->name_state = NAME_KNOWN;
3387 list_del(&e->list);
3388 } else {
3389 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003390 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003391 }
3392
Johan Hedberge3846622013-01-09 15:29:33 +02003393 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3394 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003395
3396failed:
3397 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003398 return err;
3399}
3400
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003401static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003402 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003403{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003404 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003405 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003406 int err;
3407
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003408 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003409
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003410 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003411 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3412 MGMT_STATUS_INVALID_PARAMS,
3413 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003414
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003415 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003416
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003417 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003418 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003419 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003420 else
Szymon Janca6785be2012-12-13 15:11:21 +01003421 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003422
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003423 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003424 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003425
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003426 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003427
3428 return err;
3429}
3430
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003431static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003432 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003433{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003434 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003435 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003436 int err;
3437
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003438 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003439
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003440 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003441 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3442 MGMT_STATUS_INVALID_PARAMS,
3443 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003444
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003445 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003446
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003447 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003448 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003449 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003450 else
Szymon Janca6785be2012-12-13 15:11:21 +01003451 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003453 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003454 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003455
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003456 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003457
3458 return err;
3459}
3460
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003461static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3462 u16 len)
3463{
3464 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003465 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003466 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003467 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003468
3469 BT_DBG("%s", hdev->name);
3470
Szymon Jancc72d4b82012-03-16 16:02:57 +01003471 source = __le16_to_cpu(cp->source);
3472
3473 if (source > 0x0002)
3474 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3475 MGMT_STATUS_INVALID_PARAMS);
3476
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003477 hci_dev_lock(hdev);
3478
Szymon Jancc72d4b82012-03-16 16:02:57 +01003479 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003480 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3481 hdev->devid_product = __le16_to_cpu(cp->product);
3482 hdev->devid_version = __le16_to_cpu(cp->version);
3483
3484 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3485
Johan Hedberg890ea892013-03-15 17:06:52 -05003486 hci_req_init(&req, hdev);
3487 update_eir(&req);
3488 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003489
3490 hci_dev_unlock(hdev);
3491
3492 return err;
3493}
3494
Johan Hedberg4375f102013-09-25 13:26:10 +03003495static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3496{
3497 struct cmd_lookup match = { NULL, hdev };
3498
3499 if (status) {
3500 u8 mgmt_err = mgmt_status(status);
3501
3502 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3503 cmd_status_rsp, &mgmt_err);
3504 return;
3505 }
3506
3507 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3508 &match);
3509
3510 new_settings(hdev, match.sk);
3511
3512 if (match.sk)
3513 sock_put(match.sk);
3514}
3515
Marcel Holtmann21b51872013-10-10 09:47:53 -07003516static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3517 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003518{
3519 struct mgmt_mode *cp = data;
3520 struct pending_cmd *cmd;
3521 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003522 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003523 int err;
3524
3525 BT_DBG("request for %s", hdev->name);
3526
Johan Hedberge6fe7982013-10-02 15:45:22 +03003527 status = mgmt_le_support(hdev);
3528 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003529 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003530 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003531
3532 if (cp->val != 0x00 && cp->val != 0x01)
3533 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3534 MGMT_STATUS_INVALID_PARAMS);
3535
3536 hci_dev_lock(hdev);
3537
3538 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003539 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003540
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003541 /* The following conditions are ones which mean that we should
3542 * not do any HCI communication but directly send a mgmt
3543 * response to user space (after toggling the flag if
3544 * necessary).
3545 */
3546 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003547 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003548 bool changed = false;
3549
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003550 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3551 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003552 changed = true;
3553 }
3554
3555 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3556 if (err < 0)
3557 goto unlock;
3558
3559 if (changed)
3560 err = new_settings(hdev, sk);
3561
3562 goto unlock;
3563 }
3564
3565 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3566 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3567 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3568 MGMT_STATUS_BUSY);
3569 goto unlock;
3570 }
3571
3572 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3573 if (!cmd) {
3574 err = -ENOMEM;
3575 goto unlock;
3576 }
3577
3578 hci_req_init(&req, hdev);
3579
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003580 if (val)
3581 enable_advertising(&req);
3582 else
3583 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003584
3585 err = hci_req_run(&req, set_advertising_complete);
3586 if (err < 0)
3587 mgmt_pending_remove(cmd);
3588
3589unlock:
3590 hci_dev_unlock(hdev);
3591 return err;
3592}
3593
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003594static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3595 void *data, u16 len)
3596{
3597 struct mgmt_cp_set_static_address *cp = data;
3598 int err;
3599
3600 BT_DBG("%s", hdev->name);
3601
Marcel Holtmann62af4442013-10-02 22:10:32 -07003602 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003603 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003604 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003605
3606 if (hdev_is_powered(hdev))
3607 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3608 MGMT_STATUS_REJECTED);
3609
3610 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3611 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3612 return cmd_status(sk, hdev->id,
3613 MGMT_OP_SET_STATIC_ADDRESS,
3614 MGMT_STATUS_INVALID_PARAMS);
3615
3616 /* Two most significant bits shall be set */
3617 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3618 return cmd_status(sk, hdev->id,
3619 MGMT_OP_SET_STATIC_ADDRESS,
3620 MGMT_STATUS_INVALID_PARAMS);
3621 }
3622
3623 hci_dev_lock(hdev);
3624
3625 bacpy(&hdev->static_addr, &cp->bdaddr);
3626
3627 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3628
3629 hci_dev_unlock(hdev);
3630
3631 return err;
3632}
3633
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003634static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3635 void *data, u16 len)
3636{
3637 struct mgmt_cp_set_scan_params *cp = data;
3638 __u16 interval, window;
3639 int err;
3640
3641 BT_DBG("%s", hdev->name);
3642
3643 if (!lmp_le_capable(hdev))
3644 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3645 MGMT_STATUS_NOT_SUPPORTED);
3646
3647 interval = __le16_to_cpu(cp->interval);
3648
3649 if (interval < 0x0004 || interval > 0x4000)
3650 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3651 MGMT_STATUS_INVALID_PARAMS);
3652
3653 window = __le16_to_cpu(cp->window);
3654
3655 if (window < 0x0004 || window > 0x4000)
3656 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3657 MGMT_STATUS_INVALID_PARAMS);
3658
Marcel Holtmann899e1072013-10-14 09:55:32 -07003659 if (window > interval)
3660 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3661 MGMT_STATUS_INVALID_PARAMS);
3662
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003663 hci_dev_lock(hdev);
3664
3665 hdev->le_scan_interval = interval;
3666 hdev->le_scan_window = window;
3667
3668 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3669
3670 hci_dev_unlock(hdev);
3671
3672 return err;
3673}
3674
Johan Hedberg33e38b32013-03-15 17:07:05 -05003675static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3676{
3677 struct pending_cmd *cmd;
3678
3679 BT_DBG("status 0x%02x", status);
3680
3681 hci_dev_lock(hdev);
3682
3683 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3684 if (!cmd)
3685 goto unlock;
3686
3687 if (status) {
3688 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3689 mgmt_status(status));
3690 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003691 struct mgmt_mode *cp = cmd->param;
3692
3693 if (cp->val)
3694 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3695 else
3696 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3697
Johan Hedberg33e38b32013-03-15 17:07:05 -05003698 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3699 new_settings(hdev, cmd->sk);
3700 }
3701
3702 mgmt_pending_remove(cmd);
3703
3704unlock:
3705 hci_dev_unlock(hdev);
3706}
3707
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003708static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003709 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003710{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003711 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003712 struct pending_cmd *cmd;
3713 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003714 int err;
3715
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003716 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003717
Johan Hedberg56f87902013-10-02 13:43:13 +03003718 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3719 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003720 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3721 MGMT_STATUS_NOT_SUPPORTED);
3722
Johan Hedberga7e80f22013-01-09 16:05:19 +02003723 if (cp->val != 0x00 && cp->val != 0x01)
3724 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3725 MGMT_STATUS_INVALID_PARAMS);
3726
Johan Hedberg5400c042012-02-21 16:40:33 +02003727 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003728 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003729 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003730
3731 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003732 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003733 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003734
3735 hci_dev_lock(hdev);
3736
Johan Hedberg05cbf292013-03-15 17:07:07 -05003737 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3738 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3739 MGMT_STATUS_BUSY);
3740 goto unlock;
3741 }
3742
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003743 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3744 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3745 hdev);
3746 goto unlock;
3747 }
3748
Johan Hedberg33e38b32013-03-15 17:07:05 -05003749 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3750 data, len);
3751 if (!cmd) {
3752 err = -ENOMEM;
3753 goto unlock;
3754 }
3755
3756 hci_req_init(&req, hdev);
3757
Johan Hedberg406d7802013-03-15 17:07:09 -05003758 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003759
3760 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003761 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003762 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003763 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003764 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003765 }
3766
Johan Hedberg33e38b32013-03-15 17:07:05 -05003767unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003768 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003769
Antti Julkuf6422ec2011-06-22 13:11:56 +03003770 return err;
3771}
3772
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003773static void set_bredr_scan(struct hci_request *req)
3774{
3775 struct hci_dev *hdev = req->hdev;
3776 u8 scan = 0;
3777
3778 /* Ensure that fast connectable is disabled. This function will
3779 * not do anything if the page scan parameters are already what
3780 * they should be.
3781 */
3782 write_fast_connectable(req, false);
3783
3784 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3785 scan |= SCAN_PAGE;
3786 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3787 scan |= SCAN_INQUIRY;
3788
3789 if (scan)
3790 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3791}
3792
Johan Hedberg0663ca22013-10-02 13:43:14 +03003793static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3794{
3795 struct pending_cmd *cmd;
3796
3797 BT_DBG("status 0x%02x", status);
3798
3799 hci_dev_lock(hdev);
3800
3801 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3802 if (!cmd)
3803 goto unlock;
3804
3805 if (status) {
3806 u8 mgmt_err = mgmt_status(status);
3807
3808 /* We need to restore the flag if related HCI commands
3809 * failed.
3810 */
3811 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3812
3813 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3814 } else {
3815 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3816 new_settings(hdev, cmd->sk);
3817 }
3818
3819 mgmt_pending_remove(cmd);
3820
3821unlock:
3822 hci_dev_unlock(hdev);
3823}
3824
3825static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3826{
3827 struct mgmt_mode *cp = data;
3828 struct pending_cmd *cmd;
3829 struct hci_request req;
3830 int err;
3831
3832 BT_DBG("request for %s", hdev->name);
3833
3834 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3835 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3836 MGMT_STATUS_NOT_SUPPORTED);
3837
3838 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3839 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3840 MGMT_STATUS_REJECTED);
3841
3842 if (cp->val != 0x00 && cp->val != 0x01)
3843 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3844 MGMT_STATUS_INVALID_PARAMS);
3845
3846 hci_dev_lock(hdev);
3847
3848 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3849 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3850 goto unlock;
3851 }
3852
3853 if (!hdev_is_powered(hdev)) {
3854 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003855 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3856 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3857 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3858 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3859 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3860 }
3861
3862 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3863
3864 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3865 if (err < 0)
3866 goto unlock;
3867
3868 err = new_settings(hdev, sk);
3869 goto unlock;
3870 }
3871
3872 /* Reject disabling when powered on */
3873 if (!cp->val) {
3874 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3875 MGMT_STATUS_REJECTED);
3876 goto unlock;
3877 }
3878
3879 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3880 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3881 MGMT_STATUS_BUSY);
3882 goto unlock;
3883 }
3884
3885 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3886 if (!cmd) {
3887 err = -ENOMEM;
3888 goto unlock;
3889 }
3890
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07003891 /* We need to flip the bit already here so that update_ad
Johan Hedberg0663ca22013-10-02 13:43:14 +03003892 * generates the correct flags.
3893 */
3894 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3895
3896 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003897
3898 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3899 set_bredr_scan(&req);
3900
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07003901 update_ad(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003902
Johan Hedberg0663ca22013-10-02 13:43:14 +03003903 err = hci_req_run(&req, set_bredr_complete);
3904 if (err < 0)
3905 mgmt_pending_remove(cmd);
3906
3907unlock:
3908 hci_dev_unlock(hdev);
3909 return err;
3910}
3911
Johan Hedberg3f706b72013-01-20 14:27:16 +02003912static bool ltk_is_valid(struct mgmt_ltk_info *key)
3913{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003914 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3915 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003916 if (key->master != 0x00 && key->master != 0x01)
3917 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003918 if (!bdaddr_type_is_le(key->addr.type))
3919 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003920 return true;
3921}
3922
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003923static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003924 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003925{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003926 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3927 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003928 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003929
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003930 BT_DBG("request for %s", hdev->name);
3931
3932 if (!lmp_le_capable(hdev))
3933 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3934 MGMT_STATUS_NOT_SUPPORTED);
3935
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003936 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003937
3938 expected_len = sizeof(*cp) + key_count *
3939 sizeof(struct mgmt_ltk_info);
3940 if (expected_len != len) {
3941 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003942 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003943 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003944 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003945 }
3946
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003947 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003948
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003949 for (i = 0; i < key_count; i++) {
3950 struct mgmt_ltk_info *key = &cp->keys[i];
3951
Johan Hedberg3f706b72013-01-20 14:27:16 +02003952 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003953 return cmd_status(sk, hdev->id,
3954 MGMT_OP_LOAD_LONG_TERM_KEYS,
3955 MGMT_STATUS_INVALID_PARAMS);
3956 }
3957
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003958 hci_dev_lock(hdev);
3959
3960 hci_smp_ltks_clear(hdev);
3961
3962 for (i = 0; i < key_count; i++) {
3963 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003964 u8 type, addr_type;
3965
3966 if (key->addr.type == BDADDR_LE_PUBLIC)
3967 addr_type = ADDR_LE_DEV_PUBLIC;
3968 else
3969 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003970
3971 if (key->master)
3972 type = HCI_SMP_LTK;
3973 else
3974 type = HCI_SMP_LTK_SLAVE;
3975
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003976 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003977 type, 0, key->authenticated, key->val,
3978 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003979 }
3980
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003981 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3982 NULL, 0);
3983
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003984 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003985
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003986 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003987}
3988
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003989static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003990 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3991 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003992 bool var_len;
3993 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003994} mgmt_handlers[] = {
3995 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003996 { read_version, false, MGMT_READ_VERSION_SIZE },
3997 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3998 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3999 { read_controller_info, false, MGMT_READ_INFO_SIZE },
4000 { set_powered, false, MGMT_SETTING_SIZE },
4001 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
4002 { set_connectable, false, MGMT_SETTING_SIZE },
4003 { set_fast_connectable, false, MGMT_SETTING_SIZE },
4004 { set_pairable, false, MGMT_SETTING_SIZE },
4005 { set_link_security, false, MGMT_SETTING_SIZE },
4006 { set_ssp, false, MGMT_SETTING_SIZE },
4007 { set_hs, false, MGMT_SETTING_SIZE },
4008 { set_le, false, MGMT_SETTING_SIZE },
4009 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
4010 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
4011 { add_uuid, false, MGMT_ADD_UUID_SIZE },
4012 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
4013 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
4014 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
4015 { disconnect, false, MGMT_DISCONNECT_SIZE },
4016 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
4017 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
4018 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
4019 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
4020 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
4021 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
4022 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
4023 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
4024 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
4025 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
4026 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
4027 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
4028 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
4029 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
4030 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
4031 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
4032 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
4033 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
4034 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07004035 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03004036 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03004037 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004038 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07004039 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004040};
4041
4042
Johan Hedberg03811012010-12-08 00:21:06 +02004043int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
4044{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004045 void *buf;
4046 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004047 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004048 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004049 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004050 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004051 int err;
4052
4053 BT_DBG("got %zu bytes", msglen);
4054
4055 if (msglen < sizeof(*hdr))
4056 return -EINVAL;
4057
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004058 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004059 if (!buf)
4060 return -ENOMEM;
4061
4062 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4063 err = -EFAULT;
4064 goto done;
4065 }
4066
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004067 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004068 opcode = __le16_to_cpu(hdr->opcode);
4069 index = __le16_to_cpu(hdr->index);
4070 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004071
4072 if (len != msglen - sizeof(*hdr)) {
4073 err = -EINVAL;
4074 goto done;
4075 }
4076
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004077 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004078 hdev = hci_dev_get(index);
4079 if (!hdev) {
4080 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004081 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004082 goto done;
4083 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004084
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004085 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4086 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004087 err = cmd_status(sk, index, opcode,
4088 MGMT_STATUS_INVALID_INDEX);
4089 goto done;
4090 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004091 }
4092
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004093 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004094 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004095 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004096 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004097 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004098 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004099 }
4100
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004101 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004102 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004103 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004104 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004105 goto done;
4106 }
4107
Johan Hedbergbe22b542012-03-01 22:24:41 +02004108 handler = &mgmt_handlers[opcode];
4109
4110 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004111 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004112 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004113 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004114 goto done;
4115 }
4116
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004117 if (hdev)
4118 mgmt_init_hdev(sk, hdev);
4119
4120 cp = buf + sizeof(*hdr);
4121
Johan Hedbergbe22b542012-03-01 22:24:41 +02004122 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004123 if (err < 0)
4124 goto done;
4125
Johan Hedberg03811012010-12-08 00:21:06 +02004126 err = msglen;
4127
4128done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004129 if (hdev)
4130 hci_dev_put(hdev);
4131
Johan Hedberg03811012010-12-08 00:21:06 +02004132 kfree(buf);
4133 return err;
4134}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004135
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004136void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004137{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004138 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004139 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004140
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004141 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004142}
4143
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004144void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004145{
Johan Hedberg5f159032012-03-02 03:13:19 +02004146 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004147
Marcel Holtmann1514b892013-10-06 08:25:01 -07004148 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004149 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004150
Johan Hedberg744cf192011-11-08 20:40:14 +02004151 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004152
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004153 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004154}
4155
Johan Hedberg229ab392013-03-15 17:06:53 -05004156static void powered_complete(struct hci_dev *hdev, u8 status)
4157{
4158 struct cmd_lookup match = { NULL, hdev };
4159
4160 BT_DBG("status 0x%02x", status);
4161
4162 hci_dev_lock(hdev);
4163
4164 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4165
4166 new_settings(hdev, match.sk);
4167
4168 hci_dev_unlock(hdev);
4169
4170 if (match.sk)
4171 sock_put(match.sk);
4172}
4173
Johan Hedberg70da6242013-03-15 17:06:51 -05004174static int powered_update_hci(struct hci_dev *hdev)
4175{
Johan Hedberg890ea892013-03-15 17:06:52 -05004176 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004177 u8 link_sec;
4178
Johan Hedberg890ea892013-03-15 17:06:52 -05004179 hci_req_init(&req, hdev);
4180
Johan Hedberg70da6242013-03-15 17:06:51 -05004181 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4182 !lmp_host_ssp_capable(hdev)) {
4183 u8 ssp = 1;
4184
Johan Hedberg890ea892013-03-15 17:06:52 -05004185 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004186 }
4187
Johan Hedbergc73eee92013-04-19 18:35:21 +03004188 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4189 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004190 struct hci_cp_write_le_host_supported cp;
4191
4192 cp.le = 1;
4193 cp.simul = lmp_le_br_capable(hdev);
4194
4195 /* Check first if we already have the right
4196 * host state (host features set)
4197 */
4198 if (cp.le != lmp_host_le_capable(hdev) ||
4199 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004200 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4201 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004202 }
4203
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004204 if (lmp_le_capable(hdev)) {
4205 /* Set random address to static address if configured */
4206 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4207 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4208 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004209
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004210 /* Make sure the controller has a good default for
4211 * advertising data. This also applies to the case
4212 * where BR/EDR was toggled during the AUTO_OFF phase.
4213 */
4214 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4215 update_ad(&req);
4216
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004217 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4218 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004219 }
4220
Johan Hedberg70da6242013-03-15 17:06:51 -05004221 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4222 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004223 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4224 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004225
4226 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004227 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4228 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004229 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004230 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004231 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004232 }
4233
Johan Hedberg229ab392013-03-15 17:06:53 -05004234 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004235}
4236
Johan Hedberg744cf192011-11-08 20:40:14 +02004237int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004238{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004239 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004240 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4241 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004242 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004243
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004244 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4245 return 0;
4246
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004247 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004248 if (powered_update_hci(hdev) == 0)
4249 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004250
Johan Hedberg229ab392013-03-15 17:06:53 -05004251 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4252 &match);
4253 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004254 }
4255
Johan Hedberg229ab392013-03-15 17:06:53 -05004256 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4257 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4258
4259 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4260 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4261 zero_cod, sizeof(zero_cod), NULL);
4262
4263new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004264 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004265
4266 if (match.sk)
4267 sock_put(match.sk);
4268
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004269 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004270}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004271
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004272void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004273{
4274 struct pending_cmd *cmd;
4275 u8 status;
4276
4277 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4278 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004279 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004280
4281 if (err == -ERFKILL)
4282 status = MGMT_STATUS_RFKILLED;
4283 else
4284 status = MGMT_STATUS_FAILED;
4285
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004286 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004287
4288 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004289}
4290
Marcel Holtmann86a75642013-10-15 06:33:54 -07004291void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004292{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004293 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004294
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004295 /* Nothing needed here if there's a pending command since that
4296 * commands request completion callback takes care of everything
4297 * necessary.
4298 */
4299 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004300 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004301
Marcel Holtmann86a75642013-10-15 06:33:54 -07004302 if (discoverable)
4303 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4304 else
4305 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004306
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004307 if (changed)
Marcel Holtmann86a75642013-10-15 06:33:54 -07004308 new_settings(hdev, NULL);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004309}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004310
Marcel Holtmanna3309162013-10-15 06:33:55 -07004311void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004312{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004313 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004314
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004315 /* Nothing needed here if there's a pending command since that
4316 * commands request completion callback takes care of everything
4317 * necessary.
4318 */
4319 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004320 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004321
Marcel Holtmanna3309162013-10-15 06:33:55 -07004322 if (connectable)
4323 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4324 else
4325 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004326
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004327 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004328 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004329}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004330
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004331void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004332{
Johan Hedbergca69b792011-11-11 18:10:00 +02004333 u8 mgmt_err = mgmt_status(status);
4334
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004335 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004336 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004337 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004338
4339 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004340 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004341 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004342}
4343
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004344void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4345 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004346{
Johan Hedberg86742e12011-11-07 23:13:38 +02004347 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004348
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004349 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004350
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004351 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004352 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004353 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004354 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004355 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004356 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004357
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004358 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004359}
Johan Hedbergf7520542011-01-20 12:34:39 +02004360
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004361int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4362{
4363 struct mgmt_ev_new_long_term_key ev;
4364
4365 memset(&ev, 0, sizeof(ev));
4366
4367 ev.store_hint = persistent;
4368 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004369 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004370 ev.key.authenticated = key->authenticated;
4371 ev.key.enc_size = key->enc_size;
4372 ev.key.ediv = key->ediv;
4373
4374 if (key->type == HCI_SMP_LTK)
4375 ev.key.master = 1;
4376
4377 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4378 memcpy(ev.key.val, key->val, sizeof(key->val));
4379
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004380 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4381 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004382}
4383
Marcel Holtmann94933992013-10-15 10:26:39 -07004384static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4385 u8 data_len)
4386{
4387 eir[eir_len++] = sizeof(type) + data_len;
4388 eir[eir_len++] = type;
4389 memcpy(&eir[eir_len], data, data_len);
4390 eir_len += data_len;
4391
4392 return eir_len;
4393}
4394
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004395void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4396 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4397 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004398{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004399 char buf[512];
4400 struct mgmt_ev_device_connected *ev = (void *) buf;
4401 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004402
Johan Hedbergb644ba32012-01-17 21:48:47 +02004403 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004404 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004405
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004406 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004407
Johan Hedbergb644ba32012-01-17 21:48:47 +02004408 if (name_len > 0)
4409 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004410 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004411
4412 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004413 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004414 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004415
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004416 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004417
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004418 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4419 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004420}
4421
Johan Hedberg8962ee72011-01-20 12:40:27 +02004422static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4423{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004424 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004425 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004426 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004427
Johan Hedberg88c3df12012-02-09 14:27:38 +02004428 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4429 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004430
Johan Hedbergaee9b212012-02-18 15:07:59 +02004431 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004432 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004433
4434 *sk = cmd->sk;
4435 sock_hold(*sk);
4436
Johan Hedberga664b5b2011-02-19 12:06:02 -03004437 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004438}
4439
Johan Hedberg124f6e32012-02-09 13:50:12 +02004440static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004441{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004442 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004443 struct mgmt_cp_unpair_device *cp = cmd->param;
4444 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004445
4446 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004447 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4448 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004449
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004450 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4451
Johan Hedbergaee9b212012-02-18 15:07:59 +02004452 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004453
4454 mgmt_pending_remove(cmd);
4455}
4456
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004457void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4458 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004459{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004460 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004461 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004462
Johan Hedberg744cf192011-11-08 20:40:14 +02004463 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004464
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004465 bacpy(&ev.addr.bdaddr, bdaddr);
4466 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4467 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004468
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004469 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004470
4471 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004472 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004473
Johan Hedberg124f6e32012-02-09 13:50:12 +02004474 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004475 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004476}
4477
Marcel Holtmann78929242013-10-06 23:55:47 -07004478void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4479 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004480{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004481 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004482 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004483
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004484 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4485 hdev);
4486
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004487 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004488 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004489 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004490
Johan Hedberg88c3df12012-02-09 14:27:38 +02004491 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004492 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004493
Marcel Holtmann78929242013-10-06 23:55:47 -07004494 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4495 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004496
Johan Hedberga664b5b2011-02-19 12:06:02 -03004497 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004498}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004499
Marcel Holtmann445608d2013-10-06 23:55:48 -07004500void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4501 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004502{
4503 struct mgmt_ev_connect_failed ev;
4504
Johan Hedberg4c659c32011-11-07 23:13:39 +02004505 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004506 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004507 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004508
Marcel Holtmann445608d2013-10-06 23:55:48 -07004509 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004510}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004511
Johan Hedberg744cf192011-11-08 20:40:14 +02004512int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004513{
4514 struct mgmt_ev_pin_code_request ev;
4515
Johan Hedbergd8457692012-02-17 14:24:57 +02004516 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004517 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004518 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004519
Johan Hedberg744cf192011-11-08 20:40:14 +02004520 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004521 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004522}
4523
Johan Hedberg744cf192011-11-08 20:40:14 +02004524int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004525 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004526{
4527 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004528 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004529 int err;
4530
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004531 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004532 if (!cmd)
4533 return -ENOENT;
4534
Johan Hedbergd8457692012-02-17 14:24:57 +02004535 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004536 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004537
Johan Hedbergaee9b212012-02-18 15:07:59 +02004538 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004539 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004540
Johan Hedberga664b5b2011-02-19 12:06:02 -03004541 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004542
4543 return err;
4544}
4545
Johan Hedberg744cf192011-11-08 20:40:14 +02004546int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004547 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004548{
4549 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004550 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004551 int err;
4552
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004553 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004554 if (!cmd)
4555 return -ENOENT;
4556
Johan Hedbergd8457692012-02-17 14:24:57 +02004557 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004558 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004559
Johan Hedbergaee9b212012-02-18 15:07:59 +02004560 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004561 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004562
Johan Hedberga664b5b2011-02-19 12:06:02 -03004563 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004564
4565 return err;
4566}
Johan Hedberga5c29682011-02-19 12:05:57 -03004567
Johan Hedberg744cf192011-11-08 20:40:14 +02004568int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004569 u8 link_type, u8 addr_type, __le32 value,
4570 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004571{
4572 struct mgmt_ev_user_confirm_request ev;
4573
Johan Hedberg744cf192011-11-08 20:40:14 +02004574 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004575
Johan Hedberg272d90d2012-02-09 15:26:12 +02004576 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004577 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004578 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004579 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004580
Johan Hedberg744cf192011-11-08 20:40:14 +02004581 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004582 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004583}
4584
Johan Hedberg272d90d2012-02-09 15:26:12 +02004585int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004586 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004587{
4588 struct mgmt_ev_user_passkey_request ev;
4589
4590 BT_DBG("%s", hdev->name);
4591
Johan Hedberg272d90d2012-02-09 15:26:12 +02004592 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004593 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004594
4595 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004596 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004597}
4598
Brian Gix0df4c182011-11-16 13:53:13 -08004599static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004600 u8 link_type, u8 addr_type, u8 status,
4601 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004602{
4603 struct pending_cmd *cmd;
4604 struct mgmt_rp_user_confirm_reply rp;
4605 int err;
4606
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004607 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004608 if (!cmd)
4609 return -ENOENT;
4610
Johan Hedberg272d90d2012-02-09 15:26:12 +02004611 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004612 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004613 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004614 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004615
Johan Hedberga664b5b2011-02-19 12:06:02 -03004616 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004617
4618 return err;
4619}
4620
Johan Hedberg744cf192011-11-08 20:40:14 +02004621int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004622 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004623{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004624 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004625 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004626}
4627
Johan Hedberg272d90d2012-02-09 15:26:12 +02004628int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004629 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004630{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004631 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004632 status,
4633 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004634}
Johan Hedberg2a611692011-02-19 12:06:00 -03004635
Brian Gix604086b2011-11-23 08:28:33 -08004636int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004637 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004638{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004639 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004640 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004641}
4642
Johan Hedberg272d90d2012-02-09 15:26:12 +02004643int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004644 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004645{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004646 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004647 status,
4648 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004649}
4650
Johan Hedberg92a25252012-09-06 18:39:26 +03004651int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4652 u8 link_type, u8 addr_type, u32 passkey,
4653 u8 entered)
4654{
4655 struct mgmt_ev_passkey_notify ev;
4656
4657 BT_DBG("%s", hdev->name);
4658
4659 bacpy(&ev.addr.bdaddr, bdaddr);
4660 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4661 ev.passkey = __cpu_to_le32(passkey);
4662 ev.entered = entered;
4663
4664 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4665}
4666
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004667int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004668 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004669{
4670 struct mgmt_ev_auth_failed ev;
4671
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004672 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004673 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004674 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004675
Johan Hedberg744cf192011-11-08 20:40:14 +02004676 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004677}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004678
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004679int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4680{
4681 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004682 bool changed = false;
4683 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004684
4685 if (status) {
4686 u8 mgmt_err = mgmt_status(status);
4687 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004688 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004689 return 0;
4690 }
4691
Johan Hedberg47990ea2012-02-22 11:58:37 +02004692 if (test_bit(HCI_AUTH, &hdev->flags)) {
4693 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4694 changed = true;
4695 } else {
4696 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4697 changed = true;
4698 }
4699
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004700 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004701 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004702
Johan Hedberg47990ea2012-02-22 11:58:37 +02004703 if (changed)
4704 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004705
4706 if (match.sk)
4707 sock_put(match.sk);
4708
4709 return err;
4710}
4711
Johan Hedberg890ea892013-03-15 17:06:52 -05004712static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004713{
Johan Hedberg890ea892013-03-15 17:06:52 -05004714 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004715 struct hci_cp_write_eir cp;
4716
Johan Hedberg976eb202012-10-24 21:12:01 +03004717 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004718 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004719
Johan Hedbergc80da272012-02-22 15:38:48 +02004720 memset(hdev->eir, 0, sizeof(hdev->eir));
4721
Johan Hedbergcacaf522012-02-21 00:52:42 +02004722 memset(&cp, 0, sizeof(cp));
4723
Johan Hedberg890ea892013-03-15 17:06:52 -05004724 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004725}
4726
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004727int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004728{
4729 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004730 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004731 bool changed = false;
4732 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004733
4734 if (status) {
4735 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004736
4737 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004738 &hdev->dev_flags)) {
4739 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004740 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004741 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004742
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004743 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4744 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004745
4746 return err;
4747 }
4748
4749 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004750 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004751 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004752 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4753 if (!changed)
4754 changed = test_and_clear_bit(HCI_HS_ENABLED,
4755 &hdev->dev_flags);
4756 else
4757 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004758 }
4759
4760 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4761
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004762 if (changed)
4763 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004764
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004765 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004766 sock_put(match.sk);
4767
Johan Hedberg890ea892013-03-15 17:06:52 -05004768 hci_req_init(&req, hdev);
4769
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004770 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004771 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004772 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004773 clear_eir(&req);
4774
4775 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004776
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004777 return err;
4778}
4779
Johan Hedberg92da6092013-03-15 17:06:55 -05004780static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004781{
4782 struct cmd_lookup *match = data;
4783
Johan Hedberg90e70452012-02-23 23:09:40 +02004784 if (match->sk == NULL) {
4785 match->sk = cmd->sk;
4786 sock_hold(match->sk);
4787 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004788}
4789
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004790int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004791 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004792{
Johan Hedberg90e70452012-02-23 23:09:40 +02004793 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4794 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004795
Johan Hedberg92da6092013-03-15 17:06:55 -05004796 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4797 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4798 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004799
4800 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004801 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4802 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004803
4804 if (match.sk)
4805 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004806
4807 return err;
4808}
4809
Johan Hedberg744cf192011-11-08 20:40:14 +02004810int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004811{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004812 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004813 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004814
Johan Hedberg13928972013-03-15 17:07:00 -05004815 if (status)
4816 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004817
4818 memset(&ev, 0, sizeof(ev));
4819 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004820 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004821
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004822 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004823 if (!cmd) {
4824 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004825
Johan Hedberg13928972013-03-15 17:07:00 -05004826 /* If this is a HCI command related to powering on the
4827 * HCI dev don't send any mgmt signals.
4828 */
4829 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4830 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004831 }
4832
Johan Hedberg13928972013-03-15 17:07:00 -05004833 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4834 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004835}
Szymon Jancc35938b2011-03-22 13:12:21 +01004836
Johan Hedberg744cf192011-11-08 20:40:14 +02004837int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004838 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004839{
4840 struct pending_cmd *cmd;
4841 int err;
4842
Johan Hedberg744cf192011-11-08 20:40:14 +02004843 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004844
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004845 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004846 if (!cmd)
4847 return -ENOENT;
4848
4849 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004850 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4851 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004852 } else {
4853 struct mgmt_rp_read_local_oob_data rp;
4854
4855 memcpy(rp.hash, hash, sizeof(rp.hash));
4856 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4857
Johan Hedberg744cf192011-11-08 20:40:14 +02004858 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004859 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4860 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004861 }
4862
4863 mgmt_pending_remove(cmd);
4864
4865 return err;
4866}
Johan Hedberge17acd42011-03-30 23:57:16 +03004867
Marcel Holtmann901801b2013-10-06 23:55:51 -07004868void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4869 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4870 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004871{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004872 char buf[512];
4873 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004874 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004875
Andre Guedes12602d02013-04-30 15:29:40 -03004876 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004877 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004878
Johan Hedberg1dc06092012-01-15 21:01:23 +02004879 /* Leave 5 bytes for a potential CoD field */
4880 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004881 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004882
Johan Hedberg1dc06092012-01-15 21:01:23 +02004883 memset(buf, 0, sizeof(buf));
4884
Johan Hedberge319d2e2012-01-15 19:51:59 +02004885 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004886 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004887 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004888 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304889 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004890 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304891 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004892
Johan Hedberg1dc06092012-01-15 21:01:23 +02004893 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004894 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004895
Johan Hedberg1dc06092012-01-15 21:01:23 +02004896 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4897 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004898 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004899
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004900 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004901 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004902
Marcel Holtmann901801b2013-10-06 23:55:51 -07004903 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004904}
Johan Hedberga88a9652011-03-30 13:18:12 +03004905
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004906void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4907 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004908{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004909 struct mgmt_ev_device_found *ev;
4910 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4911 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004912
Johan Hedbergb644ba32012-01-17 21:48:47 +02004913 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004914
Johan Hedbergb644ba32012-01-17 21:48:47 +02004915 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004916
Johan Hedbergb644ba32012-01-17 21:48:47 +02004917 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004918 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004919 ev->rssi = rssi;
4920
4921 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004922 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004923
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004924 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004925
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004926 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004927}
Johan Hedberg314b2382011-04-27 10:29:57 -04004928
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004929void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004930{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004931 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004932 struct pending_cmd *cmd;
4933
Andre Guedes343fb142011-11-22 17:14:19 -03004934 BT_DBG("%s discovering %u", hdev->name, discovering);
4935
Johan Hedberg164a6e72011-11-01 17:06:44 +02004936 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004937 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004938 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004939 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004940
4941 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004942 u8 type = hdev->discovery.type;
4943
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004944 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4945 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004946 mgmt_pending_remove(cmd);
4947 }
4948
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004949 memset(&ev, 0, sizeof(ev));
4950 ev.type = hdev->discovery.type;
4951 ev.discovering = discovering;
4952
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004953 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004954}
Antti Julku5e762442011-08-25 16:48:02 +03004955
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004956int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004957{
4958 struct pending_cmd *cmd;
4959 struct mgmt_ev_device_blocked ev;
4960
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004961 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004962
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004963 bacpy(&ev.addr.bdaddr, bdaddr);
4964 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004965
Johan Hedberg744cf192011-11-08 20:40:14 +02004966 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004967 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004968}
4969
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004970int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004971{
4972 struct pending_cmd *cmd;
4973 struct mgmt_ev_device_unblocked ev;
4974
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004975 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004976
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004977 bacpy(&ev.addr.bdaddr, bdaddr);
4978 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004979
Johan Hedberg744cf192011-11-08 20:40:14 +02004980 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004981 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004982}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004983
4984static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4985{
4986 BT_DBG("%s status %u", hdev->name, status);
4987
4988 /* Clear the advertising mgmt setting if we failed to re-enable it */
4989 if (status) {
4990 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004991 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004992 }
4993}
4994
4995void mgmt_reenable_advertising(struct hci_dev *hdev)
4996{
4997 struct hci_request req;
4998
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004999 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005000 return;
5001
5002 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5003 return;
5004
5005 hci_req_init(&req, hdev);
5006 enable_advertising(&req);
5007
5008 /* If this fails we have no option but to let user space know
5009 * that we've disabled advertising.
5010 */
5011 if (hci_req_run(&req, adv_enable_complete) < 0) {
5012 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005013 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005014 }
5015}