blob: c959915d308e684a92263df1be321b7ba6905e59 [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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedbergaee9b2182012-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 Hedberg84bde9d6c2012-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 Hedberg84bde9d6c2012-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 Hedbergaee9b2182012-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 Hedberg4ae143012013-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 Padovan6039aa732012-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 Hedbergaee9b2182012-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 Hedberga3d4e20a2012-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 Holtmannd1967ff2013-10-15 10:57:40 -07004291void mgmt_discoverable_timeout(struct hci_dev *hdev)
4292{
4293 struct hci_request req;
4294 u8 scan = SCAN_PAGE;
4295
4296 hci_dev_lock(hdev);
4297
4298 /* When discoverable timeout triggers, then just make sure
4299 * the limited discoverable flag is cleared. Even in the case
4300 * of a timeout triggered from general discoverable, it is
4301 * safe to unconditionally clear the flag.
4302 */
4303 clear_bit(HCI_LIMITED_DISCOVERABLE, &hdev->dev_flags);
4304
4305 hci_req_init(&req, hdev);
4306 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, sizeof(scan), &scan);
4307 update_class(&req);
4308 hci_req_run(&req, NULL);
4309
4310 hdev->discov_timeout = 0;
4311
4312 hci_dev_unlock(hdev);
4313}
4314
Marcel Holtmann86a75642013-10-15 06:33:54 -07004315void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004316{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004317 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004318
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004319 /* Nothing needed here if there's a pending command since that
4320 * commands request completion callback takes care of everything
4321 * necessary.
4322 */
4323 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004324 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004325
Marcel Holtmann86a75642013-10-15 06:33:54 -07004326 if (discoverable)
4327 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4328 else
4329 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004330
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004331 if (changed)
Marcel Holtmann86a75642013-10-15 06:33:54 -07004332 new_settings(hdev, NULL);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004333}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004334
Marcel Holtmanna3309162013-10-15 06:33:55 -07004335void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004336{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004337 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004338
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004339 /* Nothing needed here if there's a pending command since that
4340 * commands request completion callback takes care of everything
4341 * necessary.
4342 */
4343 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004344 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004345
Marcel Holtmanna3309162013-10-15 06:33:55 -07004346 if (connectable)
4347 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4348 else
4349 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004350
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004351 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004352 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004353}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004354
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004355void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004356{
Johan Hedbergca69b792011-11-11 18:10:00 +02004357 u8 mgmt_err = mgmt_status(status);
4358
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004359 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004360 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004361 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004362
4363 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004364 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004365 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004366}
4367
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004368void mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4369 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004370{
Johan Hedberg86742e12011-11-07 23:13:38 +02004371 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004372
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004373 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004374
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004375 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004376 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004377 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004378 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004379 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004380 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004381
Marcel Holtmanndc4a5ee2013-10-15 10:15:57 -07004382 mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004383}
Johan Hedbergf7520542011-01-20 12:34:39 +02004384
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004385int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4386{
4387 struct mgmt_ev_new_long_term_key ev;
4388
4389 memset(&ev, 0, sizeof(ev));
4390
4391 ev.store_hint = persistent;
4392 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004393 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004394 ev.key.authenticated = key->authenticated;
4395 ev.key.enc_size = key->enc_size;
4396 ev.key.ediv = key->ediv;
4397
4398 if (key->type == HCI_SMP_LTK)
4399 ev.key.master = 1;
4400
4401 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4402 memcpy(ev.key.val, key->val, sizeof(key->val));
4403
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004404 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4405 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004406}
4407
Marcel Holtmann94933992013-10-15 10:26:39 -07004408static inline u16 eir_append_data(u8 *eir, u16 eir_len, u8 type, u8 *data,
4409 u8 data_len)
4410{
4411 eir[eir_len++] = sizeof(type) + data_len;
4412 eir[eir_len++] = type;
4413 memcpy(&eir[eir_len], data, data_len);
4414 eir_len += data_len;
4415
4416 return eir_len;
4417}
4418
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004419void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4420 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4421 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004422{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004423 char buf[512];
4424 struct mgmt_ev_device_connected *ev = (void *) buf;
4425 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004426
Johan Hedbergb644ba32012-01-17 21:48:47 +02004427 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004428 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004429
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004430 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004431
Johan Hedbergb644ba32012-01-17 21:48:47 +02004432 if (name_len > 0)
4433 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004434 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004435
4436 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004437 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004438 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004439
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004440 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004441
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004442 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4443 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004444}
4445
Johan Hedberg8962ee72011-01-20 12:40:27 +02004446static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4447{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004448 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004449 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004450 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004451
Johan Hedberg88c3df12012-02-09 14:27:38 +02004452 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4453 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004454
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004455 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004456 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004457
4458 *sk = cmd->sk;
4459 sock_hold(*sk);
4460
Johan Hedberga664b5b2011-02-19 12:06:02 -03004461 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004462}
4463
Johan Hedberg124f6e32012-02-09 13:50:12 +02004464static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004465{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004466 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004467 struct mgmt_cp_unpair_device *cp = cmd->param;
4468 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004469
4470 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004471 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4472 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004473
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004474 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4475
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004476 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004477
4478 mgmt_pending_remove(cmd);
4479}
4480
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004481void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4482 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004483{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004484 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004485 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004486
Johan Hedberg744cf192011-11-08 20:40:14 +02004487 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004488
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004489 bacpy(&ev.addr.bdaddr, bdaddr);
4490 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4491 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004492
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004493 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004494
4495 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004496 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004497
Johan Hedberg124f6e32012-02-09 13:50:12 +02004498 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004499 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004500}
4501
Marcel Holtmann78929242013-10-06 23:55:47 -07004502void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4503 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004504{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004505 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004506 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004507
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004508 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4509 hdev);
4510
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004511 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004512 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004513 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004514
Johan Hedberg88c3df12012-02-09 14:27:38 +02004515 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004516 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004517
Marcel Holtmann78929242013-10-06 23:55:47 -07004518 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4519 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004520
Johan Hedberga664b5b2011-02-19 12:06:02 -03004521 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004522}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004523
Marcel Holtmann445608d2013-10-06 23:55:48 -07004524void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4525 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004526{
4527 struct mgmt_ev_connect_failed ev;
4528
Johan Hedberg4c659c32011-11-07 23:13:39 +02004529 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004530 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004531 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004532
Marcel Holtmann445608d2013-10-06 23:55:48 -07004533 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004534}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004535
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004536void mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004537{
4538 struct mgmt_ev_pin_code_request ev;
4539
Johan Hedbergd8457692012-02-17 14:24:57 +02004540 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004541 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004542 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004543
Marcel Holtmannce0e4a02013-10-15 14:26:20 -07004544 mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004545}
4546
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004547void mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4548 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004549{
4550 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004551 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004552
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004553 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004554 if (!cmd)
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004555 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004556
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
Marcel Holtmanne669cf82013-10-15 14:26:21 -07004560 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
4561 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
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004566void mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
4567 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004568{
4569 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004570 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004571
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004572 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004573 if (!cmd)
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004574 return;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004575
Johan Hedbergd8457692012-02-17 14:24:57 +02004576 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004577 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004578
Marcel Holtmann3eb38522013-10-15 14:26:22 -07004579 cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
4580 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004581
Johan Hedberga664b5b2011-02-19 12:06:02 -03004582 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004583}
Johan Hedberga5c29682011-02-19 12:05:57 -03004584
Johan Hedberg744cf192011-11-08 20:40:14 +02004585int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004586 u8 link_type, u8 addr_type, __le32 value,
4587 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004588{
4589 struct mgmt_ev_user_confirm_request ev;
4590
Johan Hedberg744cf192011-11-08 20:40:14 +02004591 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004592
Johan Hedberg272d90d2012-02-09 15:26:12 +02004593 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004594 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004595 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004596 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004597
Johan Hedberg744cf192011-11-08 20:40:14 +02004598 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004599 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004600}
4601
Johan Hedberg272d90d2012-02-09 15:26:12 +02004602int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004603 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004604{
4605 struct mgmt_ev_user_passkey_request ev;
4606
4607 BT_DBG("%s", hdev->name);
4608
Johan Hedberg272d90d2012-02-09 15:26:12 +02004609 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004610 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004611
4612 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004613 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004614}
4615
Brian Gix0df4c182011-11-16 13:53:13 -08004616static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004617 u8 link_type, u8 addr_type, u8 status,
4618 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004619{
4620 struct pending_cmd *cmd;
4621 struct mgmt_rp_user_confirm_reply rp;
4622 int err;
4623
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004624 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004625 if (!cmd)
4626 return -ENOENT;
4627
Johan Hedberg272d90d2012-02-09 15:26:12 +02004628 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004629 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02004630 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004631 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004632
Johan Hedberga664b5b2011-02-19 12:06:02 -03004633 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004634
4635 return err;
4636}
4637
Johan Hedberg744cf192011-11-08 20:40:14 +02004638int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004639 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004640{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004641 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004642 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004643}
4644
Johan Hedberg272d90d2012-02-09 15:26:12 +02004645int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004646 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004647{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004648 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004649 status,
4650 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004651}
Johan Hedberg2a611692011-02-19 12:06:00 -03004652
Brian Gix604086b2011-11-23 08:28:33 -08004653int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004654 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004655{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004656 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004657 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004658}
4659
Johan Hedberg272d90d2012-02-09 15:26:12 +02004660int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004661 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004662{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004663 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004664 status,
4665 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004666}
4667
Johan Hedberg92a25252012-09-06 18:39:26 +03004668int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4669 u8 link_type, u8 addr_type, u32 passkey,
4670 u8 entered)
4671{
4672 struct mgmt_ev_passkey_notify ev;
4673
4674 BT_DBG("%s", hdev->name);
4675
4676 bacpy(&ev.addr.bdaddr, bdaddr);
4677 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4678 ev.passkey = __cpu_to_le32(passkey);
4679 ev.entered = entered;
4680
4681 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4682}
4683
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004684int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004685 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004686{
4687 struct mgmt_ev_auth_failed ev;
4688
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004689 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004690 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004691 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004692
Johan Hedberg744cf192011-11-08 20:40:14 +02004693 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004694}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004695
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004696int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4697{
4698 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004699 bool changed = false;
4700 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004701
4702 if (status) {
4703 u8 mgmt_err = mgmt_status(status);
4704 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004705 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004706 return 0;
4707 }
4708
Johan Hedberg47990ea2012-02-22 11:58:37 +02004709 if (test_bit(HCI_AUTH, &hdev->flags)) {
4710 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4711 changed = true;
4712 } else {
4713 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4714 changed = true;
4715 }
4716
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004717 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004718 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004719
Johan Hedberg47990ea2012-02-22 11:58:37 +02004720 if (changed)
4721 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004722
4723 if (match.sk)
4724 sock_put(match.sk);
4725
4726 return err;
4727}
4728
Johan Hedberg890ea892013-03-15 17:06:52 -05004729static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004730{
Johan Hedberg890ea892013-03-15 17:06:52 -05004731 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004732 struct hci_cp_write_eir cp;
4733
Johan Hedberg976eb202012-10-24 21:12:01 +03004734 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004735 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004736
Johan Hedbergc80da272012-02-22 15:38:48 +02004737 memset(hdev->eir, 0, sizeof(hdev->eir));
4738
Johan Hedbergcacaf522012-02-21 00:52:42 +02004739 memset(&cp, 0, sizeof(cp));
4740
Johan Hedberg890ea892013-03-15 17:06:52 -05004741 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004742}
4743
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004744int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004745{
4746 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004747 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004748 bool changed = false;
4749 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004750
4751 if (status) {
4752 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004753
4754 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004755 &hdev->dev_flags)) {
4756 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004757 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004758 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004759
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004760 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4761 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004762
4763 return err;
4764 }
4765
4766 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004767 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004768 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004769 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4770 if (!changed)
4771 changed = test_and_clear_bit(HCI_HS_ENABLED,
4772 &hdev->dev_flags);
4773 else
4774 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004775 }
4776
4777 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4778
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004779 if (changed)
4780 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004781
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004782 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004783 sock_put(match.sk);
4784
Johan Hedberg890ea892013-03-15 17:06:52 -05004785 hci_req_init(&req, hdev);
4786
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004787 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004788 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004789 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004790 clear_eir(&req);
4791
4792 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004793
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004794 return err;
4795}
4796
Johan Hedberg92da6092013-03-15 17:06:55 -05004797static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004798{
4799 struct cmd_lookup *match = data;
4800
Johan Hedberg90e70452012-02-23 23:09:40 +02004801 if (match->sk == NULL) {
4802 match->sk = cmd->sk;
4803 sock_hold(match->sk);
4804 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004805}
4806
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004807int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004808 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004809{
Johan Hedberg90e70452012-02-23 23:09:40 +02004810 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4811 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004812
Johan Hedberg92da6092013-03-15 17:06:55 -05004813 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4814 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4815 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004816
4817 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004818 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4819 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004820
4821 if (match.sk)
4822 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004823
4824 return err;
4825}
4826
Johan Hedberg744cf192011-11-08 20:40:14 +02004827int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004828{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004829 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004830 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004831
Johan Hedberg13928972013-03-15 17:07:00 -05004832 if (status)
4833 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004834
4835 memset(&ev, 0, sizeof(ev));
4836 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004837 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004838
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004839 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004840 if (!cmd) {
4841 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004842
Johan Hedberg13928972013-03-15 17:07:00 -05004843 /* If this is a HCI command related to powering on the
4844 * HCI dev don't send any mgmt signals.
4845 */
4846 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4847 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004848 }
4849
Johan Hedberg13928972013-03-15 17:07:00 -05004850 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4851 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004852}
Szymon Jancc35938b2011-03-22 13:12:21 +01004853
Johan Hedberg744cf192011-11-08 20:40:14 +02004854int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004855 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004856{
4857 struct pending_cmd *cmd;
4858 int err;
4859
Johan Hedberg744cf192011-11-08 20:40:14 +02004860 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004861
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004862 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004863 if (!cmd)
4864 return -ENOENT;
4865
4866 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004867 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4868 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004869 } else {
4870 struct mgmt_rp_read_local_oob_data rp;
4871
4872 memcpy(rp.hash, hash, sizeof(rp.hash));
4873 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4874
Johan Hedberg744cf192011-11-08 20:40:14 +02004875 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004876 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4877 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004878 }
4879
4880 mgmt_pending_remove(cmd);
4881
4882 return err;
4883}
Johan Hedberge17acd42011-03-30 23:57:16 +03004884
Marcel Holtmann901801b2013-10-06 23:55:51 -07004885void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4886 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4887 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004888{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004889 char buf[512];
4890 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004891 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004892
Andre Guedes12602d02013-04-30 15:29:40 -03004893 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004894 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004895
Johan Hedberg1dc06092012-01-15 21:01:23 +02004896 /* Leave 5 bytes for a potential CoD field */
4897 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004898 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004899
Johan Hedberg1dc06092012-01-15 21:01:23 +02004900 memset(buf, 0, sizeof(buf));
4901
Johan Hedberge319d2e2012-01-15 19:51:59 +02004902 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004903 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004904 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004905 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304906 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004907 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304908 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004909
Johan Hedberg1dc06092012-01-15 21:01:23 +02004910 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004911 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004912
Johan Hedberg1dc06092012-01-15 21:01:23 +02004913 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4914 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004915 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004916
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004917 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004918 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004919
Marcel Holtmann901801b2013-10-06 23:55:51 -07004920 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004921}
Johan Hedberga88a9652011-03-30 13:18:12 +03004922
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004923void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4924 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004925{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004926 struct mgmt_ev_device_found *ev;
4927 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4928 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004929
Johan Hedbergb644ba32012-01-17 21:48:47 +02004930 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004931
Johan Hedbergb644ba32012-01-17 21:48:47 +02004932 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004933
Johan Hedbergb644ba32012-01-17 21:48:47 +02004934 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004935 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004936 ev->rssi = rssi;
4937
4938 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004939 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004940
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004941 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004942
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004943 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004944}
Johan Hedberg314b2382011-04-27 10:29:57 -04004945
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004946void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004947{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004948 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004949 struct pending_cmd *cmd;
4950
Andre Guedes343fb142011-11-22 17:14:19 -03004951 BT_DBG("%s discovering %u", hdev->name, discovering);
4952
Johan Hedberg164a6e72011-11-01 17:06:44 +02004953 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004954 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004955 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004956 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004957
4958 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004959 u8 type = hdev->discovery.type;
4960
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004961 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4962 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004963 mgmt_pending_remove(cmd);
4964 }
4965
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004966 memset(&ev, 0, sizeof(ev));
4967 ev.type = hdev->discovery.type;
4968 ev.discovering = discovering;
4969
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004970 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004971}
Antti Julku5e762442011-08-25 16:48:02 +03004972
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004973int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004974{
4975 struct pending_cmd *cmd;
4976 struct mgmt_ev_device_blocked ev;
4977
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004978 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004979
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004980 bacpy(&ev.addr.bdaddr, bdaddr);
4981 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004982
Johan Hedberg744cf192011-11-08 20:40:14 +02004983 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004984 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004985}
4986
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004987int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004988{
4989 struct pending_cmd *cmd;
4990 struct mgmt_ev_device_unblocked ev;
4991
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004992 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004993
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004994 bacpy(&ev.addr.bdaddr, bdaddr);
4995 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004996
Johan Hedberg744cf192011-11-08 20:40:14 +02004997 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004998 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004999}
Marcel Holtmann5976e602013-10-06 04:08:14 -07005000
5001static void adv_enable_complete(struct hci_dev *hdev, u8 status)
5002{
5003 BT_DBG("%s status %u", hdev->name, status);
5004
5005 /* Clear the advertising mgmt setting if we failed to re-enable it */
5006 if (status) {
5007 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005008 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005009 }
5010}
5011
5012void mgmt_reenable_advertising(struct hci_dev *hdev)
5013{
5014 struct hci_request req;
5015
Marcel Holtmannb145edc2013-10-10 09:47:54 -07005016 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07005017 return;
5018
5019 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
5020 return;
5021
5022 hci_req_init(&req, hdev);
5023 enable_advertising(&req);
5024
5025 /* If this fails we have no option but to let user space know
5026 * that we've disabled advertising.
5027 */
5028 if (hci_req_run(&req, adv_enable_complete) < 0) {
5029 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07005030 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07005031 }
5032}