blob: 1d608ca0b0eefcc5d33b150a4f0146ce5eda79e3 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070033
34#include "smp.h"
Johan Hedberg03811012010-12-08 00:21:06 +020035
Johan Hedberg2da9c552012-02-17 14:39:28 +020036#define MGMT_VERSION 1
Marcel Holtmann9ab8cf32013-10-02 05:18:31 -070037#define MGMT_REVISION 4
Johan Hedberg02d98122010-12-13 21:07:04 +020038
Johan Hedberge70bb2e2012-02-13 16:59:33 +020039static const u16 mgmt_commands[] = {
40 MGMT_OP_READ_INDEX_LIST,
41 MGMT_OP_READ_INFO,
42 MGMT_OP_SET_POWERED,
43 MGMT_OP_SET_DISCOVERABLE,
44 MGMT_OP_SET_CONNECTABLE,
45 MGMT_OP_SET_FAST_CONNECTABLE,
46 MGMT_OP_SET_PAIRABLE,
47 MGMT_OP_SET_LINK_SECURITY,
48 MGMT_OP_SET_SSP,
49 MGMT_OP_SET_HS,
50 MGMT_OP_SET_LE,
51 MGMT_OP_SET_DEV_CLASS,
52 MGMT_OP_SET_LOCAL_NAME,
53 MGMT_OP_ADD_UUID,
54 MGMT_OP_REMOVE_UUID,
55 MGMT_OP_LOAD_LINK_KEYS,
56 MGMT_OP_LOAD_LONG_TERM_KEYS,
57 MGMT_OP_DISCONNECT,
58 MGMT_OP_GET_CONNECTIONS,
59 MGMT_OP_PIN_CODE_REPLY,
60 MGMT_OP_PIN_CODE_NEG_REPLY,
61 MGMT_OP_SET_IO_CAPABILITY,
62 MGMT_OP_PAIR_DEVICE,
63 MGMT_OP_CANCEL_PAIR_DEVICE,
64 MGMT_OP_UNPAIR_DEVICE,
65 MGMT_OP_USER_CONFIRM_REPLY,
66 MGMT_OP_USER_CONFIRM_NEG_REPLY,
67 MGMT_OP_USER_PASSKEY_REPLY,
68 MGMT_OP_USER_PASSKEY_NEG_REPLY,
69 MGMT_OP_READ_LOCAL_OOB_DATA,
70 MGMT_OP_ADD_REMOTE_OOB_DATA,
71 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
72 MGMT_OP_START_DISCOVERY,
73 MGMT_OP_STOP_DISCOVERY,
74 MGMT_OP_CONFIRM_NAME,
75 MGMT_OP_BLOCK_DEVICE,
76 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070077 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030078 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030079 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070080 MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann7f72134e2013-10-11 14:44:58 -070081 MGMT_OP_SET_SCAN_PARAMS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020082};
83
84static const u16 mgmt_events[] = {
85 MGMT_EV_CONTROLLER_ERROR,
86 MGMT_EV_INDEX_ADDED,
87 MGMT_EV_INDEX_REMOVED,
88 MGMT_EV_NEW_SETTINGS,
89 MGMT_EV_CLASS_OF_DEV_CHANGED,
90 MGMT_EV_LOCAL_NAME_CHANGED,
91 MGMT_EV_NEW_LINK_KEY,
92 MGMT_EV_NEW_LONG_TERM_KEY,
93 MGMT_EV_DEVICE_CONNECTED,
94 MGMT_EV_DEVICE_DISCONNECTED,
95 MGMT_EV_CONNECT_FAILED,
96 MGMT_EV_PIN_CODE_REQUEST,
97 MGMT_EV_USER_CONFIRM_REQUEST,
98 MGMT_EV_USER_PASSKEY_REQUEST,
99 MGMT_EV_AUTH_FAILED,
100 MGMT_EV_DEVICE_FOUND,
101 MGMT_EV_DISCOVERING,
102 MGMT_EV_DEVICE_BLOCKED,
103 MGMT_EV_DEVICE_UNBLOCKED,
104 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300105 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200106};
107
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800108#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200109
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200110#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
111 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
112
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200113struct pending_cmd {
114 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200115 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100117 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300119 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200120};
121
Johan Hedbergca69b792011-11-11 18:10:00 +0200122/* HCI to MGMT error code conversion table */
123static u8 mgmt_status_table[] = {
124 MGMT_STATUS_SUCCESS,
125 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
126 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
127 MGMT_STATUS_FAILED, /* Hardware Failure */
128 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
129 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
130 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
131 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
132 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
133 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
134 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
135 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
136 MGMT_STATUS_BUSY, /* Command Disallowed */
137 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
138 MGMT_STATUS_REJECTED, /* Rejected Security */
139 MGMT_STATUS_REJECTED, /* Rejected Personal */
140 MGMT_STATUS_TIMEOUT, /* Host Timeout */
141 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
142 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
143 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
144 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
145 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
146 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
147 MGMT_STATUS_BUSY, /* Repeated Attempts */
148 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
149 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
150 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
151 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
152 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
153 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
154 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
155 MGMT_STATUS_FAILED, /* Unspecified Error */
156 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
157 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
158 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
159 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
160 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
161 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
162 MGMT_STATUS_FAILED, /* Unit Link Key Used */
163 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
164 MGMT_STATUS_TIMEOUT, /* Instant Passed */
165 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
166 MGMT_STATUS_FAILED, /* Transaction Collision */
167 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
168 MGMT_STATUS_REJECTED, /* QoS Rejected */
169 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
170 MGMT_STATUS_REJECTED, /* Insufficient Security */
171 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
172 MGMT_STATUS_BUSY, /* Role Switch Pending */
173 MGMT_STATUS_FAILED, /* Slot Violation */
174 MGMT_STATUS_FAILED, /* Role Switch Failed */
175 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
176 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
177 MGMT_STATUS_BUSY, /* Host Busy Pairing */
178 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
179 MGMT_STATUS_BUSY, /* Controller Busy */
180 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
181 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
182 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
183 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
184 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
185};
186
187static u8 mgmt_status(u8 hci_status)
188{
189 if (hci_status < ARRAY_SIZE(mgmt_status_table))
190 return mgmt_status_table[hci_status];
191
192 return MGMT_STATUS_FAILED;
193}
194
Szymon Janc4e51eae2011-02-25 19:05:48 +0100195static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200196{
197 struct sk_buff *skb;
198 struct mgmt_hdr *hdr;
199 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300200 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200201
Szymon Janc34eb5252011-02-28 14:10:08 +0100202 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200203
Andre Guedes790eff42012-06-07 19:05:46 -0300204 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200205 if (!skb)
206 return -ENOMEM;
207
208 hdr = (void *) skb_put(skb, sizeof(*hdr));
209
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530210 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100211 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212 hdr->len = cpu_to_le16(sizeof(*ev));
213
214 ev = (void *) skb_put(skb, sizeof(*ev));
215 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200216 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200217
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300218 err = sock_queue_rcv_skb(sk, skb);
219 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200220 kfree_skb(skb);
221
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300222 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223}
224
Johan Hedbergaee9b212012-02-18 15:07:59 +0200225static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300226 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200227{
228 struct sk_buff *skb;
229 struct mgmt_hdr *hdr;
230 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300231 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200232
233 BT_DBG("sock %p", sk);
234
Andre Guedes790eff42012-06-07 19:05:46 -0300235 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200236 if (!skb)
237 return -ENOMEM;
238
239 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200240
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530241 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100242 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200243 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200244
Johan Hedberga38528f2011-01-22 06:46:43 +0200245 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200246 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200247 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100248
249 if (rp)
250 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300252 err = sock_queue_rcv_skb(sk, skb);
253 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200254 kfree_skb(skb);
255
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100256 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200257}
258
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300259static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
260 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200261{
262 struct mgmt_rp_read_version rp;
263
264 BT_DBG("sock %p", sk);
265
266 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200267 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200268
Johan Hedbergaee9b212012-02-18 15:07:59 +0200269 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300270 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200271}
272
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300273static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
274 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200275{
276 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200277 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
278 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200279 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200280 size_t rp_size;
281 int i, err;
282
283 BT_DBG("sock %p", sk);
284
285 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
286
287 rp = kmalloc(rp_size, GFP_KERNEL);
288 if (!rp)
289 return -ENOMEM;
290
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200291 rp->num_commands = __constant_cpu_to_le16(num_commands);
292 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200293
294 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
295 put_unaligned_le16(mgmt_commands[i], opcode);
296
297 for (i = 0; i < num_events; i++, opcode++)
298 put_unaligned_le16(mgmt_events[i], opcode);
299
Johan Hedbergaee9b212012-02-18 15:07:59 +0200300 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300301 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200302 kfree(rp);
303
304 return err;
305}
306
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300307static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
308 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200309{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200310 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200311 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200312 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300314 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315
316 BT_DBG("sock %p", sk);
317
318 read_lock(&hci_dev_list_lock);
319
320 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300321 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700322 if (d->dev_type == HCI_BREDR)
323 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324 }
325
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 rp_len = sizeof(*rp) + (2 * count);
327 rp = kmalloc(rp_len, GFP_ATOMIC);
328 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100329 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100331 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200332
Johan Hedberg476e44c2012-10-19 20:10:46 +0300333 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200334 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200335 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200336 continue;
337
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700338 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
339 continue;
340
Marcel Holtmann1514b892013-10-06 08:25:01 -0700341 if (d->dev_type == HCI_BREDR) {
342 rp->index[count++] = cpu_to_le16(d->id);
343 BT_DBG("Added hci%u", d->id);
344 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345 }
346
Johan Hedberg476e44c2012-10-19 20:10:46 +0300347 rp->num_controllers = cpu_to_le16(count);
348 rp_len = sizeof(*rp) + (2 * count);
349
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 read_unlock(&hci_dev_list_lock);
351
Johan Hedbergaee9b212012-02-18 15:07:59 +0200352 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300353 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354
Johan Hedberga38528f2011-01-22 06:46:43 +0200355 kfree(rp);
356
357 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200358}
359
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200360static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200361{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200366
Andre Guedesed3fa312012-07-24 15:03:46 -0300367 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300368 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500369 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
370 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300371 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 settings |= MGMT_SETTING_BREDR;
373 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmanna82974c2013-10-11 09:48:47 -0700374
375 if (lmp_ssp_capable(hdev)) {
376 settings |= MGMT_SETTING_SSP;
377 settings |= MGMT_SETTING_HS;
378 }
Marcel Holtmann848566b2013-10-01 22:59:22 -0700379 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300381 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200382 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300383 settings |= MGMT_SETTING_ADVERTISING;
384 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200385
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200386 return settings;
387}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200388
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389static u32 get_current_settings(struct hci_dev *hdev)
390{
391 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200392
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200393 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100394 settings |= MGMT_SETTING_POWERED;
395
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200396 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200397 settings |= MGMT_SETTING_CONNECTABLE;
398
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500399 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
400 settings |= MGMT_SETTING_FAST_CONNECTABLE;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_DISCOVERABLE;
404
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200405 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_PAIRABLE;
407
Johan Hedberg56f87902013-10-02 13:43:13 +0300408 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_BREDR;
410
Johan Hedberg06199cf2012-02-22 16:37:11 +0200411 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200413
Johan Hedberg47990ea2012-02-22 11:58:37 +0200414 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200416
Johan 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 Hedbergaee9b212012-02-18 15:07:59 +0200876 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300877 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200878}
879
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200880static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300881 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200882{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300883 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200884 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200885 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200886
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200887 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200888
Johan Hedberga7e80f22013-01-09 16:05:19 +0200889 if (cp->val != 0x00 && cp->val != 0x01)
890 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
891 MGMT_STATUS_INVALID_PARAMS);
892
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300893 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200894
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300895 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
896 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
897 MGMT_STATUS_BUSY);
898 goto failed;
899 }
900
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100901 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
902 cancel_delayed_work(&hdev->power_off);
903
904 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200905 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
906 data, len);
907 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100908 goto failed;
909 }
910 }
911
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200912 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200913 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200914 goto failed;
915 }
916
Johan Hedberg03811012010-12-08 00:21:06 +0200917 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
918 if (!cmd) {
919 err = -ENOMEM;
920 goto failed;
921 }
922
923 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200924 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200925 else
Johan Hedberg19202572013-01-14 22:33:51 +0200926 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200927
928 err = 0;
929
930failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300931 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200932 return err;
933}
934
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300935static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
936 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200937{
938 struct sk_buff *skb;
939 struct mgmt_hdr *hdr;
940
Andre Guedes790eff42012-06-07 19:05:46 -0300941 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200942 if (!skb)
943 return -ENOMEM;
944
945 hdr = (void *) skb_put(skb, sizeof(*hdr));
946 hdr->opcode = cpu_to_le16(event);
947 if (hdev)
948 hdr->index = cpu_to_le16(hdev->id);
949 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530950 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200951 hdr->len = cpu_to_le16(data_len);
952
953 if (data)
954 memcpy(skb_put(skb, data_len), data, data_len);
955
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100956 /* Time stamp */
957 __net_timestamp(skb);
958
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200959 hci_send_to_control(skb, skip_sk);
960 kfree_skb(skb);
961
962 return 0;
963}
964
965static int new_settings(struct hci_dev *hdev, struct sock *skip)
966{
967 __le32 ev;
968
969 ev = cpu_to_le32(get_current_settings(hdev));
970
971 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
972}
973
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300974struct cmd_lookup {
975 struct sock *sk;
976 struct hci_dev *hdev;
977 u8 mgmt_status;
978};
979
980static void settings_rsp(struct pending_cmd *cmd, void *data)
981{
982 struct cmd_lookup *match = data;
983
984 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
985
986 list_del(&cmd->list);
987
988 if (match->sk == NULL) {
989 match->sk = cmd->sk;
990 sock_hold(match->sk);
991 }
992
993 mgmt_pending_free(cmd);
994}
995
996static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
997{
998 u8 *status = data;
999
1000 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
1001 mgmt_pending_remove(cmd);
1002}
1003
Johan Hedberge6fe7982013-10-02 15:45:22 +03001004static u8 mgmt_bredr_support(struct hci_dev *hdev)
1005{
1006 if (!lmp_bredr_capable(hdev))
1007 return MGMT_STATUS_NOT_SUPPORTED;
1008 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
1009 return MGMT_STATUS_REJECTED;
1010 else
1011 return MGMT_STATUS_SUCCESS;
1012}
1013
1014static u8 mgmt_le_support(struct hci_dev *hdev)
1015{
1016 if (!lmp_le_capable(hdev))
1017 return MGMT_STATUS_NOT_SUPPORTED;
1018 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
1019 return MGMT_STATUS_REJECTED;
1020 else
1021 return MGMT_STATUS_SUCCESS;
1022}
1023
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001024static void set_discoverable_complete(struct hci_dev *hdev, u8 status)
1025{
1026 struct pending_cmd *cmd;
1027 struct mgmt_mode *cp;
Marcel Holtmann970ba522013-10-15 06:33:57 -07001028 struct hci_request req;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001029 bool changed;
1030
1031 BT_DBG("status 0x%02x", status);
1032
1033 hci_dev_lock(hdev);
1034
1035 cmd = mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev);
1036 if (!cmd)
1037 goto unlock;
1038
1039 if (status) {
1040 u8 mgmt_err = mgmt_status(status);
1041 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1042 goto remove_cmd;
1043 }
1044
1045 cp = cmd->param;
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001046 if (cp->val) {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001047 changed = !test_and_set_bit(HCI_DISCOVERABLE,
1048 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001049
1050 if (hdev->discov_timeout > 0) {
1051 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
1052 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1053 to);
1054 }
1055 } else {
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001056 changed = test_and_clear_bit(HCI_DISCOVERABLE,
1057 &hdev->dev_flags);
Marcel Holtmannd4462a02013-10-15 08:11:02 -07001058 }
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001059
1060 send_settings_rsp(cmd->sk, MGMT_OP_SET_DISCOVERABLE, hdev);
1061
1062 if (changed)
1063 new_settings(hdev, cmd->sk);
1064
Marcel Holtmann970ba522013-10-15 06:33:57 -07001065 /* When the discoverable mode gets changed, make sure
1066 * that class of device has the limited discoverable
1067 * bit correctly set.
1068 */
1069 hci_req_init(&req, hdev);
1070 update_class(&req);
1071 hci_req_run(&req, NULL);
1072
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001073remove_cmd:
1074 mgmt_pending_remove(cmd);
1075
1076unlock:
1077 hci_dev_unlock(hdev);
1078}
1079
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001080static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001081 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001082{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001083 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001084 struct pending_cmd *cmd;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001085 struct hci_request req;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001086 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001087 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001088 int err;
1089
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001090 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +02001091
Johan Hedberge6fe7982013-10-02 15:45:22 +03001092 status = mgmt_bredr_support(hdev);
1093 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001094 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001095 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001096
Johan Hedberga7e80f22013-01-09 16:05:19 +02001097 if (cp->val != 0x00 && cp->val != 0x01)
1098 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
1099 MGMT_STATUS_INVALID_PARAMS);
1100
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001101 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +01001102 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001103 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001104 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001105
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001106 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001107
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001108 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001109 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001110 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001111 goto failed;
1112 }
1113
1114 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001115 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001116 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001117 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001118 goto failed;
1119 }
1120
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001121 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
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_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001124 goto failed;
1125 }
1126
1127 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001128 bool changed = false;
1129
1130 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
1131 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1132 changed = true;
1133 }
1134
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001135 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001136 if (err < 0)
1137 goto failed;
1138
1139 if (changed)
1140 err = new_settings(hdev, sk);
1141
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001142 goto failed;
1143 }
1144
1145 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann36261542013-10-15 08:28:51 -07001146 cancel_delayed_work(&hdev->discov_off);
1147 hdev->discov_timeout = timeout;
Marcel Holtmann955638e2012-02-22 18:21:00 +01001148
Marcel Holtmann36261542013-10-15 08:28:51 -07001149 if (cp->val && hdev->discov_timeout > 0) {
1150 int to = msecs_to_jiffies(hdev->discov_timeout * 1000);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001151 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
Marcel Holtmann36261542013-10-15 08:28:51 -07001152 to);
Marcel Holtmann955638e2012-02-22 18:21:00 +01001153 }
1154
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001155 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001156 goto failed;
1157 }
1158
1159 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1160 if (!cmd) {
1161 err = -ENOMEM;
1162 goto failed;
1163 }
1164
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001165 hci_req_init(&req, hdev);
1166
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001167 scan = SCAN_PAGE;
1168
1169 if (cp->val)
1170 scan |= SCAN_INQUIRY;
1171 else
1172 cancel_delayed_work(&hdev->discov_off);
1173
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03001174 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1175
1176 err = hci_req_run(&req, set_discoverable_complete);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001177 if (err < 0)
1178 mgmt_pending_remove(cmd);
1179
1180 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001181 hdev->discov_timeout = timeout;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001182
1183failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001184 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001185 return err;
1186}
1187
Johan Hedberg406d7802013-03-15 17:07:09 -05001188static void write_fast_connectable(struct hci_request *req, bool enable)
1189{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001190 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001191 struct hci_cp_write_page_scan_activity acp;
1192 u8 type;
1193
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001194 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1195 return;
1196
Johan Hedberg406d7802013-03-15 17:07:09 -05001197 if (enable) {
1198 type = PAGE_SCAN_TYPE_INTERLACED;
1199
1200 /* 160 msec page scan interval */
1201 acp.interval = __constant_cpu_to_le16(0x0100);
1202 } else {
1203 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1204
1205 /* default 1.28 sec page scan */
1206 acp.interval = __constant_cpu_to_le16(0x0800);
1207 }
1208
1209 acp.window = __constant_cpu_to_le16(0x0012);
1210
Johan Hedbergbd98b992013-03-15 17:07:13 -05001211 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1212 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1213 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1214 sizeof(acp), &acp);
1215
1216 if (hdev->page_scan_type != type)
1217 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001218}
1219
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001220static u8 get_adv_type(struct hci_dev *hdev)
1221{
1222 struct pending_cmd *cmd;
1223 bool connectable;
1224
1225 /* If there's a pending mgmt command the flag will not yet have
1226 * it's final value, so check for this first.
1227 */
1228 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1229 if (cmd) {
1230 struct mgmt_mode *cp = cmd->param;
1231 connectable = !!cp->val;
1232 } else {
1233 connectable = test_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1234 }
1235
1236 return connectable ? LE_ADV_IND : LE_ADV_NONCONN_IND;
1237}
1238
Johan Hedberg95c66e72013-10-14 16:20:06 +03001239static void enable_advertising(struct hci_request *req)
1240{
1241 struct hci_dev *hdev = req->hdev;
1242 struct hci_cp_le_set_adv_param cp;
1243 u8 enable = 0x01;
1244
1245 memset(&cp, 0, sizeof(cp));
1246 cp.min_interval = __constant_cpu_to_le16(0x0800);
1247 cp.max_interval = __constant_cpu_to_le16(0x0800);
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001248 cp.type = get_adv_type(hdev);
Johan Hedberg95c66e72013-10-14 16:20:06 +03001249 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1250 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1251 else
1252 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1253 cp.channel_map = 0x07;
1254
1255 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1256
1257 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1258}
1259
1260static void disable_advertising(struct hci_request *req)
1261{
1262 u8 enable = 0x00;
1263
1264 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
1265}
1266
Johan Hedberg2b76f452013-03-15 17:07:04 -05001267static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1268{
1269 struct pending_cmd *cmd;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001270 struct mgmt_mode *cp;
1271 bool changed;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001272
1273 BT_DBG("status 0x%02x", status);
1274
1275 hci_dev_lock(hdev);
1276
1277 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1278 if (!cmd)
1279 goto unlock;
1280
Johan Hedberg37438c12013-10-14 16:20:05 +03001281 if (status) {
1282 u8 mgmt_err = mgmt_status(status);
1283 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
1284 goto remove_cmd;
1285 }
1286
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001287 cp = cmd->param;
1288 if (cp->val)
1289 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1290 else
1291 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1292
Johan Hedberg2b76f452013-03-15 17:07:04 -05001293 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1294
Johan Hedbergd7b856f2013-10-14 16:20:04 +03001295 if (changed)
1296 new_settings(hdev, cmd->sk);
1297
Johan Hedberg37438c12013-10-14 16:20:05 +03001298remove_cmd:
Johan Hedberg2b76f452013-03-15 17:07:04 -05001299 mgmt_pending_remove(cmd);
1300
1301unlock:
1302 hci_dev_unlock(hdev);
1303}
1304
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001305static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001306 u16 len)
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001307{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001308 struct mgmt_mode *cp = data;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001309 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001310 struct hci_request req;
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001311 u8 scan;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001312 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02001313
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001314 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001315
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001316 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
1317 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg33c525c2012-10-24 21:11:58 +03001318 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001319 MGMT_STATUS_REJECTED);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001320
Johan Hedberga7e80f22013-01-09 16:05:19 +02001321 if (cp->val != 0x00 && cp->val != 0x01)
1322 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1323 MGMT_STATUS_INVALID_PARAMS);
1324
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001325 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001326
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001327 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001328 bool changed = false;
1329
1330 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1331 changed = true;
1332
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001333 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001334 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001335 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001336 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1337 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1338 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001339
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001340 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001341 if (err < 0)
1342 goto failed;
1343
1344 if (changed)
1345 err = new_settings(hdev, sk);
1346
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001347 goto failed;
1348 }
1349
1350 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001351 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001352 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001353 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001354 goto failed;
1355 }
1356
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001357 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1358 if (!cmd) {
1359 err = -ENOMEM;
1360 goto failed;
1361 }
1362
Johan Hedberg2b76f452013-03-15 17:07:04 -05001363 hci_req_init(&req, hdev);
1364
Johan Hedberg9b742462013-10-14 16:20:03 +03001365 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) &&
1366 cp->val != test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg9b742462013-10-14 16:20:03 +03001367 if (cp->val) {
1368 scan = SCAN_PAGE;
1369 } else {
1370 scan = 0;
1371
1372 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Marcel Holtmann8d6083f2013-10-14 16:38:45 -07001373 hdev->discov_timeout > 0)
Johan Hedberg9b742462013-10-14 16:20:03 +03001374 cancel_delayed_work(&hdev->discov_off);
1375 }
1376
1377 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1378 }
Johan Hedberg2b76f452013-03-15 17:07:04 -05001379
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001380 /* If we're going from non-connectable to connectable or
1381 * vice-versa when fast connectable is enabled ensure that fast
1382 * connectable gets disabled. write_fast_connectable won't do
1383 * anything if the page scan parameters are already what they
1384 * should be.
1385 */
1386 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001387 write_fast_connectable(&req, false);
1388
Johan Hedberg1987fdc2013-10-14 21:15:24 +03001389 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) &&
1390 hci_conn_num(hdev, LE_LINK) == 0) {
1391 disable_advertising(&req);
1392 enable_advertising(&req);
1393 }
1394
Johan Hedberg2b76f452013-03-15 17:07:04 -05001395 err = hci_req_run(&req, set_connectable_complete);
Johan Hedberg9b742462013-10-14 16:20:03 +03001396 if (err < 0) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001397 mgmt_pending_remove(cmd);
Johan Hedberg9b742462013-10-14 16:20:03 +03001398 if (err == -ENODATA)
1399 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE,
1400 hdev);
1401 goto failed;
1402 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001403
1404failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001405 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001406 return err;
1407}
1408
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001409static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001410 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001411{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001412 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001413 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001414 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001415
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001416 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001417
Johan Hedberga7e80f22013-01-09 16:05:19 +02001418 if (cp->val != 0x00 && cp->val != 0x01)
1419 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1420 MGMT_STATUS_INVALID_PARAMS);
1421
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001422 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001423
1424 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001425 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001426 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001427 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001428
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001429 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001430 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001431 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001432
Marcel Holtmann55594352013-10-06 16:11:57 -07001433 if (changed)
1434 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001435
Marcel Holtmann55594352013-10-06 16:11:57 -07001436unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001437 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001438 return err;
1439}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001440
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001441static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1442 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001443{
1444 struct mgmt_mode *cp = data;
1445 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001446 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001447 int err;
1448
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001449 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001450
Johan Hedberge6fe7982013-10-02 15:45:22 +03001451 status = mgmt_bredr_support(hdev);
1452 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001453 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001454 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001455
Johan Hedberga7e80f22013-01-09 16:05:19 +02001456 if (cp->val != 0x00 && cp->val != 0x01)
1457 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1458 MGMT_STATUS_INVALID_PARAMS);
1459
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001460 hci_dev_lock(hdev);
1461
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001462 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001463 bool changed = false;
1464
1465 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001466 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001467 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1468 changed = true;
1469 }
1470
1471 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1472 if (err < 0)
1473 goto failed;
1474
1475 if (changed)
1476 err = new_settings(hdev, sk);
1477
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001478 goto failed;
1479 }
1480
1481 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001482 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001483 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001484 goto failed;
1485 }
1486
1487 val = !!cp->val;
1488
1489 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1490 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1491 goto failed;
1492 }
1493
1494 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1495 if (!cmd) {
1496 err = -ENOMEM;
1497 goto failed;
1498 }
1499
1500 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1501 if (err < 0) {
1502 mgmt_pending_remove(cmd);
1503 goto failed;
1504 }
1505
1506failed:
1507 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001508 return err;
1509}
1510
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001511static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001512{
1513 struct mgmt_mode *cp = data;
1514 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001515 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001516 int err;
1517
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001518 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001519
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001520 status = mgmt_bredr_support(hdev);
1521 if (status)
1522 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1523
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001524 if (!lmp_ssp_capable(hdev))
1525 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1526 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001527
Johan Hedberga7e80f22013-01-09 16:05:19 +02001528 if (cp->val != 0x00 && cp->val != 0x01)
1529 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1530 MGMT_STATUS_INVALID_PARAMS);
1531
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001532 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001533
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001534 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001535 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001536
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001537 if (cp->val) {
1538 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1539 &hdev->dev_flags);
1540 } else {
1541 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1542 &hdev->dev_flags);
1543 if (!changed)
1544 changed = test_and_clear_bit(HCI_HS_ENABLED,
1545 &hdev->dev_flags);
1546 else
1547 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001548 }
1549
1550 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1551 if (err < 0)
1552 goto failed;
1553
1554 if (changed)
1555 err = new_settings(hdev, sk);
1556
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001557 goto failed;
1558 }
1559
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001560 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1561 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001562 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1563 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001564 goto failed;
1565 }
1566
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001567 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001568 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1569 goto failed;
1570 }
1571
1572 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1573 if (!cmd) {
1574 err = -ENOMEM;
1575 goto failed;
1576 }
1577
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001578 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001579 if (err < 0) {
1580 mgmt_pending_remove(cmd);
1581 goto failed;
1582 }
1583
1584failed:
1585 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001586 return err;
1587}
1588
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001589static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001590{
1591 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001592 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001593 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001594 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001595
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001596 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001597
Johan Hedberge6fe7982013-10-02 15:45:22 +03001598 status = mgmt_bredr_support(hdev);
1599 if (status)
1600 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001601
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001602 if (!lmp_ssp_capable(hdev))
1603 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1604 MGMT_STATUS_NOT_SUPPORTED);
1605
1606 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1607 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1608 MGMT_STATUS_REJECTED);
1609
Johan Hedberga7e80f22013-01-09 16:05:19 +02001610 if (cp->val != 0x00 && cp->val != 0x01)
1611 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1612 MGMT_STATUS_INVALID_PARAMS);
1613
Marcel Holtmannee392692013-10-01 22:59:23 -07001614 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001615
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001616 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001617 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001618 } else {
1619 if (hdev_is_powered(hdev)) {
1620 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1621 MGMT_STATUS_REJECTED);
1622 goto unlock;
1623 }
1624
Marcel Holtmannee392692013-10-01 22:59:23 -07001625 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001626 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001627
1628 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1629 if (err < 0)
1630 goto unlock;
1631
1632 if (changed)
1633 err = new_settings(hdev, sk);
1634
1635unlock:
1636 hci_dev_unlock(hdev);
1637 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001638}
1639
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001640static void le_enable_complete(struct hci_dev *hdev, u8 status)
1641{
1642 struct cmd_lookup match = { NULL, hdev };
1643
1644 if (status) {
1645 u8 mgmt_err = mgmt_status(status);
1646
1647 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1648 &mgmt_err);
1649 return;
1650 }
1651
1652 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1653
1654 new_settings(hdev, match.sk);
1655
1656 if (match.sk)
1657 sock_put(match.sk);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001658
1659 /* Make sure the controller has a good default for
1660 * advertising data. Restrict the update to when LE
1661 * has actually been enabled. During power on, the
1662 * update in powered_update_hci will take care of it.
1663 */
1664 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1665 struct hci_request req;
1666
1667 hci_dev_lock(hdev);
1668
1669 hci_req_init(&req, hdev);
1670 update_ad(&req);
1671 hci_req_run(&req, NULL);
1672
1673 hci_dev_unlock(hdev);
1674 }
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001675}
1676
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001677static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001678{
1679 struct mgmt_mode *cp = data;
1680 struct hci_cp_write_le_host_supported hci_cp;
1681 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001682 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001683 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001684 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001685
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001686 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001687
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001688 if (!lmp_le_capable(hdev))
1689 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1690 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001691
Johan Hedberga7e80f22013-01-09 16:05:19 +02001692 if (cp->val != 0x00 && cp->val != 0x01)
1693 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1694 MGMT_STATUS_INVALID_PARAMS);
1695
Johan Hedbergc73eee92013-04-19 18:35:21 +03001696 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001697 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001698 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1699 MGMT_STATUS_REJECTED);
1700
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001701 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001702
1703 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001704 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001705
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001706 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001707 bool changed = false;
1708
1709 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1710 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1711 changed = true;
1712 }
1713
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001714 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1715 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001716 changed = true;
1717 }
1718
Johan Hedberg06199cf2012-02-22 16:37:11 +02001719 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1720 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001721 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001722
1723 if (changed)
1724 err = new_settings(hdev, sk);
1725
Johan Hedberg1de028c2012-02-29 19:55:35 -08001726 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001727 }
1728
Johan Hedberg4375f102013-09-25 13:26:10 +03001729 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1730 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001731 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001732 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001733 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001734 }
1735
1736 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1737 if (!cmd) {
1738 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001739 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001740 }
1741
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001742 hci_req_init(&req, hdev);
1743
Johan Hedberg06199cf2012-02-22 16:37:11 +02001744 memset(&hci_cp, 0, sizeof(hci_cp));
1745
1746 if (val) {
1747 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001748 hci_cp.simul = lmp_le_br_capable(hdev);
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07001749 } else {
1750 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
1751 disable_advertising(&req);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001752 }
1753
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001754 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1755 &hci_cp);
1756
1757 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301758 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001759 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001760
Johan Hedberg1de028c2012-02-29 19:55:35 -08001761unlock:
1762 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001763 return err;
1764}
1765
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001766/* This is a helper function to test for pending mgmt commands that can
1767 * cause CoD or EIR HCI commands. We can only allow one such pending
1768 * mgmt command at a time since otherwise we cannot easily track what
1769 * the current values are, will be, and based on that calculate if a new
1770 * HCI command needs to be sent and if yes with what value.
1771 */
1772static bool pending_eir_or_class(struct hci_dev *hdev)
1773{
1774 struct pending_cmd *cmd;
1775
1776 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1777 switch (cmd->opcode) {
1778 case MGMT_OP_ADD_UUID:
1779 case MGMT_OP_REMOVE_UUID:
1780 case MGMT_OP_SET_DEV_CLASS:
1781 case MGMT_OP_SET_POWERED:
1782 return true;
1783 }
1784 }
1785
1786 return false;
1787}
1788
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001789static const u8 bluetooth_base_uuid[] = {
1790 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1791 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1792};
1793
1794static u8 get_uuid_size(const u8 *uuid)
1795{
1796 u32 val;
1797
1798 if (memcmp(uuid, bluetooth_base_uuid, 12))
1799 return 128;
1800
1801 val = get_unaligned_le32(&uuid[12]);
1802 if (val > 0xffff)
1803 return 32;
1804
1805 return 16;
1806}
1807
Johan Hedberg92da6092013-03-15 17:06:55 -05001808static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1809{
1810 struct pending_cmd *cmd;
1811
1812 hci_dev_lock(hdev);
1813
1814 cmd = mgmt_pending_find(mgmt_op, hdev);
1815 if (!cmd)
1816 goto unlock;
1817
1818 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1819 hdev->dev_class, 3);
1820
1821 mgmt_pending_remove(cmd);
1822
1823unlock:
1824 hci_dev_unlock(hdev);
1825}
1826
1827static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1828{
1829 BT_DBG("status 0x%02x", status);
1830
1831 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1832}
1833
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001834static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001835{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001836 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001837 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001838 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001839 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001840 int err;
1841
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001842 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001843
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001844 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001845
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001846 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001847 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001848 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001849 goto failed;
1850 }
1851
Andre Guedes92c4c202012-06-07 19:05:44 -03001852 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001853 if (!uuid) {
1854 err = -ENOMEM;
1855 goto failed;
1856 }
1857
1858 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001859 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001860 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001861
Johan Hedbergde66aa62013-01-27 00:31:27 +02001862 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001863
Johan Hedberg890ea892013-03-15 17:06:52 -05001864 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001865
Johan Hedberg890ea892013-03-15 17:06:52 -05001866 update_class(&req);
1867 update_eir(&req);
1868
Johan Hedberg92da6092013-03-15 17:06:55 -05001869 err = hci_req_run(&req, add_uuid_complete);
1870 if (err < 0) {
1871 if (err != -ENODATA)
1872 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001873
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001874 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001875 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001876 goto failed;
1877 }
1878
1879 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001880 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001881 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001882 goto failed;
1883 }
1884
1885 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001886
1887failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001888 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001889 return err;
1890}
1891
Johan Hedberg24b78d02012-02-23 23:24:30 +02001892static bool enable_service_cache(struct hci_dev *hdev)
1893{
1894 if (!hdev_is_powered(hdev))
1895 return false;
1896
1897 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001898 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1899 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001900 return true;
1901 }
1902
1903 return false;
1904}
1905
Johan Hedberg92da6092013-03-15 17:06:55 -05001906static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1907{
1908 BT_DBG("status 0x%02x", status);
1909
1910 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1911}
1912
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001913static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001914 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001915{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001916 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001917 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001918 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001919 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 -05001920 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001921 int err, found;
1922
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001923 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001924
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001925 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001926
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001927 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001928 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001929 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001930 goto unlock;
1931 }
1932
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001933 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1934 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001935
Johan Hedberg24b78d02012-02-23 23:24:30 +02001936 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001937 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001938 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001939 goto unlock;
1940 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001941
Johan Hedberg9246a862012-02-23 21:33:16 +02001942 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001943 }
1944
1945 found = 0;
1946
Johan Hedberg056341c2013-01-27 00:31:30 +02001947 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001948 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1949 continue;
1950
1951 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001952 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001953 found++;
1954 }
1955
1956 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001957 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001958 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001959 goto unlock;
1960 }
1961
Johan Hedberg9246a862012-02-23 21:33:16 +02001962update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001963 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001964
Johan Hedberg890ea892013-03-15 17:06:52 -05001965 update_class(&req);
1966 update_eir(&req);
1967
Johan Hedberg92da6092013-03-15 17:06:55 -05001968 err = hci_req_run(&req, remove_uuid_complete);
1969 if (err < 0) {
1970 if (err != -ENODATA)
1971 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001972
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001973 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001974 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001975 goto unlock;
1976 }
1977
1978 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001979 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001980 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001981 goto unlock;
1982 }
1983
1984 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001985
1986unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001987 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001988 return err;
1989}
1990
Johan Hedberg92da6092013-03-15 17:06:55 -05001991static void set_class_complete(struct hci_dev *hdev, u8 status)
1992{
1993 BT_DBG("status 0x%02x", status);
1994
1995 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1996}
1997
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001998static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001999 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002000{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002001 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02002002 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002003 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002004 int err;
2005
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002006 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002007
Marcel Holtmann6203fc92013-10-02 23:37:29 -07002008 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02002009 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2010 MGMT_STATUS_NOT_SUPPORTED);
2011
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002012 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002013
Johan Hedberg0cab9c82013-03-15 17:06:54 -05002014 if (pending_eir_or_class(hdev)) {
2015 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2016 MGMT_STATUS_BUSY);
2017 goto unlock;
2018 }
2019
2020 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
2021 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
2022 MGMT_STATUS_INVALID_PARAMS);
2023 goto unlock;
2024 }
2025
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002026 hdev->major_class = cp->major;
2027 hdev->minor_class = cp->minor;
2028
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002029 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002030 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002031 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02002032 goto unlock;
2033 }
2034
Johan Hedberg890ea892013-03-15 17:06:52 -05002035 hci_req_init(&req, hdev);
2036
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002037 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02002038 hci_dev_unlock(hdev);
2039 cancel_delayed_work_sync(&hdev->service_cache);
2040 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05002041 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02002042 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02002043
Johan Hedberg890ea892013-03-15 17:06:52 -05002044 update_class(&req);
2045
Johan Hedberg92da6092013-03-15 17:06:55 -05002046 err = hci_req_run(&req, set_class_complete);
2047 if (err < 0) {
2048 if (err != -ENODATA)
2049 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002050
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002051 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002052 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02002053 goto unlock;
2054 }
2055
2056 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05002057 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02002058 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05002059 goto unlock;
2060 }
2061
2062 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002063
Johan Hedbergb5235a62012-02-21 14:32:24 +02002064unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002065 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002066 return err;
2067}
2068
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002069static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002070 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002071{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002072 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002073 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002074 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002075
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07002076 BT_DBG("request for %s", hdev->name);
2077
2078 if (!lmp_bredr_capable(hdev))
2079 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2080 MGMT_STATUS_NOT_SUPPORTED);
2081
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002082 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002083
Johan Hedberg86742e12011-11-07 23:13:38 +02002084 expected_len = sizeof(*cp) + key_count *
2085 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002086 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002087 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002088 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002089 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002090 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002091 }
2092
Johan Hedberg4ae14302013-01-20 14:27:13 +02002093 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
2094 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2095 MGMT_STATUS_INVALID_PARAMS);
2096
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002097 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002098 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002099
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002100 for (i = 0; i < key_count; i++) {
2101 struct mgmt_link_key_info *key = &cp->keys[i];
2102
2103 if (key->addr.type != BDADDR_BREDR)
2104 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
2105 MGMT_STATUS_INVALID_PARAMS);
2106 }
2107
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002108 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002109
2110 hci_link_keys_clear(hdev);
2111
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002112 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002113 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002114 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02002115 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002116
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002117 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02002118 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002119
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002120 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002121 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002122 }
2123
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002124 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02002125
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002126 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002127
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002128 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002129}
2130
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002131static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002132 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002133{
2134 struct mgmt_ev_device_unpaired ev;
2135
2136 bacpy(&ev.addr.bdaddr, bdaddr);
2137 ev.addr.type = addr_type;
2138
2139 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002140 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002141}
2142
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002143static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002144 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002145{
Johan Hedberg124f6e32012-02-09 13:50:12 +02002146 struct mgmt_cp_unpair_device *cp = data;
2147 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002148 struct hci_cp_disconnect dc;
2149 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002150 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002151 int err;
2152
Johan Hedberga8a1d192011-11-10 15:54:38 +02002153 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002154 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2155 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002156
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002157 if (!bdaddr_type_is_valid(cp->addr.type))
2158 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2159 MGMT_STATUS_INVALID_PARAMS,
2160 &rp, sizeof(rp));
2161
Johan Hedberg118da702013-01-20 14:27:20 +02002162 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
2163 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
2164 MGMT_STATUS_INVALID_PARAMS,
2165 &rp, sizeof(rp));
2166
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002167 hci_dev_lock(hdev);
2168
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002169 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002170 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002171 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002172 goto unlock;
2173 }
2174
Andre Guedes591f47f2012-04-24 21:02:49 -03002175 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02002176 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
2177 else
2178 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03002179
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002180 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002181 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002182 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002183 goto unlock;
2184 }
2185
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002186 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03002187 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002188 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002189 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002190 else
2191 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002192 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02002193 } else {
2194 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002195 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002196
Johan Hedberga8a1d192011-11-10 15:54:38 +02002197 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002198 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002199 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002200 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002201 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002202 }
2203
Johan Hedberg124f6e32012-02-09 13:50:12 +02002204 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002205 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002206 if (!cmd) {
2207 err = -ENOMEM;
2208 goto unlock;
2209 }
2210
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002211 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002212 dc.reason = 0x13; /* Remote User Terminated Connection */
2213 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2214 if (err < 0)
2215 mgmt_pending_remove(cmd);
2216
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002217unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002218 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002219 return err;
2220}
2221
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002222static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002223 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002224{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002225 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002226 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002227 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002228 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002229 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002230 int err;
2231
2232 BT_DBG("");
2233
Johan Hedberg06a63b12013-01-20 14:27:21 +02002234 memset(&rp, 0, sizeof(rp));
2235 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2236 rp.addr.type = cp->addr.type;
2237
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002238 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002239 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2240 MGMT_STATUS_INVALID_PARAMS,
2241 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002242
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002243 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002244
2245 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002246 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2247 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002248 goto failed;
2249 }
2250
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002251 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002252 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2253 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002254 goto failed;
2255 }
2256
Andre Guedes591f47f2012-04-24 21:02:49 -03002257 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002258 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2259 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002260 else
2261 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002262
Vishal Agarwalf9607272012-06-13 05:32:43 +05302263 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002264 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2265 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002266 goto failed;
2267 }
2268
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002269 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002270 if (!cmd) {
2271 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002272 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002273 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002274
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002275 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002276 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002277
2278 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2279 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002280 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002281
2282failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002283 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002284 return err;
2285}
2286
Andre Guedes57c14772012-04-24 21:02:50 -03002287static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002288{
2289 switch (link_type) {
2290 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002291 switch (addr_type) {
2292 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002293 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002294
Johan Hedberg48264f02011-11-09 13:58:58 +02002295 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002296 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002297 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002298 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002299
Johan Hedberg4c659c32011-11-07 23:13:39 +02002300 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002301 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002302 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002303 }
2304}
2305
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002306static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2307 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002308{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002309 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002310 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002311 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002312 int err;
2313 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002314
2315 BT_DBG("");
2316
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002317 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002318
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002319 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002320 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002321 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002322 goto unlock;
2323 }
2324
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002325 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002326 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2327 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002328 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002329 }
2330
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002331 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002332 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002333 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002334 err = -ENOMEM;
2335 goto unlock;
2336 }
2337
Johan Hedberg2784eb42011-01-21 13:56:35 +02002338 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002339 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002340 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2341 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002342 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002343 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002344 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002345 continue;
2346 i++;
2347 }
2348
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002349 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002350
Johan Hedberg4c659c32011-11-07 23:13:39 +02002351 /* Recalculate length in case of filtered SCO connections, etc */
2352 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002353
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002354 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002355 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002356
Johan Hedberga38528f2011-01-22 06:46:43 +02002357 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002358
2359unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002360 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002361 return err;
2362}
2363
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002364static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002365 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002366{
2367 struct pending_cmd *cmd;
2368 int err;
2369
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002370 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002371 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002372 if (!cmd)
2373 return -ENOMEM;
2374
Johan Hedbergd8457692012-02-17 14:24:57 +02002375 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002376 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002377 if (err < 0)
2378 mgmt_pending_remove(cmd);
2379
2380 return err;
2381}
2382
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002383static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002384 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002385{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002386 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002387 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002388 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002389 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002390 int err;
2391
2392 BT_DBG("");
2393
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002394 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002395
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002396 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002397 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002398 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002399 goto failed;
2400 }
2401
Johan Hedbergd8457692012-02-17 14:24:57 +02002402 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002403 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002404 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002405 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002406 goto failed;
2407 }
2408
2409 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002410 struct mgmt_cp_pin_code_neg_reply ncp;
2411
2412 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002413
2414 BT_ERR("PIN code is not 16 bytes long");
2415
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002416 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002417 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002418 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002419 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002420
2421 goto failed;
2422 }
2423
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002424 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002425 if (!cmd) {
2426 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002427 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002428 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002429
Johan Hedbergd8457692012-02-17 14:24:57 +02002430 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002431 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002432 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002433
2434 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2435 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002436 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002437
2438failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002439 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002440 return err;
2441}
2442
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002443static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2444 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002445{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002446 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002447
2448 BT_DBG("");
2449
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002450 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002451
2452 hdev->io_capability = cp->io_capability;
2453
2454 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002455 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002456
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002457 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002458
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002459 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2460 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002461}
2462
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002463static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002464{
2465 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002466 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002467
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002468 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002469 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2470 continue;
2471
Johan Hedberge9a416b2011-02-19 12:05:56 -03002472 if (cmd->user_data != conn)
2473 continue;
2474
2475 return cmd;
2476 }
2477
2478 return NULL;
2479}
2480
2481static void pairing_complete(struct pending_cmd *cmd, u8 status)
2482{
2483 struct mgmt_rp_pair_device rp;
2484 struct hci_conn *conn = cmd->user_data;
2485
Johan Hedbergba4e5642011-11-11 00:07:34 +02002486 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002487 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002488
Johan Hedbergaee9b212012-02-18 15:07:59 +02002489 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002490 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002491
2492 /* So we don't get further callbacks for this connection */
2493 conn->connect_cfm_cb = NULL;
2494 conn->security_cfm_cb = NULL;
2495 conn->disconn_cfm_cb = NULL;
2496
David Herrmann76a68ba2013-04-06 20:28:37 +02002497 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002498
Johan Hedberga664b5b2011-02-19 12:06:02 -03002499 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002500}
2501
2502static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2503{
2504 struct pending_cmd *cmd;
2505
2506 BT_DBG("status %u", status);
2507
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002508 cmd = find_pairing(conn);
2509 if (!cmd)
2510 BT_DBG("Unable to find a pending command");
2511 else
Johan Hedberge2113262012-02-18 15:20:03 +02002512 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002513}
2514
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302515static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2516{
2517 struct pending_cmd *cmd;
2518
2519 BT_DBG("status %u", status);
2520
2521 if (!status)
2522 return;
2523
2524 cmd = find_pairing(conn);
2525 if (!cmd)
2526 BT_DBG("Unable to find a pending command");
2527 else
2528 pairing_complete(cmd, mgmt_status(status));
2529}
2530
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002531static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002532 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002533{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002534 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002535 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002536 struct pending_cmd *cmd;
2537 u8 sec_level, auth_type;
2538 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002539 int err;
2540
2541 BT_DBG("");
2542
Szymon Jancf950a30e2013-01-18 12:48:07 +01002543 memset(&rp, 0, sizeof(rp));
2544 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2545 rp.addr.type = cp->addr.type;
2546
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002547 if (!bdaddr_type_is_valid(cp->addr.type))
2548 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2549 MGMT_STATUS_INVALID_PARAMS,
2550 &rp, sizeof(rp));
2551
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002552 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002553
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002554 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002555 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2556 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002557 goto unlock;
2558 }
2559
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002560 sec_level = BT_SECURITY_MEDIUM;
2561 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002562 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002563 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002564 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002565
Andre Guedes591f47f2012-04-24 21:02:49 -03002566 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002567 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2568 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002569 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002570 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2571 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002572
Ville Tervo30e76272011-02-22 16:10:53 -03002573 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002574 int status;
2575
2576 if (PTR_ERR(conn) == -EBUSY)
2577 status = MGMT_STATUS_BUSY;
2578 else
2579 status = MGMT_STATUS_CONNECT_FAILED;
2580
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002581 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002582 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002583 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002584 goto unlock;
2585 }
2586
2587 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002588 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002589 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002590 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002591 goto unlock;
2592 }
2593
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002594 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002595 if (!cmd) {
2596 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002597 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002598 goto unlock;
2599 }
2600
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002601 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002602 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002603 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302604 else
2605 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002606
Johan Hedberge9a416b2011-02-19 12:05:56 -03002607 conn->security_cfm_cb = pairing_complete_cb;
2608 conn->disconn_cfm_cb = pairing_complete_cb;
2609 conn->io_capability = cp->io_cap;
2610 cmd->user_data = conn;
2611
2612 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002613 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002614 pairing_complete(cmd, 0);
2615
2616 err = 0;
2617
2618unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002619 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002620 return err;
2621}
2622
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002623static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2624 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002625{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002626 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002627 struct pending_cmd *cmd;
2628 struct hci_conn *conn;
2629 int err;
2630
2631 BT_DBG("");
2632
Johan Hedberg28424702012-02-02 04:02:29 +02002633 hci_dev_lock(hdev);
2634
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002635 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002636 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002637 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002638 goto unlock;
2639 }
2640
Johan Hedberg28424702012-02-02 04:02:29 +02002641 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2642 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002643 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002644 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002645 goto unlock;
2646 }
2647
2648 conn = cmd->user_data;
2649
2650 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002651 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002652 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002653 goto unlock;
2654 }
2655
2656 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2657
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002658 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002659 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002660unlock:
2661 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002662 return err;
2663}
2664
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002665static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002666 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002667 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002668{
Johan Hedberga5c29682011-02-19 12:05:57 -03002669 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002670 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002671 int err;
2672
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002673 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002674
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002675 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002676 err = cmd_complete(sk, hdev->id, mgmt_op,
2677 MGMT_STATUS_NOT_POWERED, addr,
2678 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002679 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002680 }
2681
Johan Hedberg1707c602013-03-15 17:07:15 -05002682 if (addr->type == BDADDR_BREDR)
2683 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002684 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002685 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002686
Johan Hedberg272d90d2012-02-09 15:26:12 +02002687 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002688 err = cmd_complete(sk, hdev->id, mgmt_op,
2689 MGMT_STATUS_NOT_CONNECTED, addr,
2690 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002691 goto done;
2692 }
2693
Johan Hedberg1707c602013-03-15 17:07:15 -05002694 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002695 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002696 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002697
Brian Gix5fe57d92011-12-21 16:12:13 -08002698 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002699 err = cmd_complete(sk, hdev->id, mgmt_op,
2700 MGMT_STATUS_SUCCESS, addr,
2701 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002702 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002703 err = cmd_complete(sk, hdev->id, mgmt_op,
2704 MGMT_STATUS_FAILED, addr,
2705 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002706
Brian Gix47c15e22011-11-16 13:53:14 -08002707 goto done;
2708 }
2709
Johan Hedberg1707c602013-03-15 17:07:15 -05002710 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002711 if (!cmd) {
2712 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002713 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002714 }
2715
Brian Gix0df4c182011-11-16 13:53:13 -08002716 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002717 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2718 struct hci_cp_user_passkey_reply cp;
2719
Johan Hedberg1707c602013-03-15 17:07:15 -05002720 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002721 cp.passkey = passkey;
2722 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2723 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002724 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2725 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002726
Johan Hedberga664b5b2011-02-19 12:06:02 -03002727 if (err < 0)
2728 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002729
Brian Gix0df4c182011-11-16 13:53:13 -08002730done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002731 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002732 return err;
2733}
2734
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302735static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2736 void *data, u16 len)
2737{
2738 struct mgmt_cp_pin_code_neg_reply *cp = data;
2739
2740 BT_DBG("");
2741
Johan Hedberg1707c602013-03-15 17:07:15 -05002742 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302743 MGMT_OP_PIN_CODE_NEG_REPLY,
2744 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2745}
2746
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002747static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2748 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002749{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002750 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002751
2752 BT_DBG("");
2753
2754 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002755 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002756 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002757
Johan Hedberg1707c602013-03-15 17:07:15 -05002758 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002759 MGMT_OP_USER_CONFIRM_REPLY,
2760 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002761}
2762
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002763static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002764 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002765{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002766 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002767
2768 BT_DBG("");
2769
Johan Hedberg1707c602013-03-15 17:07:15 -05002770 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002771 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2772 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002773}
2774
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002775static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2776 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002777{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002778 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002779
2780 BT_DBG("");
2781
Johan Hedberg1707c602013-03-15 17:07:15 -05002782 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002783 MGMT_OP_USER_PASSKEY_REPLY,
2784 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002785}
2786
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002787static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002788 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002789{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002790 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002791
2792 BT_DBG("");
2793
Johan Hedberg1707c602013-03-15 17:07:15 -05002794 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002795 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2796 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002797}
2798
Johan Hedberg13928972013-03-15 17:07:00 -05002799static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002800{
Johan Hedberg13928972013-03-15 17:07:00 -05002801 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002802 struct hci_cp_write_local_name cp;
2803
Johan Hedberg13928972013-03-15 17:07:00 -05002804 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002805
Johan Hedberg890ea892013-03-15 17:06:52 -05002806 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002807}
2808
Johan Hedberg13928972013-03-15 17:07:00 -05002809static void set_name_complete(struct hci_dev *hdev, u8 status)
2810{
2811 struct mgmt_cp_set_local_name *cp;
2812 struct pending_cmd *cmd;
2813
2814 BT_DBG("status 0x%02x", status);
2815
2816 hci_dev_lock(hdev);
2817
2818 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2819 if (!cmd)
2820 goto unlock;
2821
2822 cp = cmd->param;
2823
2824 if (status)
2825 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2826 mgmt_status(status));
2827 else
2828 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2829 cp, sizeof(*cp));
2830
2831 mgmt_pending_remove(cmd);
2832
2833unlock:
2834 hci_dev_unlock(hdev);
2835}
2836
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002837static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002838 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002839{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002840 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002841 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002842 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002843 int err;
2844
2845 BT_DBG("");
2846
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002847 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002848
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002849 /* If the old values are the same as the new ones just return a
2850 * direct command complete event.
2851 */
2852 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2853 !memcmp(hdev->short_name, cp->short_name,
2854 sizeof(hdev->short_name))) {
2855 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2856 data, len);
2857 goto failed;
2858 }
2859
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002860 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002861
Johan Hedbergb5235a62012-02-21 14:32:24 +02002862 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002863 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002864
2865 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002866 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002867 if (err < 0)
2868 goto failed;
2869
2870 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002871 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002872
Johan Hedbergb5235a62012-02-21 14:32:24 +02002873 goto failed;
2874 }
2875
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002876 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002877 if (!cmd) {
2878 err = -ENOMEM;
2879 goto failed;
2880 }
2881
Johan Hedberg13928972013-03-15 17:07:00 -05002882 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2883
Johan Hedberg890ea892013-03-15 17:06:52 -05002884 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002885
2886 if (lmp_bredr_capable(hdev)) {
2887 update_name(&req);
2888 update_eir(&req);
2889 }
2890
2891 if (lmp_le_capable(hdev))
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07002892 update_ad(&req);
Johan Hedberg3f985052013-03-15 17:07:02 -05002893
Johan Hedberg13928972013-03-15 17:07:00 -05002894 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002895 if (err < 0)
2896 mgmt_pending_remove(cmd);
2897
2898failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002899 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002900 return err;
2901}
2902
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002903static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002904 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002905{
Szymon Jancc35938b2011-03-22 13:12:21 +01002906 struct pending_cmd *cmd;
2907 int err;
2908
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002909 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002910
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002911 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002912
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002913 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002914 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002915 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002916 goto unlock;
2917 }
2918
Andre Guedes9a1a1992012-07-24 15:03:48 -03002919 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002920 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002921 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002922 goto unlock;
2923 }
2924
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002925 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002926 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002927 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002928 goto unlock;
2929 }
2930
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002931 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002932 if (!cmd) {
2933 err = -ENOMEM;
2934 goto unlock;
2935 }
2936
2937 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2938 if (err < 0)
2939 mgmt_pending_remove(cmd);
2940
2941unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002942 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002943 return err;
2944}
2945
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002946static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002947 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002948{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002949 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002950 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002951 int err;
2952
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002953 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002954
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002955 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002956
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002957 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002958 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002959 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002960 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002961 else
Szymon Janca6785be2012-12-13 15:11:21 +01002962 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002963
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002964 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002965 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002966
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002967 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002968 return err;
2969}
2970
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002971static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002972 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002973{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002974 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002975 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002976 int err;
2977
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002978 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002979
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002980 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002981
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002982 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002983 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002984 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002985 else
Szymon Janca6785be2012-12-13 15:11:21 +01002986 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002987
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002988 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002989 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002990
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002991 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002992 return err;
2993}
2994
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002995static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2996{
2997 struct pending_cmd *cmd;
2998 u8 type;
2999 int err;
3000
3001 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3002
3003 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
3004 if (!cmd)
3005 return -ENOENT;
3006
3007 type = hdev->discovery.type;
3008
3009 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3010 &type, sizeof(type));
3011 mgmt_pending_remove(cmd);
3012
3013 return err;
3014}
3015
Andre Guedes7c307722013-04-30 15:29:28 -03003016static void start_discovery_complete(struct hci_dev *hdev, u8 status)
3017{
3018 BT_DBG("status %d", status);
3019
3020 if (status) {
3021 hci_dev_lock(hdev);
3022 mgmt_start_discovery_failed(hdev, status);
3023 hci_dev_unlock(hdev);
3024 return;
3025 }
3026
3027 hci_dev_lock(hdev);
3028 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
3029 hci_dev_unlock(hdev);
3030
3031 switch (hdev->discovery.type) {
3032 case DISCOV_TYPE_LE:
3033 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003034 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003035 break;
3036
3037 case DISCOV_TYPE_INTERLEAVED:
3038 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03003039 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03003040 break;
3041
3042 case DISCOV_TYPE_BREDR:
3043 break;
3044
3045 default:
3046 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
3047 }
3048}
3049
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003050static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003051 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003052{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003053 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003054 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03003055 struct hci_cp_le_set_scan_param param_cp;
3056 struct hci_cp_le_set_scan_enable enable_cp;
3057 struct hci_cp_inquiry inq_cp;
3058 struct hci_request req;
3059 /* General inquiry access code (GIAC) */
3060 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03003061 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04003062 int err;
3063
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003064 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003065
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003066 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003067
Johan Hedberg4b34ee782012-02-21 14:13:02 +02003068 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003069 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003070 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02003071 goto failed;
3072 }
3073
Andre Guedes642be6c2012-03-21 00:03:37 -03003074 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
3075 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3076 MGMT_STATUS_BUSY);
3077 goto failed;
3078 }
3079
Johan Hedbergff9ef572012-01-04 14:23:45 +02003080 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003081 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003082 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003083 goto failed;
3084 }
3085
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003086 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003087 if (!cmd) {
3088 err = -ENOMEM;
3089 goto failed;
3090 }
3091
Andre Guedes4aab14e2012-02-17 20:39:36 -03003092 hdev->discovery.type = cp->type;
3093
Andre Guedes7c307722013-04-30 15:29:28 -03003094 hci_req_init(&req, hdev);
3095
Andre Guedes4aab14e2012-02-17 20:39:36 -03003096 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03003097 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003098 status = mgmt_bredr_support(hdev);
3099 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003100 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003101 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003102 mgmt_pending_remove(cmd);
3103 goto failed;
3104 }
3105
Andre Guedes7c307722013-04-30 15:29:28 -03003106 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3107 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3108 MGMT_STATUS_BUSY);
3109 mgmt_pending_remove(cmd);
3110 goto failed;
3111 }
3112
3113 hci_inquiry_cache_flush(hdev);
3114
3115 memset(&inq_cp, 0, sizeof(inq_cp));
3116 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03003117 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03003118 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03003119 break;
3120
3121 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03003122 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03003123 status = mgmt_le_support(hdev);
3124 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02003125 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003126 status);
Johan Hedberg04106752013-01-10 14:54:09 +02003127 mgmt_pending_remove(cmd);
3128 goto failed;
3129 }
3130
Andre Guedes7c307722013-04-30 15:29:28 -03003131 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03003132 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02003133 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3134 MGMT_STATUS_NOT_SUPPORTED);
3135 mgmt_pending_remove(cmd);
3136 goto failed;
3137 }
3138
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003139 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03003140 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3141 MGMT_STATUS_REJECTED);
3142 mgmt_pending_remove(cmd);
3143 goto failed;
3144 }
3145
3146 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
3147 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3148 MGMT_STATUS_BUSY);
3149 mgmt_pending_remove(cmd);
3150 goto failed;
3151 }
3152
3153 memset(&param_cp, 0, sizeof(param_cp));
3154 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03003155 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
3156 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07003157 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
3158 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
3159 else
3160 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03003161 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
3162 &param_cp);
3163
3164 memset(&enable_cp, 0, sizeof(enable_cp));
3165 enable_cp.enable = LE_SCAN_ENABLE;
3166 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
3167 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
3168 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03003169 break;
3170
Andre Guedesf39799f2012-02-17 20:39:35 -03003171 default:
Johan Hedberg04106752013-01-10 14:54:09 +02003172 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
3173 MGMT_STATUS_INVALID_PARAMS);
3174 mgmt_pending_remove(cmd);
3175 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03003176 }
Andre Guedes3fd24152012-02-03 17:48:01 -03003177
Andre Guedes7c307722013-04-30 15:29:28 -03003178 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003179 if (err < 0)
3180 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003181 else
3182 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003183
3184failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003185 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003186 return err;
3187}
3188
Andre Guedes1183fdc2013-04-30 15:29:35 -03003189static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3190{
3191 struct pending_cmd *cmd;
3192 int err;
3193
3194 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3195 if (!cmd)
3196 return -ENOENT;
3197
3198 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3199 &hdev->discovery.type, sizeof(hdev->discovery.type));
3200 mgmt_pending_remove(cmd);
3201
3202 return err;
3203}
3204
Andre Guedes0e05bba2013-04-30 15:29:33 -03003205static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
3206{
3207 BT_DBG("status %d", status);
3208
3209 hci_dev_lock(hdev);
3210
3211 if (status) {
3212 mgmt_stop_discovery_failed(hdev, status);
3213 goto unlock;
3214 }
3215
3216 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3217
3218unlock:
3219 hci_dev_unlock(hdev);
3220}
3221
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003222static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003223 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003224{
Johan Hedbergd9306502012-02-20 23:25:18 +02003225 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003226 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003227 struct hci_cp_remote_name_req_cancel cp;
3228 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003229 struct hci_request req;
3230 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003231 int err;
3232
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003233 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003234
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003235 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003236
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003237 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003238 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003239 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3240 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003241 goto unlock;
3242 }
3243
3244 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003245 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003246 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3247 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003248 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003249 }
3250
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003251 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003252 if (!cmd) {
3253 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003254 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003255 }
3256
Andre Guedes0e05bba2013-04-30 15:29:33 -03003257 hci_req_init(&req, hdev);
3258
Andre Guedese0d9727e2012-03-20 15:15:36 -03003259 switch (hdev->discovery.state) {
3260 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003261 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3262 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3263 } else {
3264 cancel_delayed_work(&hdev->le_scan_disable);
3265
3266 memset(&enable_cp, 0, sizeof(enable_cp));
3267 enable_cp.enable = LE_SCAN_DISABLE;
3268 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3269 sizeof(enable_cp), &enable_cp);
3270 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003271
Andre Guedese0d9727e2012-03-20 15:15:36 -03003272 break;
3273
3274 case DISCOVERY_RESOLVING:
3275 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003276 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003277 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003278 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003279 err = cmd_complete(sk, hdev->id,
3280 MGMT_OP_STOP_DISCOVERY, 0,
3281 &mgmt_cp->type,
3282 sizeof(mgmt_cp->type));
3283 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3284 goto unlock;
3285 }
3286
3287 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003288 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3289 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003290
3291 break;
3292
3293 default:
3294 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003295
3296 mgmt_pending_remove(cmd);
3297 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3298 MGMT_STATUS_FAILED, &mgmt_cp->type,
3299 sizeof(mgmt_cp->type));
3300 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003301 }
3302
Andre Guedes0e05bba2013-04-30 15:29:33 -03003303 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003304 if (err < 0)
3305 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003306 else
3307 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003308
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003309unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003310 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003311 return err;
3312}
3313
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003314static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003315 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003316{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003317 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003318 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003319 int err;
3320
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003321 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003322
Johan Hedberg561aafb2012-01-04 13:31:59 +02003323 hci_dev_lock(hdev);
3324
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003325 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003326 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003327 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003328 goto failed;
3329 }
3330
Johan Hedberga198e7b2012-02-17 14:27:06 +02003331 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003332 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003333 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003334 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003335 goto failed;
3336 }
3337
3338 if (cp->name_known) {
3339 e->name_state = NAME_KNOWN;
3340 list_del(&e->list);
3341 } else {
3342 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02003343 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003344 }
3345
Johan Hedberge3846622013-01-09 15:29:33 +02003346 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3347 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003348
3349failed:
3350 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003351 return err;
3352}
3353
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003354static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003355 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003356{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003357 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003358 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003359 int err;
3360
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003361 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003362
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003363 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003364 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3365 MGMT_STATUS_INVALID_PARAMS,
3366 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003367
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003368 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003369
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003370 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003371 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003372 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003373 else
Szymon Janca6785be2012-12-13 15:11:21 +01003374 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003375
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003376 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003377 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003378
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003379 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003380
3381 return err;
3382}
3383
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003384static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003385 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003386{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003387 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003388 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003389 int err;
3390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003391 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003392
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003393 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003394 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3395 MGMT_STATUS_INVALID_PARAMS,
3396 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003397
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003398 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003399
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003400 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003401 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003402 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003403 else
Szymon Janca6785be2012-12-13 15:11:21 +01003404 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003405
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003406 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003407 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003408
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003409 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003410
3411 return err;
3412}
3413
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003414static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3415 u16 len)
3416{
3417 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003418 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003419 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003420 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003421
3422 BT_DBG("%s", hdev->name);
3423
Szymon Jancc72d4b82012-03-16 16:02:57 +01003424 source = __le16_to_cpu(cp->source);
3425
3426 if (source > 0x0002)
3427 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3428 MGMT_STATUS_INVALID_PARAMS);
3429
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003430 hci_dev_lock(hdev);
3431
Szymon Jancc72d4b82012-03-16 16:02:57 +01003432 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003433 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3434 hdev->devid_product = __le16_to_cpu(cp->product);
3435 hdev->devid_version = __le16_to_cpu(cp->version);
3436
3437 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3438
Johan Hedberg890ea892013-03-15 17:06:52 -05003439 hci_req_init(&req, hdev);
3440 update_eir(&req);
3441 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003442
3443 hci_dev_unlock(hdev);
3444
3445 return err;
3446}
3447
Johan Hedberg4375f102013-09-25 13:26:10 +03003448static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3449{
3450 struct cmd_lookup match = { NULL, hdev };
3451
3452 if (status) {
3453 u8 mgmt_err = mgmt_status(status);
3454
3455 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3456 cmd_status_rsp, &mgmt_err);
3457 return;
3458 }
3459
3460 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3461 &match);
3462
3463 new_settings(hdev, match.sk);
3464
3465 if (match.sk)
3466 sock_put(match.sk);
3467}
3468
Marcel Holtmann21b51872013-10-10 09:47:53 -07003469static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3470 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003471{
3472 struct mgmt_mode *cp = data;
3473 struct pending_cmd *cmd;
3474 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003475 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003476 int err;
3477
3478 BT_DBG("request for %s", hdev->name);
3479
Johan Hedberge6fe7982013-10-02 15:45:22 +03003480 status = mgmt_le_support(hdev);
3481 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003482 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003483 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003484
3485 if (cp->val != 0x00 && cp->val != 0x01)
3486 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3487 MGMT_STATUS_INVALID_PARAMS);
3488
3489 hci_dev_lock(hdev);
3490
3491 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003492 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003493
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003494 /* The following conditions are ones which mean that we should
3495 * not do any HCI communication but directly send a mgmt
3496 * response to user space (after toggling the flag if
3497 * necessary).
3498 */
3499 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003500 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003501 bool changed = false;
3502
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003503 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3504 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003505 changed = true;
3506 }
3507
3508 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3509 if (err < 0)
3510 goto unlock;
3511
3512 if (changed)
3513 err = new_settings(hdev, sk);
3514
3515 goto unlock;
3516 }
3517
3518 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3519 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3520 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3521 MGMT_STATUS_BUSY);
3522 goto unlock;
3523 }
3524
3525 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3526 if (!cmd) {
3527 err = -ENOMEM;
3528 goto unlock;
3529 }
3530
3531 hci_req_init(&req, hdev);
3532
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003533 if (val)
3534 enable_advertising(&req);
3535 else
3536 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003537
3538 err = hci_req_run(&req, set_advertising_complete);
3539 if (err < 0)
3540 mgmt_pending_remove(cmd);
3541
3542unlock:
3543 hci_dev_unlock(hdev);
3544 return err;
3545}
3546
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003547static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3548 void *data, u16 len)
3549{
3550 struct mgmt_cp_set_static_address *cp = data;
3551 int err;
3552
3553 BT_DBG("%s", hdev->name);
3554
Marcel Holtmann62af4442013-10-02 22:10:32 -07003555 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003556 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003557 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003558
3559 if (hdev_is_powered(hdev))
3560 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3561 MGMT_STATUS_REJECTED);
3562
3563 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3564 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3565 return cmd_status(sk, hdev->id,
3566 MGMT_OP_SET_STATIC_ADDRESS,
3567 MGMT_STATUS_INVALID_PARAMS);
3568
3569 /* Two most significant bits shall be set */
3570 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3571 return cmd_status(sk, hdev->id,
3572 MGMT_OP_SET_STATIC_ADDRESS,
3573 MGMT_STATUS_INVALID_PARAMS);
3574 }
3575
3576 hci_dev_lock(hdev);
3577
3578 bacpy(&hdev->static_addr, &cp->bdaddr);
3579
3580 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3581
3582 hci_dev_unlock(hdev);
3583
3584 return err;
3585}
3586
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003587static int set_scan_params(struct sock *sk, struct hci_dev *hdev,
3588 void *data, u16 len)
3589{
3590 struct mgmt_cp_set_scan_params *cp = data;
3591 __u16 interval, window;
3592 int err;
3593
3594 BT_DBG("%s", hdev->name);
3595
3596 if (!lmp_le_capable(hdev))
3597 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3598 MGMT_STATUS_NOT_SUPPORTED);
3599
3600 interval = __le16_to_cpu(cp->interval);
3601
3602 if (interval < 0x0004 || interval > 0x4000)
3603 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3604 MGMT_STATUS_INVALID_PARAMS);
3605
3606 window = __le16_to_cpu(cp->window);
3607
3608 if (window < 0x0004 || window > 0x4000)
3609 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3610 MGMT_STATUS_INVALID_PARAMS);
3611
Marcel Holtmann899e1072013-10-14 09:55:32 -07003612 if (window > interval)
3613 return cmd_status(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS,
3614 MGMT_STATUS_INVALID_PARAMS);
3615
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003616 hci_dev_lock(hdev);
3617
3618 hdev->le_scan_interval = interval;
3619 hdev->le_scan_window = window;
3620
3621 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_SCAN_PARAMS, 0, NULL, 0);
3622
3623 hci_dev_unlock(hdev);
3624
3625 return err;
3626}
3627
Johan Hedberg33e38b32013-03-15 17:07:05 -05003628static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3629{
3630 struct pending_cmd *cmd;
3631
3632 BT_DBG("status 0x%02x", status);
3633
3634 hci_dev_lock(hdev);
3635
3636 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3637 if (!cmd)
3638 goto unlock;
3639
3640 if (status) {
3641 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3642 mgmt_status(status));
3643 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003644 struct mgmt_mode *cp = cmd->param;
3645
3646 if (cp->val)
3647 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3648 else
3649 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3650
Johan Hedberg33e38b32013-03-15 17:07:05 -05003651 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3652 new_settings(hdev, cmd->sk);
3653 }
3654
3655 mgmt_pending_remove(cmd);
3656
3657unlock:
3658 hci_dev_unlock(hdev);
3659}
3660
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003661static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003662 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003663{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003664 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003665 struct pending_cmd *cmd;
3666 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003667 int err;
3668
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003669 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003670
Johan Hedberg56f87902013-10-02 13:43:13 +03003671 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3672 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003673 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3674 MGMT_STATUS_NOT_SUPPORTED);
3675
Johan Hedberga7e80f22013-01-09 16:05:19 +02003676 if (cp->val != 0x00 && cp->val != 0x01)
3677 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3678 MGMT_STATUS_INVALID_PARAMS);
3679
Johan Hedberg5400c042012-02-21 16:40:33 +02003680 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003681 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003682 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003683
3684 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003685 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003686 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003687
3688 hci_dev_lock(hdev);
3689
Johan Hedberg05cbf292013-03-15 17:07:07 -05003690 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3691 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3692 MGMT_STATUS_BUSY);
3693 goto unlock;
3694 }
3695
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003696 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3697 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3698 hdev);
3699 goto unlock;
3700 }
3701
Johan Hedberg33e38b32013-03-15 17:07:05 -05003702 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3703 data, len);
3704 if (!cmd) {
3705 err = -ENOMEM;
3706 goto unlock;
3707 }
3708
3709 hci_req_init(&req, hdev);
3710
Johan Hedberg406d7802013-03-15 17:07:09 -05003711 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003712
3713 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003714 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003715 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003716 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003717 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003718 }
3719
Johan Hedberg33e38b32013-03-15 17:07:05 -05003720unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003721 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003722
Antti Julkuf6422ec2011-06-22 13:11:56 +03003723 return err;
3724}
3725
Johan Hedberg67e5a7a2013-10-14 21:15:25 +03003726static void set_bredr_scan(struct hci_request *req)
3727{
3728 struct hci_dev *hdev = req->hdev;
3729 u8 scan = 0;
3730
3731 /* Ensure that fast connectable is disabled. This function will
3732 * not do anything if the page scan parameters are already what
3733 * they should be.
3734 */
3735 write_fast_connectable(req, false);
3736
3737 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3738 scan |= SCAN_PAGE;
3739 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3740 scan |= SCAN_INQUIRY;
3741
3742 if (scan)
3743 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3744}
3745
Johan Hedberg0663ca22013-10-02 13:43:14 +03003746static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3747{
3748 struct pending_cmd *cmd;
3749
3750 BT_DBG("status 0x%02x", status);
3751
3752 hci_dev_lock(hdev);
3753
3754 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3755 if (!cmd)
3756 goto unlock;
3757
3758 if (status) {
3759 u8 mgmt_err = mgmt_status(status);
3760
3761 /* We need to restore the flag if related HCI commands
3762 * failed.
3763 */
3764 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3765
3766 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3767 } else {
3768 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3769 new_settings(hdev, cmd->sk);
3770 }
3771
3772 mgmt_pending_remove(cmd);
3773
3774unlock:
3775 hci_dev_unlock(hdev);
3776}
3777
3778static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3779{
3780 struct mgmt_mode *cp = data;
3781 struct pending_cmd *cmd;
3782 struct hci_request req;
3783 int err;
3784
3785 BT_DBG("request for %s", hdev->name);
3786
3787 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3788 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3789 MGMT_STATUS_NOT_SUPPORTED);
3790
3791 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3792 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3793 MGMT_STATUS_REJECTED);
3794
3795 if (cp->val != 0x00 && cp->val != 0x01)
3796 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3797 MGMT_STATUS_INVALID_PARAMS);
3798
3799 hci_dev_lock(hdev);
3800
3801 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3802 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3803 goto unlock;
3804 }
3805
3806 if (!hdev_is_powered(hdev)) {
3807 if (!cp->val) {
Johan Hedberg0663ca22013-10-02 13:43:14 +03003808 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3809 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3810 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3811 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3812 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3813 }
3814
3815 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3816
3817 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3818 if (err < 0)
3819 goto unlock;
3820
3821 err = new_settings(hdev, sk);
3822 goto unlock;
3823 }
3824
3825 /* Reject disabling when powered on */
3826 if (!cp->val) {
3827 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3828 MGMT_STATUS_REJECTED);
3829 goto unlock;
3830 }
3831
3832 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3833 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3834 MGMT_STATUS_BUSY);
3835 goto unlock;
3836 }
3837
3838 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3839 if (!cmd) {
3840 err = -ENOMEM;
3841 goto unlock;
3842 }
3843
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07003844 /* We need to flip the bit already here so that update_ad
Johan Hedberg0663ca22013-10-02 13:43:14 +03003845 * generates the correct flags.
3846 */
3847 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3848
3849 hci_req_init(&req, hdev);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003850
3851 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3852 set_bredr_scan(&req);
3853
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07003854 update_ad(&req);
Johan Hedbergaa8af462013-10-14 21:15:26 +03003855
Johan Hedberg0663ca22013-10-02 13:43:14 +03003856 err = hci_req_run(&req, set_bredr_complete);
3857 if (err < 0)
3858 mgmt_pending_remove(cmd);
3859
3860unlock:
3861 hci_dev_unlock(hdev);
3862 return err;
3863}
3864
Johan Hedberg3f706b72013-01-20 14:27:16 +02003865static bool ltk_is_valid(struct mgmt_ltk_info *key)
3866{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003867 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3868 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003869 if (key->master != 0x00 && key->master != 0x01)
3870 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003871 if (!bdaddr_type_is_le(key->addr.type))
3872 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003873 return true;
3874}
3875
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003876static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003877 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003878{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003879 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3880 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003881 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003882
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003883 BT_DBG("request for %s", hdev->name);
3884
3885 if (!lmp_le_capable(hdev))
3886 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3887 MGMT_STATUS_NOT_SUPPORTED);
3888
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003889 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003890
3891 expected_len = sizeof(*cp) + key_count *
3892 sizeof(struct mgmt_ltk_info);
3893 if (expected_len != len) {
3894 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003895 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003896 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003897 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003898 }
3899
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003900 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003901
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003902 for (i = 0; i < key_count; i++) {
3903 struct mgmt_ltk_info *key = &cp->keys[i];
3904
Johan Hedberg3f706b72013-01-20 14:27:16 +02003905 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003906 return cmd_status(sk, hdev->id,
3907 MGMT_OP_LOAD_LONG_TERM_KEYS,
3908 MGMT_STATUS_INVALID_PARAMS);
3909 }
3910
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003911 hci_dev_lock(hdev);
3912
3913 hci_smp_ltks_clear(hdev);
3914
3915 for (i = 0; i < key_count; i++) {
3916 struct mgmt_ltk_info *key = &cp->keys[i];
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003917 u8 type, addr_type;
3918
3919 if (key->addr.type == BDADDR_LE_PUBLIC)
3920 addr_type = ADDR_LE_DEV_PUBLIC;
3921 else
3922 addr_type = ADDR_LE_DEV_RANDOM;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003923
3924 if (key->master)
3925 type = HCI_SMP_LTK;
3926 else
3927 type = HCI_SMP_LTK_SLAVE;
3928
Marcel Holtmann79d95a12013-10-13 03:57:38 -07003929 hci_add_ltk(hdev, &key->addr.bdaddr, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003930 type, 0, key->authenticated, key->val,
3931 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003932 }
3933
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003934 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3935 NULL, 0);
3936
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003937 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003938
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003939 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003940}
3941
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003942static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003943 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3944 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003945 bool var_len;
3946 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003947} mgmt_handlers[] = {
3948 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003949 { read_version, false, MGMT_READ_VERSION_SIZE },
3950 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3951 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3952 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3953 { set_powered, false, MGMT_SETTING_SIZE },
3954 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3955 { set_connectable, false, MGMT_SETTING_SIZE },
3956 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3957 { set_pairable, false, MGMT_SETTING_SIZE },
3958 { set_link_security, false, MGMT_SETTING_SIZE },
3959 { set_ssp, false, MGMT_SETTING_SIZE },
3960 { set_hs, false, MGMT_SETTING_SIZE },
3961 { set_le, false, MGMT_SETTING_SIZE },
3962 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3963 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3964 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3965 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3966 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3967 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3968 { disconnect, false, MGMT_DISCONNECT_SIZE },
3969 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3970 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3971 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3972 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3973 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3974 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3975 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3976 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3977 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3978 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3979 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3980 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3981 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3982 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3983 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3984 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3985 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3986 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3987 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003988 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003989 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003990 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003991 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Marcel Holtmann14b49b92013-10-11 08:23:20 -07003992 { set_scan_params, false, MGMT_SET_SCAN_PARAMS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003993};
3994
3995
Johan Hedberg03811012010-12-08 00:21:06 +02003996int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3997{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003998 void *buf;
3999 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02004000 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01004001 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004002 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02004003 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02004004 int err;
4005
4006 BT_DBG("got %zu bytes", msglen);
4007
4008 if (msglen < sizeof(*hdr))
4009 return -EINVAL;
4010
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03004011 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02004012 if (!buf)
4013 return -ENOMEM;
4014
4015 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
4016 err = -EFAULT;
4017 goto done;
4018 }
4019
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03004020 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07004021 opcode = __le16_to_cpu(hdr->opcode);
4022 index = __le16_to_cpu(hdr->index);
4023 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02004024
4025 if (len != msglen - sizeof(*hdr)) {
4026 err = -EINVAL;
4027 goto done;
4028 }
4029
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004030 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004031 hdev = hci_dev_get(index);
4032 if (!hdev) {
4033 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004034 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004035 goto done;
4036 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004037
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02004038 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
4039 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07004040 err = cmd_status(sk, index, opcode,
4041 MGMT_STATUS_INVALID_INDEX);
4042 goto done;
4043 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004044 }
4045
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004046 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004047 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02004048 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02004049 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004050 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004051 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02004052 }
4053
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004054 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004055 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004056 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004057 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004058 goto done;
4059 }
4060
Johan Hedbergbe22b542012-03-01 22:24:41 +02004061 handler = &mgmt_handlers[opcode];
4062
4063 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004064 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02004065 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004066 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02004067 goto done;
4068 }
4069
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02004070 if (hdev)
4071 mgmt_init_hdev(sk, hdev);
4072
4073 cp = buf + sizeof(*hdr);
4074
Johan Hedbergbe22b542012-03-01 22:24:41 +02004075 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02004076 if (err < 0)
4077 goto done;
4078
Johan Hedberg03811012010-12-08 00:21:06 +02004079 err = msglen;
4080
4081done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02004082 if (hdev)
4083 hci_dev_put(hdev);
4084
Johan Hedberg03811012010-12-08 00:21:06 +02004085 kfree(buf);
4086 return err;
4087}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004088
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004089void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004090{
Marcel Holtmann1514b892013-10-06 08:25:01 -07004091 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004092 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004093
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004094 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004095}
4096
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004097void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02004098{
Johan Hedberg5f159032012-03-02 03:13:19 +02004099 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004100
Marcel Holtmann1514b892013-10-06 08:25:01 -07004101 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004102 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03004103
Johan Hedberg744cf192011-11-08 20:40:14 +02004104 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02004105
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07004106 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004107}
4108
Johan Hedberg229ab392013-03-15 17:06:53 -05004109static void powered_complete(struct hci_dev *hdev, u8 status)
4110{
4111 struct cmd_lookup match = { NULL, hdev };
4112
4113 BT_DBG("status 0x%02x", status);
4114
4115 hci_dev_lock(hdev);
4116
4117 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4118
4119 new_settings(hdev, match.sk);
4120
4121 hci_dev_unlock(hdev);
4122
4123 if (match.sk)
4124 sock_put(match.sk);
4125}
4126
Johan Hedberg70da6242013-03-15 17:06:51 -05004127static int powered_update_hci(struct hci_dev *hdev)
4128{
Johan Hedberg890ea892013-03-15 17:06:52 -05004129 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05004130 u8 link_sec;
4131
Johan Hedberg890ea892013-03-15 17:06:52 -05004132 hci_req_init(&req, hdev);
4133
Johan Hedberg70da6242013-03-15 17:06:51 -05004134 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
4135 !lmp_host_ssp_capable(hdev)) {
4136 u8 ssp = 1;
4137
Johan Hedberg890ea892013-03-15 17:06:52 -05004138 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004139 }
4140
Johan Hedbergc73eee92013-04-19 18:35:21 +03004141 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
4142 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05004143 struct hci_cp_write_le_host_supported cp;
4144
4145 cp.le = 1;
4146 cp.simul = lmp_le_br_capable(hdev);
4147
4148 /* Check first if we already have the right
4149 * host state (host features set)
4150 */
4151 if (cp.le != lmp_host_le_capable(hdev) ||
4152 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004153 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
4154 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05004155 }
4156
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004157 if (lmp_le_capable(hdev)) {
4158 /* Set random address to static address if configured */
4159 if (bacmp(&hdev->static_addr, BDADDR_ANY))
4160 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
4161 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07004162
Marcel Holtmann441ad2d2013-10-15 06:33:52 -07004163 /* Make sure the controller has a good default for
4164 * advertising data. This also applies to the case
4165 * where BR/EDR was toggled during the AUTO_OFF phase.
4166 */
4167 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
4168 update_ad(&req);
4169
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07004170 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4171 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03004172 }
4173
Johan Hedberg70da6242013-03-15 17:06:51 -05004174 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
4175 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004176 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
4177 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05004178
4179 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03004180 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
4181 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004182 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05004183 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05004184 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05004185 }
4186
Johan Hedberg229ab392013-03-15 17:06:53 -05004187 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05004188}
4189
Johan Hedberg744cf192011-11-08 20:40:14 +02004190int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02004191{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02004192 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05004193 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
4194 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004195 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004196
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004197 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
4198 return 0;
4199
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004200 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05004201 if (powered_update_hci(hdev) == 0)
4202 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02004203
Johan Hedberg229ab392013-03-15 17:06:53 -05004204 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
4205 &match);
4206 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02004207 }
4208
Johan Hedberg229ab392013-03-15 17:06:53 -05004209 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
4210 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
4211
4212 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
4213 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
4214 zero_cod, sizeof(zero_cod), NULL);
4215
4216new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004217 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02004218
4219 if (match.sk)
4220 sock_put(match.sk);
4221
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004222 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02004223}
Johan Hedberg73f22f62010-12-29 16:00:25 +02004224
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004225void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03004226{
4227 struct pending_cmd *cmd;
4228 u8 status;
4229
4230 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
4231 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004232 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03004233
4234 if (err == -ERFKILL)
4235 status = MGMT_STATUS_RFKILLED;
4236 else
4237 status = MGMT_STATUS_FAILED;
4238
Marcel Holtmann3eec7052013-10-06 23:55:46 -07004239 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004240
4241 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03004242}
4243
Marcel Holtmann86a75642013-10-15 06:33:54 -07004244void mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02004245{
Marcel Holtmann86a75642013-10-15 06:33:54 -07004246 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004247
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004248 /* Nothing needed here if there's a pending command since that
4249 * commands request completion callback takes care of everything
4250 * necessary.
4251 */
4252 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev))
Marcel Holtmann86a75642013-10-15 06:33:54 -07004253 return;
Johan Hedbergbfaf8c92013-10-14 21:15:27 +03004254
Marcel Holtmann86a75642013-10-15 06:33:54 -07004255 if (discoverable)
4256 changed = !test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
4257 else
4258 changed = test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004259
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004260 if (changed)
Marcel Holtmann86a75642013-10-15 06:33:54 -07004261 new_settings(hdev, NULL);
Johan Hedberg73f22f62010-12-29 16:00:25 +02004262}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004263
Marcel Holtmanna3309162013-10-15 06:33:55 -07004264void mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004265{
Marcel Holtmanna3309162013-10-15 06:33:55 -07004266 bool changed;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004267
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004268 /* Nothing needed here if there's a pending command since that
4269 * commands request completion callback takes care of everything
4270 * necessary.
4271 */
4272 if (mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev))
Marcel Holtmanna3309162013-10-15 06:33:55 -07004273 return;
Johan Hedbergd7b856f2013-10-14 16:20:04 +03004274
Marcel Holtmanna3309162013-10-15 06:33:55 -07004275 if (connectable)
4276 changed = !test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
4277 else
4278 changed = test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004279
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004280 if (changed)
Marcel Holtmanna3309162013-10-15 06:33:55 -07004281 new_settings(hdev, NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004282}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004283
Marcel Holtmann4796e8a2013-10-15 06:33:56 -07004284void mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004285{
Johan Hedbergca69b792011-11-11 18:10:00 +02004286 u8 mgmt_err = mgmt_status(status);
4287
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004288 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004289 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004290 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004291
4292 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004293 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004294 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004295}
4296
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004297int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4298 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004299{
Johan Hedberg86742e12011-11-07 23:13:38 +02004300 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004301
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004302 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004303
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004304 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004305 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004306 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004307 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004308 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004309 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004310
Johan Hedberg744cf192011-11-08 20:40:14 +02004311 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004312}
Johan Hedbergf7520542011-01-20 12:34:39 +02004313
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004314int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4315{
4316 struct mgmt_ev_new_long_term_key ev;
4317
4318 memset(&ev, 0, sizeof(ev));
4319
4320 ev.store_hint = persistent;
4321 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004322 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004323 ev.key.authenticated = key->authenticated;
4324 ev.key.enc_size = key->enc_size;
4325 ev.key.ediv = key->ediv;
4326
4327 if (key->type == HCI_SMP_LTK)
4328 ev.key.master = 1;
4329
4330 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4331 memcpy(ev.key.val, key->val, sizeof(key->val));
4332
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004333 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4334 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004335}
4336
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004337void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4338 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4339 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004340{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004341 char buf[512];
4342 struct mgmt_ev_device_connected *ev = (void *) buf;
4343 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004344
Johan Hedbergb644ba32012-01-17 21:48:47 +02004345 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004346 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004347
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004348 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004349
Johan Hedbergb644ba32012-01-17 21:48:47 +02004350 if (name_len > 0)
4351 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004352 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004353
4354 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004355 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004356 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004357
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004358 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004359
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004360 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4361 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004362}
4363
Johan Hedberg8962ee72011-01-20 12:40:27 +02004364static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4365{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004366 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004367 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004368 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004369
Johan Hedberg88c3df12012-02-09 14:27:38 +02004370 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4371 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004372
Johan Hedbergaee9b212012-02-18 15:07:59 +02004373 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004374 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004375
4376 *sk = cmd->sk;
4377 sock_hold(*sk);
4378
Johan Hedberga664b5b2011-02-19 12:06:02 -03004379 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004380}
4381
Johan Hedberg124f6e32012-02-09 13:50:12 +02004382static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004383{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004384 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004385 struct mgmt_cp_unpair_device *cp = cmd->param;
4386 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004387
4388 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004389 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4390 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004391
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004392 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4393
Johan Hedbergaee9b212012-02-18 15:07:59 +02004394 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004395
4396 mgmt_pending_remove(cmd);
4397}
4398
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004399void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4400 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004401{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004402 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004403 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004404
Johan Hedberg744cf192011-11-08 20:40:14 +02004405 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004406
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004407 bacpy(&ev.addr.bdaddr, bdaddr);
4408 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4409 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004410
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004411 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004412
4413 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004414 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004415
Johan Hedberg124f6e32012-02-09 13:50:12 +02004416 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004417 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004418}
4419
Marcel Holtmann78929242013-10-06 23:55:47 -07004420void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4421 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004422{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004423 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004424 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004425
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004426 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4427 hdev);
4428
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004429 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004430 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004431 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004432
Johan Hedberg88c3df12012-02-09 14:27:38 +02004433 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004434 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004435
Marcel Holtmann78929242013-10-06 23:55:47 -07004436 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4437 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004438
Johan Hedberga664b5b2011-02-19 12:06:02 -03004439 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004440}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004441
Marcel Holtmann445608d2013-10-06 23:55:48 -07004442void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4443 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004444{
4445 struct mgmt_ev_connect_failed ev;
4446
Johan Hedberg4c659c32011-11-07 23:13:39 +02004447 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004448 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004449 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004450
Marcel Holtmann445608d2013-10-06 23:55:48 -07004451 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004452}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004453
Johan Hedberg744cf192011-11-08 20:40:14 +02004454int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004455{
4456 struct mgmt_ev_pin_code_request ev;
4457
Johan Hedbergd8457692012-02-17 14:24:57 +02004458 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004459 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004460 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004461
Johan Hedberg744cf192011-11-08 20:40:14 +02004462 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004463 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004464}
4465
Johan Hedberg744cf192011-11-08 20:40:14 +02004466int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004467 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004468{
4469 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004470 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004471 int err;
4472
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004473 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004474 if (!cmd)
4475 return -ENOENT;
4476
Johan Hedbergd8457692012-02-17 14:24:57 +02004477 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004478 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004479
Johan Hedbergaee9b212012-02-18 15:07:59 +02004480 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004481 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004482
Johan Hedberga664b5b2011-02-19 12:06:02 -03004483 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004484
4485 return err;
4486}
4487
Johan Hedberg744cf192011-11-08 20:40:14 +02004488int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004489 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004490{
4491 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004492 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004493 int err;
4494
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004495 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004496 if (!cmd)
4497 return -ENOENT;
4498
Johan Hedbergd8457692012-02-17 14:24:57 +02004499 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004500 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004501
Johan Hedbergaee9b212012-02-18 15:07:59 +02004502 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004503 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004504
Johan Hedberga664b5b2011-02-19 12:06:02 -03004505 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004506
4507 return err;
4508}
Johan Hedberga5c29682011-02-19 12:05:57 -03004509
Johan Hedberg744cf192011-11-08 20:40:14 +02004510int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004511 u8 link_type, u8 addr_type, __le32 value,
4512 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004513{
4514 struct mgmt_ev_user_confirm_request ev;
4515
Johan Hedberg744cf192011-11-08 20:40:14 +02004516 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004517
Johan Hedberg272d90d2012-02-09 15:26:12 +02004518 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004519 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004520 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004521 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004522
Johan Hedberg744cf192011-11-08 20:40:14 +02004523 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004524 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004525}
4526
Johan Hedberg272d90d2012-02-09 15:26:12 +02004527int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004528 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004529{
4530 struct mgmt_ev_user_passkey_request ev;
4531
4532 BT_DBG("%s", hdev->name);
4533
Johan Hedberg272d90d2012-02-09 15:26:12 +02004534 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004535 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004536
4537 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004538 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004539}
4540
Brian Gix0df4c182011-11-16 13:53:13 -08004541static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004542 u8 link_type, u8 addr_type, u8 status,
4543 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004544{
4545 struct pending_cmd *cmd;
4546 struct mgmt_rp_user_confirm_reply rp;
4547 int err;
4548
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004549 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004550 if (!cmd)
4551 return -ENOENT;
4552
Johan Hedberg272d90d2012-02-09 15:26:12 +02004553 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004554 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004555 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004556 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004557
Johan Hedberga664b5b2011-02-19 12:06:02 -03004558 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004559
4560 return err;
4561}
4562
Johan Hedberg744cf192011-11-08 20:40:14 +02004563int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004564 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004565{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004566 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004567 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004568}
4569
Johan Hedberg272d90d2012-02-09 15:26:12 +02004570int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004571 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004572{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004573 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004574 status,
4575 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004576}
Johan Hedberg2a611692011-02-19 12:06:00 -03004577
Brian Gix604086b2011-11-23 08:28:33 -08004578int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004579 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004580{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004581 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004582 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004583}
4584
Johan Hedberg272d90d2012-02-09 15:26:12 +02004585int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004586 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004587{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004588 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004589 status,
4590 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004591}
4592
Johan Hedberg92a25252012-09-06 18:39:26 +03004593int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4594 u8 link_type, u8 addr_type, u32 passkey,
4595 u8 entered)
4596{
4597 struct mgmt_ev_passkey_notify ev;
4598
4599 BT_DBG("%s", hdev->name);
4600
4601 bacpy(&ev.addr.bdaddr, bdaddr);
4602 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4603 ev.passkey = __cpu_to_le32(passkey);
4604 ev.entered = entered;
4605
4606 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4607}
4608
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004609int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004610 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004611{
4612 struct mgmt_ev_auth_failed ev;
4613
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004614 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004615 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004616 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004617
Johan Hedberg744cf192011-11-08 20:40:14 +02004618 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004619}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004620
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004621int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4622{
4623 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004624 bool changed = false;
4625 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004626
4627 if (status) {
4628 u8 mgmt_err = mgmt_status(status);
4629 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004630 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004631 return 0;
4632 }
4633
Johan Hedberg47990ea2012-02-22 11:58:37 +02004634 if (test_bit(HCI_AUTH, &hdev->flags)) {
4635 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4636 changed = true;
4637 } else {
4638 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4639 changed = true;
4640 }
4641
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004642 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004643 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004644
Johan Hedberg47990ea2012-02-22 11:58:37 +02004645 if (changed)
4646 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004647
4648 if (match.sk)
4649 sock_put(match.sk);
4650
4651 return err;
4652}
4653
Johan Hedberg890ea892013-03-15 17:06:52 -05004654static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004655{
Johan Hedberg890ea892013-03-15 17:06:52 -05004656 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004657 struct hci_cp_write_eir cp;
4658
Johan Hedberg976eb202012-10-24 21:12:01 +03004659 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004660 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004661
Johan Hedbergc80da272012-02-22 15:38:48 +02004662 memset(hdev->eir, 0, sizeof(hdev->eir));
4663
Johan Hedbergcacaf522012-02-21 00:52:42 +02004664 memset(&cp, 0, sizeof(cp));
4665
Johan Hedberg890ea892013-03-15 17:06:52 -05004666 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004667}
4668
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004669int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004670{
4671 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004672 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004673 bool changed = false;
4674 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004675
4676 if (status) {
4677 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004678
4679 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004680 &hdev->dev_flags)) {
4681 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004682 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004683 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004684
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004685 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4686 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004687
4688 return err;
4689 }
4690
4691 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004692 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004693 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004694 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4695 if (!changed)
4696 changed = test_and_clear_bit(HCI_HS_ENABLED,
4697 &hdev->dev_flags);
4698 else
4699 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004700 }
4701
4702 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4703
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004704 if (changed)
4705 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004706
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004707 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004708 sock_put(match.sk);
4709
Johan Hedberg890ea892013-03-15 17:06:52 -05004710 hci_req_init(&req, hdev);
4711
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004712 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004713 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004714 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004715 clear_eir(&req);
4716
4717 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004718
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004719 return err;
4720}
4721
Johan Hedberg92da6092013-03-15 17:06:55 -05004722static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004723{
4724 struct cmd_lookup *match = data;
4725
Johan Hedberg90e70452012-02-23 23:09:40 +02004726 if (match->sk == NULL) {
4727 match->sk = cmd->sk;
4728 sock_hold(match->sk);
4729 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004730}
4731
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004732int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004733 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004734{
Johan Hedberg90e70452012-02-23 23:09:40 +02004735 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4736 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004737
Johan Hedberg92da6092013-03-15 17:06:55 -05004738 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4739 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4740 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004741
4742 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004743 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4744 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004745
4746 if (match.sk)
4747 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004748
4749 return err;
4750}
4751
Johan Hedberg744cf192011-11-08 20:40:14 +02004752int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004753{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004754 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004755 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004756
Johan Hedberg13928972013-03-15 17:07:00 -05004757 if (status)
4758 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004759
4760 memset(&ev, 0, sizeof(ev));
4761 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004762 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004763
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004764 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004765 if (!cmd) {
4766 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004767
Johan Hedberg13928972013-03-15 17:07:00 -05004768 /* If this is a HCI command related to powering on the
4769 * HCI dev don't send any mgmt signals.
4770 */
4771 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4772 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004773 }
4774
Johan Hedberg13928972013-03-15 17:07:00 -05004775 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4776 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004777}
Szymon Jancc35938b2011-03-22 13:12:21 +01004778
Johan Hedberg744cf192011-11-08 20:40:14 +02004779int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004780 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004781{
4782 struct pending_cmd *cmd;
4783 int err;
4784
Johan Hedberg744cf192011-11-08 20:40:14 +02004785 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004786
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004787 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004788 if (!cmd)
4789 return -ENOENT;
4790
4791 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004792 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4793 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004794 } else {
4795 struct mgmt_rp_read_local_oob_data rp;
4796
4797 memcpy(rp.hash, hash, sizeof(rp.hash));
4798 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4799
Johan Hedberg744cf192011-11-08 20:40:14 +02004800 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004801 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4802 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004803 }
4804
4805 mgmt_pending_remove(cmd);
4806
4807 return err;
4808}
Johan Hedberge17acd42011-03-30 23:57:16 +03004809
Marcel Holtmann901801b2013-10-06 23:55:51 -07004810void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4811 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4812 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004813{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004814 char buf[512];
4815 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004816 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004817
Andre Guedes12602d02013-04-30 15:29:40 -03004818 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004819 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004820
Johan Hedberg1dc06092012-01-15 21:01:23 +02004821 /* Leave 5 bytes for a potential CoD field */
4822 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004823 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004824
Johan Hedberg1dc06092012-01-15 21:01:23 +02004825 memset(buf, 0, sizeof(buf));
4826
Johan Hedberge319d2e2012-01-15 19:51:59 +02004827 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004828 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004829 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004830 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304831 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004832 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304833 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004834
Johan Hedberg1dc06092012-01-15 21:01:23 +02004835 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004836 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004837
Johan Hedberg1dc06092012-01-15 21:01:23 +02004838 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4839 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004840 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004841
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004842 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004843 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004844
Marcel Holtmann901801b2013-10-06 23:55:51 -07004845 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004846}
Johan Hedberga88a9652011-03-30 13:18:12 +03004847
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004848void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4849 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004850{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004851 struct mgmt_ev_device_found *ev;
4852 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4853 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004854
Johan Hedbergb644ba32012-01-17 21:48:47 +02004855 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004856
Johan Hedbergb644ba32012-01-17 21:48:47 +02004857 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004858
Johan Hedbergb644ba32012-01-17 21:48:47 +02004859 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004860 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004861 ev->rssi = rssi;
4862
4863 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004864 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004865
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004866 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004867
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004868 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004869}
Johan Hedberg314b2382011-04-27 10:29:57 -04004870
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004871void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004872{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004873 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004874 struct pending_cmd *cmd;
4875
Andre Guedes343fb142011-11-22 17:14:19 -03004876 BT_DBG("%s discovering %u", hdev->name, discovering);
4877
Johan Hedberg164a6e72011-11-01 17:06:44 +02004878 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004879 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004880 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004881 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004882
4883 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004884 u8 type = hdev->discovery.type;
4885
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004886 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4887 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004888 mgmt_pending_remove(cmd);
4889 }
4890
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004891 memset(&ev, 0, sizeof(ev));
4892 ev.type = hdev->discovery.type;
4893 ev.discovering = discovering;
4894
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004895 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004896}
Antti Julku5e762442011-08-25 16:48:02 +03004897
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004898int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004899{
4900 struct pending_cmd *cmd;
4901 struct mgmt_ev_device_blocked ev;
4902
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004903 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004904
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004905 bacpy(&ev.addr.bdaddr, bdaddr);
4906 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004907
Johan Hedberg744cf192011-11-08 20:40:14 +02004908 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004909 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004910}
4911
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004912int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004913{
4914 struct pending_cmd *cmd;
4915 struct mgmt_ev_device_unblocked ev;
4916
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004917 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004918
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004919 bacpy(&ev.addr.bdaddr, bdaddr);
4920 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004921
Johan Hedberg744cf192011-11-08 20:40:14 +02004922 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004923 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004924}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004925
4926static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4927{
4928 BT_DBG("%s status %u", hdev->name, status);
4929
4930 /* Clear the advertising mgmt setting if we failed to re-enable it */
4931 if (status) {
4932 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004933 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004934 }
4935}
4936
4937void mgmt_reenable_advertising(struct hci_dev *hdev)
4938{
4939 struct hci_request req;
4940
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004941 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004942 return;
4943
4944 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4945 return;
4946
4947 hci_req_init(&req, hdev);
4948 enable_advertising(&req);
4949
4950 /* If this fails we have no option but to let user space know
4951 * that we've disabled advertising.
4952 */
4953 if (hci_req_run(&req, adv_enable_complete) < 0) {
4954 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004955 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004956 }
4957}