blob: 143dd731998106abdedced6fb018828292bc3128 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Marcel Holtmannac4b7232013-10-10 14:54:16 -070033
34#include "smp.h"
Johan Hedberg03811012010-12-08 00:21:06 +020035
Johan Hedberg2da9c552012-02-17 14:39:28 +020036#define MGMT_VERSION 1
Marcel Holtmann9ab8cf32013-10-02 05:18:31 -070037#define MGMT_REVISION 4
Johan Hedberg02d98122010-12-13 21:07:04 +020038
Johan Hedberge70bb2e2012-02-13 16:59:33 +020039static const u16 mgmt_commands[] = {
40 MGMT_OP_READ_INDEX_LIST,
41 MGMT_OP_READ_INFO,
42 MGMT_OP_SET_POWERED,
43 MGMT_OP_SET_DISCOVERABLE,
44 MGMT_OP_SET_CONNECTABLE,
45 MGMT_OP_SET_FAST_CONNECTABLE,
46 MGMT_OP_SET_PAIRABLE,
47 MGMT_OP_SET_LINK_SECURITY,
48 MGMT_OP_SET_SSP,
49 MGMT_OP_SET_HS,
50 MGMT_OP_SET_LE,
51 MGMT_OP_SET_DEV_CLASS,
52 MGMT_OP_SET_LOCAL_NAME,
53 MGMT_OP_ADD_UUID,
54 MGMT_OP_REMOVE_UUID,
55 MGMT_OP_LOAD_LINK_KEYS,
56 MGMT_OP_LOAD_LONG_TERM_KEYS,
57 MGMT_OP_DISCONNECT,
58 MGMT_OP_GET_CONNECTIONS,
59 MGMT_OP_PIN_CODE_REPLY,
60 MGMT_OP_PIN_CODE_NEG_REPLY,
61 MGMT_OP_SET_IO_CAPABILITY,
62 MGMT_OP_PAIR_DEVICE,
63 MGMT_OP_CANCEL_PAIR_DEVICE,
64 MGMT_OP_UNPAIR_DEVICE,
65 MGMT_OP_USER_CONFIRM_REPLY,
66 MGMT_OP_USER_CONFIRM_NEG_REPLY,
67 MGMT_OP_USER_PASSKEY_REPLY,
68 MGMT_OP_USER_PASSKEY_NEG_REPLY,
69 MGMT_OP_READ_LOCAL_OOB_DATA,
70 MGMT_OP_ADD_REMOTE_OOB_DATA,
71 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
72 MGMT_OP_START_DISCOVERY,
73 MGMT_OP_STOP_DISCOVERY,
74 MGMT_OP_CONFIRM_NAME,
75 MGMT_OP_BLOCK_DEVICE,
76 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070077 MGMT_OP_SET_DEVICE_ID,
Johan Hedberg4375f102013-09-25 13:26:10 +030078 MGMT_OP_SET_ADVERTISING,
Johan Hedberg0663ca22013-10-02 13:43:14 +030079 MGMT_OP_SET_BREDR,
Marcel Holtmannd13eafc2013-10-02 04:41:30 -070080 MGMT_OP_SET_STATIC_ADDRESS,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020081};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300104 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200105};
106
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800107#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200108
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200109#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
110 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
111
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200112struct pending_cmd {
113 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200114 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200115 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100116 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300118 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200119};
120
Johan Hedbergca69b792011-11-11 18:10:00 +0200121/* HCI to MGMT error code conversion table */
122static u8 mgmt_status_table[] = {
123 MGMT_STATUS_SUCCESS,
124 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
125 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
126 MGMT_STATUS_FAILED, /* Hardware Failure */
127 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
128 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
129 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
130 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
131 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
132 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
133 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
134 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
135 MGMT_STATUS_BUSY, /* Command Disallowed */
136 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
137 MGMT_STATUS_REJECTED, /* Rejected Security */
138 MGMT_STATUS_REJECTED, /* Rejected Personal */
139 MGMT_STATUS_TIMEOUT, /* Host Timeout */
140 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
141 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
142 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
143 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
144 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
145 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
146 MGMT_STATUS_BUSY, /* Repeated Attempts */
147 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
148 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
149 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
150 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
151 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
152 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
154 MGMT_STATUS_FAILED, /* Unspecified Error */
155 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
156 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
157 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
158 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
159 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
160 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
161 MGMT_STATUS_FAILED, /* Unit Link Key Used */
162 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
163 MGMT_STATUS_TIMEOUT, /* Instant Passed */
164 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
165 MGMT_STATUS_FAILED, /* Transaction Collision */
166 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
167 MGMT_STATUS_REJECTED, /* QoS Rejected */
168 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
169 MGMT_STATUS_REJECTED, /* Insufficient Security */
170 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
171 MGMT_STATUS_BUSY, /* Role Switch Pending */
172 MGMT_STATUS_FAILED, /* Slot Violation */
173 MGMT_STATUS_FAILED, /* Role Switch Failed */
174 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
175 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
176 MGMT_STATUS_BUSY, /* Host Busy Pairing */
177 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
178 MGMT_STATUS_BUSY, /* Controller Busy */
179 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
180 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
181 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
182 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
183 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
184};
185
186static u8 mgmt_status(u8 hci_status)
187{
188 if (hci_status < ARRAY_SIZE(mgmt_status_table))
189 return mgmt_status_table[hci_status];
190
191 return MGMT_STATUS_FAILED;
192}
193
Szymon Janc4e51eae2011-02-25 19:05:48 +0100194static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200195{
196 struct sk_buff *skb;
197 struct mgmt_hdr *hdr;
198 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300199 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200200
Szymon Janc34eb5252011-02-28 14:10:08 +0100201 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200202
Andre Guedes790eff42012-06-07 19:05:46 -0300203 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200204 if (!skb)
205 return -ENOMEM;
206
207 hdr = (void *) skb_put(skb, sizeof(*hdr));
208
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530209 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100210 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200211 hdr->len = cpu_to_le16(sizeof(*ev));
212
213 ev = (void *) skb_put(skb, sizeof(*ev));
214 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200215 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200216
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300217 err = sock_queue_rcv_skb(sk, skb);
218 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200219 kfree_skb(skb);
220
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300221 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200222}
223
Johan Hedbergaee9b212012-02-18 15:07:59 +0200224static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300225 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200226{
227 struct sk_buff *skb;
228 struct mgmt_hdr *hdr;
229 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300230 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200231
232 BT_DBG("sock %p", sk);
233
Andre Guedes790eff42012-06-07 19:05:46 -0300234 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200235 if (!skb)
236 return -ENOMEM;
237
238 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200239
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530240 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100241 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200242 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200245 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200246 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100247
248 if (rp)
249 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200250
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300251 err = sock_queue_rcv_skb(sk, skb);
252 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200253 kfree_skb(skb);
254
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100255 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200256}
257
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300258static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
259 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200260{
261 struct mgmt_rp_read_version rp;
262
263 BT_DBG("sock %p", sk);
264
265 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200266 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200267
Johan Hedbergaee9b212012-02-18 15:07:59 +0200268 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300269 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200270}
271
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300272static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
273 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200274{
275 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200276 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
277 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200278 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200279 size_t rp_size;
280 int i, err;
281
282 BT_DBG("sock %p", sk);
283
284 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
285
286 rp = kmalloc(rp_size, GFP_KERNEL);
287 if (!rp)
288 return -ENOMEM;
289
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200290 rp->num_commands = __constant_cpu_to_le16(num_commands);
291 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200292
293 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
294 put_unaligned_le16(mgmt_commands[i], opcode);
295
296 for (i = 0; i < num_events; i++, opcode++)
297 put_unaligned_le16(mgmt_events[i], opcode);
298
Johan Hedbergaee9b212012-02-18 15:07:59 +0200299 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300300 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200301 kfree(rp);
302
303 return err;
304}
305
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300306static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
307 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200308{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200309 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200310 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200311 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300313 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200314
315 BT_DBG("sock %p", sk);
316
317 read_lock(&hci_dev_list_lock);
318
319 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300320 list_for_each_entry(d, &hci_dev_list, list) {
Marcel Holtmann1514b892013-10-06 08:25:01 -0700321 if (d->dev_type == HCI_BREDR)
322 count++;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200323 }
324
Johan Hedberga38528f2011-01-22 06:46:43 +0200325 rp_len = sizeof(*rp) + (2 * count);
326 rp = kmalloc(rp_len, GFP_ATOMIC);
327 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100328 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200329 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100330 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200331
Johan Hedberg476e44c2012-10-19 20:10:46 +0300332 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200333 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200334 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200335 continue;
336
Marcel Holtmann0736cfa2013-08-26 21:40:51 -0700337 if (test_bit(HCI_USER_CHANNEL, &d->dev_flags))
338 continue;
339
Marcel Holtmann1514b892013-10-06 08:25:01 -0700340 if (d->dev_type == HCI_BREDR) {
341 rp->index[count++] = cpu_to_le16(d->id);
342 BT_DBG("Added hci%u", d->id);
343 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200344 }
345
Johan Hedberg476e44c2012-10-19 20:10:46 +0300346 rp->num_controllers = cpu_to_le16(count);
347 rp_len = sizeof(*rp) + (2 * count);
348
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349 read_unlock(&hci_dev_list_lock);
350
Johan Hedbergaee9b212012-02-18 15:07:59 +0200351 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300352 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200353
Johan Hedberga38528f2011-01-22 06:46:43 +0200354 kfree(rp);
355
356 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200357}
358
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200359static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200360{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200361 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200362
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200363 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Andre Guedes9a1a1992012-07-24 15:03:48 -0300366 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200368
Andre Guedesed3fa312012-07-24 15:03:46 -0300369 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300370 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500371 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
372 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300373 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200374 settings |= MGMT_SETTING_BREDR;
375 settings |= MGMT_SETTING_LINK_SECURITY;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100376 settings |= MGMT_SETTING_HS;
Marcel Holtmann848566b2013-10-01 22:59:22 -0700377 }
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100378
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300379 if (lmp_le_capable(hdev)) {
Marcel Holtmann9d428202012-05-03 07:12:31 +0200380 settings |= MGMT_SETTING_LE;
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300381 settings |= MGMT_SETTING_ADVERTISING;
382 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200383
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200384 return settings;
385}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200386
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200387static u32 get_current_settings(struct hci_dev *hdev)
388{
389 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200390
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200391 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100392 settings |= MGMT_SETTING_POWERED;
393
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200394 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200395 settings |= MGMT_SETTING_CONNECTABLE;
396
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500397 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
398 settings |= MGMT_SETTING_FAST_CONNECTABLE;
399
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200400 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401 settings |= MGMT_SETTING_DISCOVERABLE;
402
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200403 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200404 settings |= MGMT_SETTING_PAIRABLE;
405
Johan Hedberg56f87902013-10-02 13:43:13 +0300406 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200407 settings |= MGMT_SETTING_BREDR;
408
Johan Hedberg06199cf2012-02-22 16:37:11 +0200409 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200411
Johan Hedberg47990ea2012-02-22 11:58:37 +0200412 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200414
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200415 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200417
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200418 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
419 settings |= MGMT_SETTING_HS;
420
Johan Hedbergf3d3444a2013-10-05 12:01:04 +0200421 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
Johan Hedbergeeca6f82013-09-25 13:26:09 +0300422 settings |= MGMT_SETTING_ADVERTISING;
423
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200424 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200425}
426
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300427#define PNP_INFO_SVCLASS_ID 0x1200
428
Johan Hedberg213202e2013-01-27 00:31:33 +0200429static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
430{
431 u8 *ptr = data, *uuids_start = NULL;
432 struct bt_uuid *uuid;
433
434 if (len < 4)
435 return ptr;
436
437 list_for_each_entry(uuid, &hdev->uuids, list) {
438 u16 uuid16;
439
440 if (uuid->size != 16)
441 continue;
442
443 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
444 if (uuid16 < 0x1100)
445 continue;
446
447 if (uuid16 == PNP_INFO_SVCLASS_ID)
448 continue;
449
450 if (!uuids_start) {
451 uuids_start = ptr;
452 uuids_start[0] = 1;
453 uuids_start[1] = EIR_UUID16_ALL;
454 ptr += 2;
455 }
456
457 /* Stop if not enough space to put next UUID */
458 if ((ptr - data) + sizeof(u16) > len) {
459 uuids_start[1] = EIR_UUID16_SOME;
460 break;
461 }
462
463 *ptr++ = (uuid16 & 0x00ff);
464 *ptr++ = (uuid16 & 0xff00) >> 8;
465 uuids_start[0] += sizeof(uuid16);
466 }
467
468 return ptr;
469}
470
Johan Hedbergcdf19632013-01-27 00:31:34 +0200471static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
472{
473 u8 *ptr = data, *uuids_start = NULL;
474 struct bt_uuid *uuid;
475
476 if (len < 6)
477 return ptr;
478
479 list_for_each_entry(uuid, &hdev->uuids, list) {
480 if (uuid->size != 32)
481 continue;
482
483 if (!uuids_start) {
484 uuids_start = ptr;
485 uuids_start[0] = 1;
486 uuids_start[1] = EIR_UUID32_ALL;
487 ptr += 2;
488 }
489
490 /* Stop if not enough space to put next UUID */
491 if ((ptr - data) + sizeof(u32) > len) {
492 uuids_start[1] = EIR_UUID32_SOME;
493 break;
494 }
495
496 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
497 ptr += sizeof(u32);
498 uuids_start[0] += sizeof(u32);
499 }
500
501 return ptr;
502}
503
Johan Hedbergc00d5752013-01-27 00:31:35 +0200504static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
505{
506 u8 *ptr = data, *uuids_start = NULL;
507 struct bt_uuid *uuid;
508
509 if (len < 18)
510 return ptr;
511
512 list_for_each_entry(uuid, &hdev->uuids, list) {
513 if (uuid->size != 128)
514 continue;
515
516 if (!uuids_start) {
517 uuids_start = ptr;
518 uuids_start[0] = 1;
519 uuids_start[1] = EIR_UUID128_ALL;
520 ptr += 2;
521 }
522
523 /* Stop if not enough space to put next UUID */
524 if ((ptr - data) + 16 > len) {
525 uuids_start[1] = EIR_UUID128_SOME;
526 break;
527 }
528
529 memcpy(ptr, uuid->uuid, 16);
530 ptr += 16;
531 uuids_start[0] += 16;
532 }
533
534 return ptr;
535}
536
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300537static void create_eir(struct hci_dev *hdev, u8 *data)
538{
539 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300540 size_t name_len;
541
542 name_len = strlen(hdev->dev_name);
543
544 if (name_len > 0) {
545 /* EIR Data type */
546 if (name_len > 48) {
547 name_len = 48;
548 ptr[1] = EIR_NAME_SHORT;
549 } else
550 ptr[1] = EIR_NAME_COMPLETE;
551
552 /* EIR Data length */
553 ptr[0] = name_len + 1;
554
555 memcpy(ptr + 2, hdev->dev_name, name_len);
556
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300557 ptr += (name_len + 2);
558 }
559
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100560 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700561 ptr[0] = 2;
562 ptr[1] = EIR_TX_POWER;
563 ptr[2] = (u8) hdev->inq_tx_power;
564
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700565 ptr += 3;
566 }
567
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700568 if (hdev->devid_source > 0) {
569 ptr[0] = 9;
570 ptr[1] = EIR_DEVICE_ID;
571
572 put_unaligned_le16(hdev->devid_source, ptr + 2);
573 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
574 put_unaligned_le16(hdev->devid_product, ptr + 6);
575 put_unaligned_le16(hdev->devid_version, ptr + 8);
576
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700577 ptr += 10;
578 }
579
Johan Hedberg213202e2013-01-27 00:31:33 +0200580 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200581 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200582 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300583}
584
Johan Hedberg890ea892013-03-15 17:06:52 -0500585static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300586{
Johan Hedberg890ea892013-03-15 17:06:52 -0500587 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300588 struct hci_cp_write_eir cp;
589
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200590 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500591 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200592
Johan Hedberg976eb202012-10-24 21:12:01 +0300593 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500594 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300595
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200596 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500597 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300598
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200599 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500600 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300601
602 memset(&cp, 0, sizeof(cp));
603
604 create_eir(hdev, cp.data);
605
606 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500607 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300608
609 memcpy(hdev->eir, cp.data, sizeof(cp.data));
610
Johan Hedberg890ea892013-03-15 17:06:52 -0500611 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300612}
613
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200614static u8 get_service_classes(struct hci_dev *hdev)
615{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300616 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200617 u8 val = 0;
618
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300619 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200620 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200621
622 return val;
623}
624
Johan Hedberg890ea892013-03-15 17:06:52 -0500625static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200626{
Johan Hedberg890ea892013-03-15 17:06:52 -0500627 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200628 u8 cod[3];
629
630 BT_DBG("%s", hdev->name);
631
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200632 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500633 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200634
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200635 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500636 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200637
638 cod[0] = hdev->minor_class;
639 cod[1] = hdev->major_class;
640 cod[2] = get_service_classes(hdev);
641
642 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500643 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200644
Johan Hedberg890ea892013-03-15 17:06:52 -0500645 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200646}
647
Johan Hedberg7d785252011-12-15 00:47:39 +0200648static void service_cache_off(struct work_struct *work)
649{
650 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300651 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500652 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200653
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200654 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200655 return;
656
Johan Hedberg890ea892013-03-15 17:06:52 -0500657 hci_req_init(&req, hdev);
658
Johan Hedberg7d785252011-12-15 00:47:39 +0200659 hci_dev_lock(hdev);
660
Johan Hedberg890ea892013-03-15 17:06:52 -0500661 update_eir(&req);
662 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200663
664 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500665
666 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200667}
668
Johan Hedberg6a919082012-02-28 06:17:26 +0200669static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200670{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200671 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200672 return;
673
Johan Hedberg4f87da82012-03-02 19:55:56 +0200674 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200675
Johan Hedberg4f87da82012-03-02 19:55:56 +0200676 /* Non-mgmt controlled devices get this bit set
677 * implicitly so that pairing works for them, however
678 * for mgmt we require user-space to explicitly enable
679 * it
680 */
681 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200682}
683
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200684static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300685 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200686{
687 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200688
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200689 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200690
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300691 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200692
Johan Hedberg03811012010-12-08 00:21:06 +0200693 memset(&rp, 0, sizeof(rp));
694
Johan Hedberg03811012010-12-08 00:21:06 +0200695 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200696
697 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200698 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200699
700 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
701 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
702
703 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200704
705 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200706 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200707
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300708 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200709
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200710 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300711 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200712}
713
714static void mgmt_pending_free(struct pending_cmd *cmd)
715{
716 sock_put(cmd->sk);
717 kfree(cmd->param);
718 kfree(cmd);
719}
720
721static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300722 struct hci_dev *hdev, void *data,
723 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200724{
725 struct pending_cmd *cmd;
726
Andre Guedes12b94562012-06-07 19:05:45 -0300727 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200728 if (!cmd)
729 return NULL;
730
731 cmd->opcode = opcode;
732 cmd->index = hdev->id;
733
Andre Guedes12b94562012-06-07 19:05:45 -0300734 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200735 if (!cmd->param) {
736 kfree(cmd);
737 return NULL;
738 }
739
740 if (data)
741 memcpy(cmd->param, data, len);
742
743 cmd->sk = sk;
744 sock_hold(sk);
745
746 list_add(&cmd->list, &hdev->mgmt_pending);
747
748 return cmd;
749}
750
751static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300752 void (*cb)(struct pending_cmd *cmd,
753 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300754 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200755{
Andre Guedesa3d09352013-02-01 11:21:30 -0300756 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200757
Andre Guedesa3d09352013-02-01 11:21:30 -0300758 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200759 if (opcode > 0 && cmd->opcode != opcode)
760 continue;
761
762 cb(cmd, data);
763 }
764}
765
766static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
767{
768 struct pending_cmd *cmd;
769
770 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
771 if (cmd->opcode == opcode)
772 return cmd;
773 }
774
775 return NULL;
776}
777
778static void mgmt_pending_remove(struct pending_cmd *cmd)
779{
780 list_del(&cmd->list);
781 mgmt_pending_free(cmd);
782}
783
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200784static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200785{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200786 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200787
Johan Hedbergaee9b212012-02-18 15:07:59 +0200788 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300789 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200790}
791
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200792static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300793 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200794{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300795 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200796 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200797 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200798
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200799 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200800
Johan Hedberga7e80f22013-01-09 16:05:19 +0200801 if (cp->val != 0x00 && cp->val != 0x01)
802 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
803 MGMT_STATUS_INVALID_PARAMS);
804
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300805 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200806
Johan Hedberg87b95ba2013-09-25 13:26:06 +0300807 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
808 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
809 MGMT_STATUS_BUSY);
810 goto failed;
811 }
812
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100813 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
814 cancel_delayed_work(&hdev->power_off);
815
816 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200817 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
818 data, len);
819 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100820 goto failed;
821 }
822 }
823
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200824 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200825 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200826 goto failed;
827 }
828
Johan Hedberg03811012010-12-08 00:21:06 +0200829 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
830 if (!cmd) {
831 err = -ENOMEM;
832 goto failed;
833 }
834
835 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200836 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200837 else
Johan Hedberg19202572013-01-14 22:33:51 +0200838 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200839
840 err = 0;
841
842failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300843 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200844 return err;
845}
846
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300847static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
848 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200849{
850 struct sk_buff *skb;
851 struct mgmt_hdr *hdr;
852
Andre Guedes790eff42012-06-07 19:05:46 -0300853 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200854 if (!skb)
855 return -ENOMEM;
856
857 hdr = (void *) skb_put(skb, sizeof(*hdr));
858 hdr->opcode = cpu_to_le16(event);
859 if (hdev)
860 hdr->index = cpu_to_le16(hdev->id);
861 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530862 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200863 hdr->len = cpu_to_le16(data_len);
864
865 if (data)
866 memcpy(skb_put(skb, data_len), data, data_len);
867
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100868 /* Time stamp */
869 __net_timestamp(skb);
870
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200871 hci_send_to_control(skb, skip_sk);
872 kfree_skb(skb);
873
874 return 0;
875}
876
877static int new_settings(struct hci_dev *hdev, struct sock *skip)
878{
879 __le32 ev;
880
881 ev = cpu_to_le32(get_current_settings(hdev));
882
883 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
884}
885
Johan Hedbergbd99abd2013-09-25 13:26:07 +0300886struct cmd_lookup {
887 struct sock *sk;
888 struct hci_dev *hdev;
889 u8 mgmt_status;
890};
891
892static void settings_rsp(struct pending_cmd *cmd, void *data)
893{
894 struct cmd_lookup *match = data;
895
896 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
897
898 list_del(&cmd->list);
899
900 if (match->sk == NULL) {
901 match->sk = cmd->sk;
902 sock_hold(match->sk);
903 }
904
905 mgmt_pending_free(cmd);
906}
907
908static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
909{
910 u8 *status = data;
911
912 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
913 mgmt_pending_remove(cmd);
914}
915
Johan Hedberge6fe7982013-10-02 15:45:22 +0300916static u8 mgmt_bredr_support(struct hci_dev *hdev)
917{
918 if (!lmp_bredr_capable(hdev))
919 return MGMT_STATUS_NOT_SUPPORTED;
920 else if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
921 return MGMT_STATUS_REJECTED;
922 else
923 return MGMT_STATUS_SUCCESS;
924}
925
926static u8 mgmt_le_support(struct hci_dev *hdev)
927{
928 if (!lmp_le_capable(hdev))
929 return MGMT_STATUS_NOT_SUPPORTED;
930 else if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
931 return MGMT_STATUS_REJECTED;
932 else
933 return MGMT_STATUS_SUCCESS;
934}
935
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200936static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300937 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200938{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300939 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200940 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200941 u16 timeout;
Johan Hedberge6fe7982013-10-02 15:45:22 +0300942 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +0200943 int err;
944
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200945 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200946
Johan Hedberge6fe7982013-10-02 15:45:22 +0300947 status = mgmt_bredr_support(hdev);
948 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +0300949 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +0300950 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +0300951
Johan Hedberga7e80f22013-01-09 16:05:19 +0200952 if (cp->val != 0x00 && cp->val != 0x01)
953 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
954 MGMT_STATUS_INVALID_PARAMS);
955
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700956 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100957 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200958 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300959 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200960
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300961 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200962
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200963 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200964 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300965 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200966 goto failed;
967 }
968
969 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300970 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200971 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300972 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200973 goto failed;
974 }
975
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200976 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200977 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300978 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200979 goto failed;
980 }
981
982 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200983 bool changed = false;
984
985 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
986 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
987 changed = true;
988 }
989
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200990 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200991 if (err < 0)
992 goto failed;
993
994 if (changed)
995 err = new_settings(hdev, sk);
996
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200997 goto failed;
998 }
999
1000 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +01001001 if (hdev->discov_timeout > 0) {
1002 cancel_delayed_work(&hdev->discov_off);
1003 hdev->discov_timeout = 0;
1004 }
1005
1006 if (cp->val && timeout > 0) {
1007 hdev->discov_timeout = timeout;
1008 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
1009 msecs_to_jiffies(hdev->discov_timeout * 1000));
1010 }
1011
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001012 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02001013 goto failed;
1014 }
1015
1016 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
1017 if (!cmd) {
1018 err = -ENOMEM;
1019 goto failed;
1020 }
1021
1022 scan = SCAN_PAGE;
1023
1024 if (cp->val)
1025 scan |= SCAN_INQUIRY;
1026 else
1027 cancel_delayed_work(&hdev->discov_off);
1028
1029 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1030 if (err < 0)
1031 mgmt_pending_remove(cmd);
1032
Johan Hedberg03811012010-12-08 00:21:06 +02001033 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001034 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +02001035
1036failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001037 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001038 return err;
1039}
1040
Johan Hedberg406d7802013-03-15 17:07:09 -05001041static void write_fast_connectable(struct hci_request *req, bool enable)
1042{
Johan Hedbergbd98b992013-03-15 17:07:13 -05001043 struct hci_dev *hdev = req->hdev;
Johan Hedberg406d7802013-03-15 17:07:09 -05001044 struct hci_cp_write_page_scan_activity acp;
1045 u8 type;
1046
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001047 if (hdev->hci_ver < BLUETOOTH_VER_1_2)
1048 return;
1049
Johan Hedberg406d7802013-03-15 17:07:09 -05001050 if (enable) {
1051 type = PAGE_SCAN_TYPE_INTERLACED;
1052
1053 /* 160 msec page scan interval */
1054 acp.interval = __constant_cpu_to_le16(0x0100);
1055 } else {
1056 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1057
1058 /* default 1.28 sec page scan */
1059 acp.interval = __constant_cpu_to_le16(0x0800);
1060 }
1061
1062 acp.window = __constant_cpu_to_le16(0x0012);
1063
Johan Hedbergbd98b992013-03-15 17:07:13 -05001064 if (__cpu_to_le16(hdev->page_scan_interval) != acp.interval ||
1065 __cpu_to_le16(hdev->page_scan_window) != acp.window)
1066 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1067 sizeof(acp), &acp);
1068
1069 if (hdev->page_scan_type != type)
1070 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
Johan Hedberg406d7802013-03-15 17:07:09 -05001071}
1072
Johan Hedberg2b76f452013-03-15 17:07:04 -05001073static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1074{
1075 struct pending_cmd *cmd;
1076
1077 BT_DBG("status 0x%02x", status);
1078
1079 hci_dev_lock(hdev);
1080
1081 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1082 if (!cmd)
1083 goto unlock;
1084
1085 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1086
1087 mgmt_pending_remove(cmd);
1088
1089unlock:
1090 hci_dev_unlock(hdev);
1091}
1092
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001093static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001094 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001095{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001096 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001097 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001098 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001099 u8 scan, status;
Johan Hedberg03811012010-12-08 00:21:06 +02001100 int err;
1101
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001102 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001103
Johan Hedberge6fe7982013-10-02 15:45:22 +03001104 status = mgmt_bredr_support(hdev);
1105 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001106 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001107 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001108
Johan Hedberga7e80f22013-01-09 16:05:19 +02001109 if (cp->val != 0x00 && cp->val != 0x01)
1110 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1111 MGMT_STATUS_INVALID_PARAMS);
1112
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001113 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001114
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001115 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001116 bool changed = false;
1117
1118 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1119 changed = true;
1120
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001121 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001122 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001123 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001124 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1125 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1126 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001127
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001128 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001129 if (err < 0)
1130 goto failed;
1131
1132 if (changed)
1133 err = new_settings(hdev, sk);
1134
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001135 goto failed;
1136 }
1137
1138 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001139 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001140 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001141 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001142 goto failed;
1143 }
1144
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001145 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001146 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001147 goto failed;
1148 }
1149
1150 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1151 if (!cmd) {
1152 err = -ENOMEM;
1153 goto failed;
1154 }
1155
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001156 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001157 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001158 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001159 scan = 0;
1160
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001161 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001162 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001163 cancel_delayed_work(&hdev->discov_off);
1164 }
1165
Johan Hedberg2b76f452013-03-15 17:07:04 -05001166 hci_req_init(&req, hdev);
1167
1168 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1169
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05001170 /* If we're going from non-connectable to connectable or
1171 * vice-versa when fast connectable is enabled ensure that fast
1172 * connectable gets disabled. write_fast_connectable won't do
1173 * anything if the page scan parameters are already what they
1174 * should be.
1175 */
1176 if (cp->val || test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
Johan Hedberge36a3762013-03-15 17:07:10 -05001177 write_fast_connectable(&req, false);
1178
Johan Hedberg2b76f452013-03-15 17:07:04 -05001179 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001180 if (err < 0)
1181 mgmt_pending_remove(cmd);
1182
1183failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001184 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001185 return err;
1186}
1187
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001188static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001189 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001190{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001191 struct mgmt_mode *cp = data;
Marcel Holtmann55594352013-10-06 16:11:57 -07001192 bool changed;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001193 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001195 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001196
Johan Hedberga7e80f22013-01-09 16:05:19 +02001197 if (cp->val != 0x00 && cp->val != 0x01)
1198 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1199 MGMT_STATUS_INVALID_PARAMS);
1200
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001201 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001202
1203 if (cp->val)
Marcel Holtmann55594352013-10-06 16:11:57 -07001204 changed = !test_and_set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001205 else
Marcel Holtmann55594352013-10-06 16:11:57 -07001206 changed = test_and_clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001207
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001208 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001209 if (err < 0)
Marcel Holtmann55594352013-10-06 16:11:57 -07001210 goto unlock;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001211
Marcel Holtmann55594352013-10-06 16:11:57 -07001212 if (changed)
1213 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001214
Marcel Holtmann55594352013-10-06 16:11:57 -07001215unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001216 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001217 return err;
1218}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001219
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001220static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1221 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001222{
1223 struct mgmt_mode *cp = data;
1224 struct pending_cmd *cmd;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001225 u8 val, status;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001226 int err;
1227
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001228 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001229
Johan Hedberge6fe7982013-10-02 15:45:22 +03001230 status = mgmt_bredr_support(hdev);
1231 if (status)
Johan Hedberg33c525c2012-10-24 21:11:58 +03001232 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03001233 status);
Johan Hedberg33c525c2012-10-24 21:11:58 +03001234
Johan Hedberga7e80f22013-01-09 16:05:19 +02001235 if (cp->val != 0x00 && cp->val != 0x01)
1236 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1237 MGMT_STATUS_INVALID_PARAMS);
1238
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001239 hci_dev_lock(hdev);
1240
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001241 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001242 bool changed = false;
1243
1244 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001245 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001246 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1247 changed = true;
1248 }
1249
1250 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1251 if (err < 0)
1252 goto failed;
1253
1254 if (changed)
1255 err = new_settings(hdev, sk);
1256
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001257 goto failed;
1258 }
1259
1260 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001261 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001262 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001263 goto failed;
1264 }
1265
1266 val = !!cp->val;
1267
1268 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1269 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1270 goto failed;
1271 }
1272
1273 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1274 if (!cmd) {
1275 err = -ENOMEM;
1276 goto failed;
1277 }
1278
1279 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1280 if (err < 0) {
1281 mgmt_pending_remove(cmd);
1282 goto failed;
1283 }
1284
1285failed:
1286 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001287 return err;
1288}
1289
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001290static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001291{
1292 struct mgmt_mode *cp = data;
1293 struct pending_cmd *cmd;
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001294 u8 status;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001295 int err;
1296
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001297 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001298
Marcel Holtmanncdba5282013-10-02 21:31:52 -07001299 status = mgmt_bredr_support(hdev);
1300 if (status)
1301 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP, status);
1302
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001303 if (!lmp_ssp_capable(hdev))
1304 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1305 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001306
Johan Hedberga7e80f22013-01-09 16:05:19 +02001307 if (cp->val != 0x00 && cp->val != 0x01)
1308 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1309 MGMT_STATUS_INVALID_PARAMS);
1310
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001311 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001312
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001313 if (!hdev_is_powered(hdev)) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001314 bool changed;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001315
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001316 if (cp->val) {
1317 changed = !test_and_set_bit(HCI_SSP_ENABLED,
1318 &hdev->dev_flags);
1319 } else {
1320 changed = test_and_clear_bit(HCI_SSP_ENABLED,
1321 &hdev->dev_flags);
1322 if (!changed)
1323 changed = test_and_clear_bit(HCI_HS_ENABLED,
1324 &hdev->dev_flags);
1325 else
1326 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001327 }
1328
1329 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1330 if (err < 0)
1331 goto failed;
1332
1333 if (changed)
1334 err = new_settings(hdev, sk);
1335
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001336 goto failed;
1337 }
1338
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001339 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev) ||
1340 mgmt_pending_find(MGMT_OP_SET_HS, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001341 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1342 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001343 goto failed;
1344 }
1345
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001346 if (!!cp->val == test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001347 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1348 goto failed;
1349 }
1350
1351 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1352 if (!cmd) {
1353 err = -ENOMEM;
1354 goto failed;
1355 }
1356
Marcel Holtmann72ef0c12013-10-10 03:08:10 -07001357 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &cp->val);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001358 if (err < 0) {
1359 mgmt_pending_remove(cmd);
1360 goto failed;
1361 }
1362
1363failed:
1364 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001365 return err;
1366}
1367
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001368static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001369{
1370 struct mgmt_mode *cp = data;
Marcel Holtmannee392692013-10-01 22:59:23 -07001371 bool changed;
Johan Hedberge6fe7982013-10-02 15:45:22 +03001372 u8 status;
Marcel Holtmannee392692013-10-01 22:59:23 -07001373 int err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001374
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001375 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001376
Johan Hedberge6fe7982013-10-02 15:45:22 +03001377 status = mgmt_bredr_support(hdev);
1378 if (status)
1379 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS, status);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001380
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07001381 if (!lmp_ssp_capable(hdev))
1382 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1383 MGMT_STATUS_NOT_SUPPORTED);
1384
1385 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
1386 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1387 MGMT_STATUS_REJECTED);
1388
Johan Hedberga7e80f22013-01-09 16:05:19 +02001389 if (cp->val != 0x00 && cp->val != 0x01)
1390 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1391 MGMT_STATUS_INVALID_PARAMS);
1392
Marcel Holtmannee392692013-10-01 22:59:23 -07001393 hci_dev_lock(hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001394
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001395 if (cp->val) {
Marcel Holtmannee392692013-10-01 22:59:23 -07001396 changed = !test_and_set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001397 } else {
1398 if (hdev_is_powered(hdev)) {
1399 err = cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1400 MGMT_STATUS_REJECTED);
1401 goto unlock;
1402 }
1403
Marcel Holtmannee392692013-10-01 22:59:23 -07001404 changed = test_and_clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Marcel Holtmanna0cdf9602013-10-02 00:27:02 -07001405 }
Marcel Holtmannee392692013-10-01 22:59:23 -07001406
1407 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1408 if (err < 0)
1409 goto unlock;
1410
1411 if (changed)
1412 err = new_settings(hdev, sk);
1413
1414unlock:
1415 hci_dev_unlock(hdev);
1416 return err;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001417}
1418
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001419static void enable_advertising(struct hci_request *req)
1420{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001421 struct hci_dev *hdev = req->hdev;
1422 struct hci_cp_le_set_adv_param cp;
1423 u8 enable = 0x01;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001424
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001425 memset(&cp, 0, sizeof(cp));
1426 cp.min_interval = __constant_cpu_to_le16(0x0800);
1427 cp.max_interval = __constant_cpu_to_le16(0x0800);
1428 cp.type = LE_ADV_IND;
1429 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
1430 cp.own_address_type = ADDR_LE_DEV_PUBLIC;
1431 else
1432 cp.own_address_type = ADDR_LE_DEV_RANDOM;
1433 cp.channel_map = 0x07;
1434
1435 hci_req_add(req, HCI_OP_LE_SET_ADV_PARAM, sizeof(cp), &cp);
1436
1437 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001438}
1439
1440static void disable_advertising(struct hci_request *req)
1441{
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001442 u8 enable = 0x00;
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001443
Marcel Holtmannb4faf3002013-10-06 03:17:56 -07001444 hci_req_add(req, HCI_OP_LE_SET_ADV_ENABLE, sizeof(enable), &enable);
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001445}
1446
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001447static void le_enable_complete(struct hci_dev *hdev, u8 status)
1448{
1449 struct cmd_lookup match = { NULL, hdev };
1450
1451 if (status) {
1452 u8 mgmt_err = mgmt_status(status);
1453
1454 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
1455 &mgmt_err);
1456 return;
1457 }
1458
1459 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
1460
1461 new_settings(hdev, match.sk);
1462
1463 if (match.sk)
1464 sock_put(match.sk);
1465}
1466
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001467static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001468{
1469 struct mgmt_mode *cp = data;
1470 struct hci_cp_write_le_host_supported hci_cp;
1471 struct pending_cmd *cmd;
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001472 struct hci_request req;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001473 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001474 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001475
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001476 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001477
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001478 if (!lmp_le_capable(hdev))
1479 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1480 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001481
Johan Hedberga7e80f22013-01-09 16:05:19 +02001482 if (cp->val != 0x00 && cp->val != 0x01)
1483 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1484 MGMT_STATUS_INVALID_PARAMS);
1485
Johan Hedbergc73eee92013-04-19 18:35:21 +03001486 /* LE-only devices do not allow toggling LE on/off */
Johan Hedberg56f87902013-10-02 13:43:13 +03001487 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
Johan Hedbergc73eee92013-04-19 18:35:21 +03001488 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1489 MGMT_STATUS_REJECTED);
1490
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001491 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001492
1493 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001494 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001495
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001496 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001497 bool changed = false;
1498
1499 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1500 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1501 changed = true;
1502 }
1503
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02001504 if (!val && test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
1505 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001506 changed = true;
1507 }
1508
Johan Hedberg06199cf2012-02-22 16:37:11 +02001509 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1510 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001511 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001512
1513 if (changed)
1514 err = new_settings(hdev, sk);
1515
Johan Hedberg1de028c2012-02-29 19:55:35 -08001516 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001517 }
1518
Johan Hedberg4375f102013-09-25 13:26:10 +03001519 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev) ||
1520 mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001521 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001522 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001523 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001524 }
1525
1526 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1527 if (!cmd) {
1528 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001529 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001530 }
1531
1532 memset(&hci_cp, 0, sizeof(hci_cp));
1533
1534 if (val) {
1535 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001536 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001537 }
1538
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001539 hci_req_init(&req, hdev);
1540
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07001541 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags) && !val)
1542 disable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03001543
Johan Hedberg416a4ae2013-09-25 13:26:08 +03001544 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1545 &hci_cp);
1546
1547 err = hci_req_run(&req, le_enable_complete);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301548 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001549 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001550
Johan Hedberg1de028c2012-02-29 19:55:35 -08001551unlock:
1552 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001553 return err;
1554}
1555
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001556/* This is a helper function to test for pending mgmt commands that can
1557 * cause CoD or EIR HCI commands. We can only allow one such pending
1558 * mgmt command at a time since otherwise we cannot easily track what
1559 * the current values are, will be, and based on that calculate if a new
1560 * HCI command needs to be sent and if yes with what value.
1561 */
1562static bool pending_eir_or_class(struct hci_dev *hdev)
1563{
1564 struct pending_cmd *cmd;
1565
1566 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1567 switch (cmd->opcode) {
1568 case MGMT_OP_ADD_UUID:
1569 case MGMT_OP_REMOVE_UUID:
1570 case MGMT_OP_SET_DEV_CLASS:
1571 case MGMT_OP_SET_POWERED:
1572 return true;
1573 }
1574 }
1575
1576 return false;
1577}
1578
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001579static const u8 bluetooth_base_uuid[] = {
1580 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1581 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1582};
1583
1584static u8 get_uuid_size(const u8 *uuid)
1585{
1586 u32 val;
1587
1588 if (memcmp(uuid, bluetooth_base_uuid, 12))
1589 return 128;
1590
1591 val = get_unaligned_le32(&uuid[12]);
1592 if (val > 0xffff)
1593 return 32;
1594
1595 return 16;
1596}
1597
Johan Hedberg92da6092013-03-15 17:06:55 -05001598static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1599{
1600 struct pending_cmd *cmd;
1601
1602 hci_dev_lock(hdev);
1603
1604 cmd = mgmt_pending_find(mgmt_op, hdev);
1605 if (!cmd)
1606 goto unlock;
1607
1608 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1609 hdev->dev_class, 3);
1610
1611 mgmt_pending_remove(cmd);
1612
1613unlock:
1614 hci_dev_unlock(hdev);
1615}
1616
1617static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1618{
1619 BT_DBG("status 0x%02x", status);
1620
1621 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1622}
1623
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001624static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001625{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001626 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001627 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001628 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001629 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001630 int err;
1631
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001632 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001633
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001634 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001635
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001636 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001637 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001638 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001639 goto failed;
1640 }
1641
Andre Guedes92c4c202012-06-07 19:05:44 -03001642 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001643 if (!uuid) {
1644 err = -ENOMEM;
1645 goto failed;
1646 }
1647
1648 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001649 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001650 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001651
Johan Hedbergde66aa62013-01-27 00:31:27 +02001652 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001653
Johan Hedberg890ea892013-03-15 17:06:52 -05001654 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001655
Johan Hedberg890ea892013-03-15 17:06:52 -05001656 update_class(&req);
1657 update_eir(&req);
1658
Johan Hedberg92da6092013-03-15 17:06:55 -05001659 err = hci_req_run(&req, add_uuid_complete);
1660 if (err < 0) {
1661 if (err != -ENODATA)
1662 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001663
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001664 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001665 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001666 goto failed;
1667 }
1668
1669 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001670 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001671 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001672 goto failed;
1673 }
1674
1675 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001676
1677failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001678 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001679 return err;
1680}
1681
Johan Hedberg24b78d02012-02-23 23:24:30 +02001682static bool enable_service_cache(struct hci_dev *hdev)
1683{
1684 if (!hdev_is_powered(hdev))
1685 return false;
1686
1687 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001688 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1689 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001690 return true;
1691 }
1692
1693 return false;
1694}
1695
Johan Hedberg92da6092013-03-15 17:06:55 -05001696static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1697{
1698 BT_DBG("status 0x%02x", status);
1699
1700 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1701}
1702
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001703static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001704 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001705{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001706 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001707 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001708 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001709 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg890ea892013-03-15 17:06:52 -05001710 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001711 int err, found;
1712
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001713 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001715 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001716
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001717 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001718 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001719 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001720 goto unlock;
1721 }
1722
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001723 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1724 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001725
Johan Hedberg24b78d02012-02-23 23:24:30 +02001726 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001727 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001728 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001729 goto unlock;
1730 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001731
Johan Hedberg9246a862012-02-23 21:33:16 +02001732 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001733 }
1734
1735 found = 0;
1736
Johan Hedberg056341c2013-01-27 00:31:30 +02001737 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001738 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1739 continue;
1740
1741 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001742 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001743 found++;
1744 }
1745
1746 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001747 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001748 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001749 goto unlock;
1750 }
1751
Johan Hedberg9246a862012-02-23 21:33:16 +02001752update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001753 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001754
Johan Hedberg890ea892013-03-15 17:06:52 -05001755 update_class(&req);
1756 update_eir(&req);
1757
Johan Hedberg92da6092013-03-15 17:06:55 -05001758 err = hci_req_run(&req, remove_uuid_complete);
1759 if (err < 0) {
1760 if (err != -ENODATA)
1761 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001762
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001763 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001764 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001765 goto unlock;
1766 }
1767
1768 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001769 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001770 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001771 goto unlock;
1772 }
1773
1774 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001775
1776unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001777 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001778 return err;
1779}
1780
Johan Hedberg92da6092013-03-15 17:06:55 -05001781static void set_class_complete(struct hci_dev *hdev, u8 status)
1782{
1783 BT_DBG("status 0x%02x", status);
1784
1785 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1786}
1787
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001788static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001789 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001790{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001791 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001792 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001793 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001794 int err;
1795
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001796 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001797
Marcel Holtmann6203fc92013-10-02 23:37:29 -07001798 if (!lmp_bredr_capable(hdev))
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001799 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1800 MGMT_STATUS_NOT_SUPPORTED);
1801
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001802 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001803
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001804 if (pending_eir_or_class(hdev)) {
1805 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1806 MGMT_STATUS_BUSY);
1807 goto unlock;
1808 }
1809
1810 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1811 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1812 MGMT_STATUS_INVALID_PARAMS);
1813 goto unlock;
1814 }
1815
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001816 hdev->major_class = cp->major;
1817 hdev->minor_class = cp->minor;
1818
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001819 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001820 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001821 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001822 goto unlock;
1823 }
1824
Johan Hedberg890ea892013-03-15 17:06:52 -05001825 hci_req_init(&req, hdev);
1826
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001827 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001828 hci_dev_unlock(hdev);
1829 cancel_delayed_work_sync(&hdev->service_cache);
1830 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001831 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001832 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001833
Johan Hedberg890ea892013-03-15 17:06:52 -05001834 update_class(&req);
1835
Johan Hedberg92da6092013-03-15 17:06:55 -05001836 err = hci_req_run(&req, set_class_complete);
1837 if (err < 0) {
1838 if (err != -ENODATA)
1839 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001840
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001841 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001842 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001843 goto unlock;
1844 }
1845
1846 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001847 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001848 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001849 goto unlock;
1850 }
1851
1852 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001853
Johan Hedbergb5235a62012-02-21 14:32:24 +02001854unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001855 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001856 return err;
1857}
1858
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001859static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001860 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001861{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001862 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001863 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001864 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001865
Marcel Holtmann9060d5c2013-10-02 21:16:07 -07001866 BT_DBG("request for %s", hdev->name);
1867
1868 if (!lmp_bredr_capable(hdev))
1869 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1870 MGMT_STATUS_NOT_SUPPORTED);
1871
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001872 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001873
Johan Hedberg86742e12011-11-07 23:13:38 +02001874 expected_len = sizeof(*cp) + key_count *
1875 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001876 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001877 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001878 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001879 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001880 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001881 }
1882
Johan Hedberg4ae143012013-01-20 14:27:13 +02001883 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1884 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1885 MGMT_STATUS_INVALID_PARAMS);
1886
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001887 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001888 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001889
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001890 for (i = 0; i < key_count; i++) {
1891 struct mgmt_link_key_info *key = &cp->keys[i];
1892
1893 if (key->addr.type != BDADDR_BREDR)
1894 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1895 MGMT_STATUS_INVALID_PARAMS);
1896 }
1897
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001898 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001899
1900 hci_link_keys_clear(hdev);
1901
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001902 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001903 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001904 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001905 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001906
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001907 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001908 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001909
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001910 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001911 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001912 }
1913
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001914 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001915
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001916 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001917
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001918 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001919}
1920
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001921static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001922 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001923{
1924 struct mgmt_ev_device_unpaired ev;
1925
1926 bacpy(&ev.addr.bdaddr, bdaddr);
1927 ev.addr.type = addr_type;
1928
1929 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001930 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001931}
1932
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001933static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001934 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001935{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001936 struct mgmt_cp_unpair_device *cp = data;
1937 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001938 struct hci_cp_disconnect dc;
1939 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001940 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001941 int err;
1942
Johan Hedberga8a1d192011-11-10 15:54:38 +02001943 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001944 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1945 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001946
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001947 if (!bdaddr_type_is_valid(cp->addr.type))
1948 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1949 MGMT_STATUS_INVALID_PARAMS,
1950 &rp, sizeof(rp));
1951
Johan Hedberg118da702013-01-20 14:27:20 +02001952 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1953 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1954 MGMT_STATUS_INVALID_PARAMS,
1955 &rp, sizeof(rp));
1956
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001957 hci_dev_lock(hdev);
1958
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001959 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001960 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001961 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001962 goto unlock;
1963 }
1964
Andre Guedes591f47f2012-04-24 21:02:49 -03001965 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001966 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1967 else
1968 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001969
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001970 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001971 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001972 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001973 goto unlock;
1974 }
1975
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001976 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001977 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001978 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001979 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001980 else
1981 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001982 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001983 } else {
1984 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001985 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001986
Johan Hedberga8a1d192011-11-10 15:54:38 +02001987 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001988 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001989 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001990 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001991 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001992 }
1993
Johan Hedberg124f6e32012-02-09 13:50:12 +02001994 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001995 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001996 if (!cmd) {
1997 err = -ENOMEM;
1998 goto unlock;
1999 }
2000
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002001 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002002 dc.reason = 0x13; /* Remote User Terminated Connection */
2003 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2004 if (err < 0)
2005 mgmt_pending_remove(cmd);
2006
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002007unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002008 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002009 return err;
2010}
2011
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002012static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002013 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002014{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002015 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02002016 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002017 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03002018 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002019 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002020 int err;
2021
2022 BT_DBG("");
2023
Johan Hedberg06a63b12013-01-20 14:27:21 +02002024 memset(&rp, 0, sizeof(rp));
2025 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2026 rp.addr.type = cp->addr.type;
2027
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002028 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02002029 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2030 MGMT_STATUS_INVALID_PARAMS,
2031 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002032
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002033 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002034
2035 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002036 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2037 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002038 goto failed;
2039 }
2040
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002041 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002042 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2043 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002044 goto failed;
2045 }
2046
Andre Guedes591f47f2012-04-24 21:02:49 -03002047 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03002048 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
2049 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02002050 else
2051 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03002052
Vishal Agarwalf9607272012-06-13 05:32:43 +05302053 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02002054 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
2055 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002056 goto failed;
2057 }
2058
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002059 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002060 if (!cmd) {
2061 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002062 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002063 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02002064
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002065 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03002066 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002067
2068 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
2069 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002070 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002071
2072failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002073 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002074 return err;
2075}
2076
Andre Guedes57c14772012-04-24 21:02:50 -03002077static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002078{
2079 switch (link_type) {
2080 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02002081 switch (addr_type) {
2082 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03002083 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03002084
Johan Hedberg48264f02011-11-09 13:58:58 +02002085 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002086 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002087 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02002088 }
Andre Guedes0ed09142012-04-03 08:46:54 -03002089
Johan Hedberg4c659c32011-11-07 23:13:39 +02002090 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03002091 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03002092 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002093 }
2094}
2095
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002096static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
2097 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02002098{
Johan Hedberg2784eb42011-01-21 13:56:35 +02002099 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002100 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02002101 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002102 int err;
2103 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002104
2105 BT_DBG("");
2106
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002107 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002108
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002109 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002110 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002111 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002112 goto unlock;
2113 }
2114
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002115 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02002116 list_for_each_entry(c, &hdev->conn_hash.list, list) {
2117 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002118 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002119 }
2120
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002121 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03002122 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02002123 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02002124 err = -ENOMEM;
2125 goto unlock;
2126 }
2127
Johan Hedberg2784eb42011-01-21 13:56:35 +02002128 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002129 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02002130 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
2131 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02002132 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002133 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03002134 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02002135 continue;
2136 i++;
2137 }
2138
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002139 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02002140
Johan Hedberg4c659c32011-11-07 23:13:39 +02002141 /* Recalculate length in case of filtered SCO connections, etc */
2142 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02002143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002144 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002145 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002146
Johan Hedberga38528f2011-01-22 06:46:43 +02002147 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002148
2149unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002150 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002151 return err;
2152}
2153
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002154static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002155 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002156{
2157 struct pending_cmd *cmd;
2158 int err;
2159
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002160 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002161 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002162 if (!cmd)
2163 return -ENOMEM;
2164
Johan Hedbergd8457692012-02-17 14:24:57 +02002165 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002166 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002167 if (err < 0)
2168 mgmt_pending_remove(cmd);
2169
2170 return err;
2171}
2172
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002173static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002174 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002175{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002176 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002177 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002178 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002179 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002180 int err;
2181
2182 BT_DBG("");
2183
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002184 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002185
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002186 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002187 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002188 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002189 goto failed;
2190 }
2191
Johan Hedbergd8457692012-02-17 14:24:57 +02002192 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002193 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002194 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002195 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002196 goto failed;
2197 }
2198
2199 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002200 struct mgmt_cp_pin_code_neg_reply ncp;
2201
2202 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002203
2204 BT_ERR("PIN code is not 16 bytes long");
2205
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002206 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002207 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002208 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002209 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002210
2211 goto failed;
2212 }
2213
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002214 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002215 if (!cmd) {
2216 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002217 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002218 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002219
Johan Hedbergd8457692012-02-17 14:24:57 +02002220 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002221 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002222 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002223
2224 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2225 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002226 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002227
2228failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002229 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002230 return err;
2231}
2232
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002233static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2234 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002235{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002236 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002237
2238 BT_DBG("");
2239
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002240 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002241
2242 hdev->io_capability = cp->io_capability;
2243
2244 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002245 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002246
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002247 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002248
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002249 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2250 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002251}
2252
Gustavo Padovan6039aa72012-05-23 04:04:18 -03002253static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002254{
2255 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002256 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002257
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002258 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002259 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2260 continue;
2261
Johan Hedberge9a416b2011-02-19 12:05:56 -03002262 if (cmd->user_data != conn)
2263 continue;
2264
2265 return cmd;
2266 }
2267
2268 return NULL;
2269}
2270
2271static void pairing_complete(struct pending_cmd *cmd, u8 status)
2272{
2273 struct mgmt_rp_pair_device rp;
2274 struct hci_conn *conn = cmd->user_data;
2275
Johan Hedbergba4e5642011-11-11 00:07:34 +02002276 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002277 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002278
Johan Hedbergaee9b212012-02-18 15:07:59 +02002279 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002280 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002281
2282 /* So we don't get further callbacks for this connection */
2283 conn->connect_cfm_cb = NULL;
2284 conn->security_cfm_cb = NULL;
2285 conn->disconn_cfm_cb = NULL;
2286
David Herrmann76a68ba2013-04-06 20:28:37 +02002287 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002288
Johan Hedberga664b5b2011-02-19 12:06:02 -03002289 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002290}
2291
2292static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2293{
2294 struct pending_cmd *cmd;
2295
2296 BT_DBG("status %u", status);
2297
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002298 cmd = find_pairing(conn);
2299 if (!cmd)
2300 BT_DBG("Unable to find a pending command");
2301 else
Johan Hedberge2113262012-02-18 15:20:03 +02002302 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002303}
2304
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302305static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2306{
2307 struct pending_cmd *cmd;
2308
2309 BT_DBG("status %u", status);
2310
2311 if (!status)
2312 return;
2313
2314 cmd = find_pairing(conn);
2315 if (!cmd)
2316 BT_DBG("Unable to find a pending command");
2317 else
2318 pairing_complete(cmd, mgmt_status(status));
2319}
2320
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002321static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002322 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002323{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002324 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002325 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002326 struct pending_cmd *cmd;
2327 u8 sec_level, auth_type;
2328 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002329 int err;
2330
2331 BT_DBG("");
2332
Szymon Jancf950a30e2013-01-18 12:48:07 +01002333 memset(&rp, 0, sizeof(rp));
2334 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2335 rp.addr.type = cp->addr.type;
2336
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002337 if (!bdaddr_type_is_valid(cp->addr.type))
2338 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2339 MGMT_STATUS_INVALID_PARAMS,
2340 &rp, sizeof(rp));
2341
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002342 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002343
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002344 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002345 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2346 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002347 goto unlock;
2348 }
2349
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002350 sec_level = BT_SECURITY_MEDIUM;
2351 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002352 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002353 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002354 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002355
Andre Guedes591f47f2012-04-24 21:02:49 -03002356 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002357 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2358 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002359 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002360 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2361 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002362
Ville Tervo30e76272011-02-22 16:10:53 -03002363 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002364 int status;
2365
2366 if (PTR_ERR(conn) == -EBUSY)
2367 status = MGMT_STATUS_BUSY;
2368 else
2369 status = MGMT_STATUS_CONNECT_FAILED;
2370
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002371 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002372 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002373 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002374 goto unlock;
2375 }
2376
2377 if (conn->connect_cfm_cb) {
David Herrmann76a68ba2013-04-06 20:28:37 +02002378 hci_conn_drop(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002379 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002380 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002381 goto unlock;
2382 }
2383
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002384 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002385 if (!cmd) {
2386 err = -ENOMEM;
David Herrmann76a68ba2013-04-06 20:28:37 +02002387 hci_conn_drop(conn);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002388 goto unlock;
2389 }
2390
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002391 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002392 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002393 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302394 else
2395 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002396
Johan Hedberge9a416b2011-02-19 12:05:56 -03002397 conn->security_cfm_cb = pairing_complete_cb;
2398 conn->disconn_cfm_cb = pairing_complete_cb;
2399 conn->io_capability = cp->io_cap;
2400 cmd->user_data = conn;
2401
2402 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002403 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002404 pairing_complete(cmd, 0);
2405
2406 err = 0;
2407
2408unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002409 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002410 return err;
2411}
2412
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002413static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2414 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002415{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002416 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002417 struct pending_cmd *cmd;
2418 struct hci_conn *conn;
2419 int err;
2420
2421 BT_DBG("");
2422
Johan Hedberg28424702012-02-02 04:02:29 +02002423 hci_dev_lock(hdev);
2424
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002425 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002426 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002427 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002428 goto unlock;
2429 }
2430
Johan Hedberg28424702012-02-02 04:02:29 +02002431 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2432 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002433 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002434 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002435 goto unlock;
2436 }
2437
2438 conn = cmd->user_data;
2439
2440 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002441 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002442 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002443 goto unlock;
2444 }
2445
2446 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2447
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002448 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002449 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002450unlock:
2451 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002452 return err;
2453}
2454
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002455static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Johan Hedberg1707c602013-03-15 17:07:15 -05002456 struct mgmt_addr_info *addr, u16 mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002457 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002458{
Johan Hedberga5c29682011-02-19 12:05:57 -03002459 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002460 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002461 int err;
2462
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002463 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002464
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002465 if (!hdev_is_powered(hdev)) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002466 err = cmd_complete(sk, hdev->id, mgmt_op,
2467 MGMT_STATUS_NOT_POWERED, addr,
2468 sizeof(*addr));
Brian Gix0df4c182011-11-16 13:53:13 -08002469 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002470 }
2471
Johan Hedberg1707c602013-03-15 17:07:15 -05002472 if (addr->type == BDADDR_BREDR)
2473 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &addr->bdaddr);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002474 else
Johan Hedberg1707c602013-03-15 17:07:15 -05002475 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &addr->bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002476
Johan Hedberg272d90d2012-02-09 15:26:12 +02002477 if (!conn) {
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002478 err = cmd_complete(sk, hdev->id, mgmt_op,
2479 MGMT_STATUS_NOT_CONNECTED, addr,
2480 sizeof(*addr));
Johan Hedberg272d90d2012-02-09 15:26:12 +02002481 goto done;
2482 }
2483
Johan Hedberg1707c602013-03-15 17:07:15 -05002484 if (addr->type == BDADDR_LE_PUBLIC || addr->type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002485 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002486 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002487
Brian Gix5fe57d92011-12-21 16:12:13 -08002488 if (!err)
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002489 err = cmd_complete(sk, hdev->id, mgmt_op,
2490 MGMT_STATUS_SUCCESS, addr,
2491 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002492 else
Johan Hedbergfeb94d32013-03-15 17:07:16 -05002493 err = cmd_complete(sk, hdev->id, mgmt_op,
2494 MGMT_STATUS_FAILED, addr,
2495 sizeof(*addr));
Brian Gix5fe57d92011-12-21 16:12:13 -08002496
Brian Gix47c15e22011-11-16 13:53:14 -08002497 goto done;
2498 }
2499
Johan Hedberg1707c602013-03-15 17:07:15 -05002500 cmd = mgmt_pending_add(sk, mgmt_op, hdev, addr, sizeof(*addr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002501 if (!cmd) {
2502 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002503 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002504 }
2505
Brian Gix0df4c182011-11-16 13:53:13 -08002506 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002507 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2508 struct hci_cp_user_passkey_reply cp;
2509
Johan Hedberg1707c602013-03-15 17:07:15 -05002510 bacpy(&cp.bdaddr, &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002511 cp.passkey = passkey;
2512 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2513 } else
Johan Hedberg1707c602013-03-15 17:07:15 -05002514 err = hci_send_cmd(hdev, hci_op, sizeof(addr->bdaddr),
2515 &addr->bdaddr);
Brian Gix604086b2011-11-23 08:28:33 -08002516
Johan Hedberga664b5b2011-02-19 12:06:02 -03002517 if (err < 0)
2518 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002519
Brian Gix0df4c182011-11-16 13:53:13 -08002520done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002521 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002522 return err;
2523}
2524
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302525static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2526 void *data, u16 len)
2527{
2528 struct mgmt_cp_pin_code_neg_reply *cp = data;
2529
2530 BT_DBG("");
2531
Johan Hedberg1707c602013-03-15 17:07:15 -05002532 return user_pairing_resp(sk, hdev, &cp->addr,
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302533 MGMT_OP_PIN_CODE_NEG_REPLY,
2534 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2535}
2536
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002537static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2538 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002539{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002540 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002541
2542 BT_DBG("");
2543
2544 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002545 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002546 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002547
Johan Hedberg1707c602013-03-15 17:07:15 -05002548 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002549 MGMT_OP_USER_CONFIRM_REPLY,
2550 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002551}
2552
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002553static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002554 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002555{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002556 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002557
2558 BT_DBG("");
2559
Johan Hedberg1707c602013-03-15 17:07:15 -05002560 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002561 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2562 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002563}
2564
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002565static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2566 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002567{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002568 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002569
2570 BT_DBG("");
2571
Johan Hedberg1707c602013-03-15 17:07:15 -05002572 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002573 MGMT_OP_USER_PASSKEY_REPLY,
2574 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002575}
2576
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002577static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002578 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002579{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002580 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002581
2582 BT_DBG("");
2583
Johan Hedberg1707c602013-03-15 17:07:15 -05002584 return user_pairing_resp(sk, hdev, &cp->addr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002585 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2586 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002587}
2588
Johan Hedberg13928972013-03-15 17:07:00 -05002589static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002590{
Johan Hedberg13928972013-03-15 17:07:00 -05002591 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002592 struct hci_cp_write_local_name cp;
2593
Johan Hedberg13928972013-03-15 17:07:00 -05002594 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002595
Johan Hedberg890ea892013-03-15 17:06:52 -05002596 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002597}
2598
Johan Hedberg13928972013-03-15 17:07:00 -05002599static void set_name_complete(struct hci_dev *hdev, u8 status)
2600{
2601 struct mgmt_cp_set_local_name *cp;
2602 struct pending_cmd *cmd;
2603
2604 BT_DBG("status 0x%02x", status);
2605
2606 hci_dev_lock(hdev);
2607
2608 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2609 if (!cmd)
2610 goto unlock;
2611
2612 cp = cmd->param;
2613
2614 if (status)
2615 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2616 mgmt_status(status));
2617 else
2618 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2619 cp, sizeof(*cp));
2620
2621 mgmt_pending_remove(cmd);
2622
2623unlock:
2624 hci_dev_unlock(hdev);
2625}
2626
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002627static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002628 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002629{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002630 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002631 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002632 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002633 int err;
2634
2635 BT_DBG("");
2636
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002637 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002638
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002639 /* If the old values are the same as the new ones just return a
2640 * direct command complete event.
2641 */
2642 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2643 !memcmp(hdev->short_name, cp->short_name,
2644 sizeof(hdev->short_name))) {
2645 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2646 data, len);
2647 goto failed;
2648 }
2649
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002650 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002651
Johan Hedbergb5235a62012-02-21 14:32:24 +02002652 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002653 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002654
2655 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002656 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002657 if (err < 0)
2658 goto failed;
2659
2660 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002661 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002662
Johan Hedbergb5235a62012-02-21 14:32:24 +02002663 goto failed;
2664 }
2665
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002666 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002667 if (!cmd) {
2668 err = -ENOMEM;
2669 goto failed;
2670 }
2671
Johan Hedberg13928972013-03-15 17:07:00 -05002672 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2673
Johan Hedberg890ea892013-03-15 17:06:52 -05002674 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002675
2676 if (lmp_bredr_capable(hdev)) {
2677 update_name(&req);
2678 update_eir(&req);
2679 }
2680
2681 if (lmp_le_capable(hdev))
2682 hci_update_ad(&req);
2683
Johan Hedberg13928972013-03-15 17:07:00 -05002684 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002685 if (err < 0)
2686 mgmt_pending_remove(cmd);
2687
2688failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002689 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002690 return err;
2691}
2692
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002693static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002694 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002695{
Szymon Jancc35938b2011-03-22 13:12:21 +01002696 struct pending_cmd *cmd;
2697 int err;
2698
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002699 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002700
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002701 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002702
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002703 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002704 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002705 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002706 goto unlock;
2707 }
2708
Andre Guedes9a1a1992012-07-24 15:03:48 -03002709 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002710 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002711 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002712 goto unlock;
2713 }
2714
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002715 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002716 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002717 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002718 goto unlock;
2719 }
2720
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002721 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002722 if (!cmd) {
2723 err = -ENOMEM;
2724 goto unlock;
2725 }
2726
2727 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2728 if (err < 0)
2729 mgmt_pending_remove(cmd);
2730
2731unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002732 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002733 return err;
2734}
2735
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002736static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002737 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002738{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002739 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002740 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002741 int err;
2742
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002743 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002744
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002745 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002746
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002747 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002748 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002749 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002750 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002751 else
Szymon Janca6785be2012-12-13 15:11:21 +01002752 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002753
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002754 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002755 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002756
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002757 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002758 return err;
2759}
2760
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002761static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002762 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002763{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002764 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002765 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002766 int err;
2767
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002768 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002769
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002770 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002771
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002772 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002773 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002774 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002775 else
Szymon Janca6785be2012-12-13 15:11:21 +01002776 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002777
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002778 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002779 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002780
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002781 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002782 return err;
2783}
2784
Andre Guedes41dc2bd2013-04-30 15:29:30 -03002785static int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
2786{
2787 struct pending_cmd *cmd;
2788 u8 type;
2789 int err;
2790
2791 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2792
2793 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
2794 if (!cmd)
2795 return -ENOENT;
2796
2797 type = hdev->discovery.type;
2798
2799 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2800 &type, sizeof(type));
2801 mgmt_pending_remove(cmd);
2802
2803 return err;
2804}
2805
Andre Guedes7c307722013-04-30 15:29:28 -03002806static void start_discovery_complete(struct hci_dev *hdev, u8 status)
2807{
2808 BT_DBG("status %d", status);
2809
2810 if (status) {
2811 hci_dev_lock(hdev);
2812 mgmt_start_discovery_failed(hdev, status);
2813 hci_dev_unlock(hdev);
2814 return;
2815 }
2816
2817 hci_dev_lock(hdev);
2818 hci_discovery_set_state(hdev, DISCOVERY_FINDING);
2819 hci_dev_unlock(hdev);
2820
2821 switch (hdev->discovery.type) {
2822 case DISCOV_TYPE_LE:
2823 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002824 DISCOV_LE_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002825 break;
2826
2827 case DISCOV_TYPE_INTERLEAVED:
2828 queue_delayed_work(hdev->workqueue, &hdev->le_scan_disable,
Andre Guedes0d8cc932013-04-30 15:29:31 -03002829 DISCOV_INTERLEAVED_TIMEOUT);
Andre Guedes7c307722013-04-30 15:29:28 -03002830 break;
2831
2832 case DISCOV_TYPE_BREDR:
2833 break;
2834
2835 default:
2836 BT_ERR("Invalid discovery type %d", hdev->discovery.type);
2837 }
2838}
2839
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002840static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002841 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002842{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002843 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002844 struct pending_cmd *cmd;
Andre Guedes7c307722013-04-30 15:29:28 -03002845 struct hci_cp_le_set_scan_param param_cp;
2846 struct hci_cp_le_set_scan_enable enable_cp;
2847 struct hci_cp_inquiry inq_cp;
2848 struct hci_request req;
2849 /* General inquiry access code (GIAC) */
2850 u8 lap[3] = { 0x33, 0x8b, 0x9e };
Johan Hedberge6fe7982013-10-02 15:45:22 +03002851 u8 status;
Johan Hedberg14a53662011-04-27 10:29:56 -04002852 int err;
2853
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002854 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002855
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002856 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002857
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002858 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002859 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002860 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002861 goto failed;
2862 }
2863
Andre Guedes642be6c2012-03-21 00:03:37 -03002864 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2865 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2866 MGMT_STATUS_BUSY);
2867 goto failed;
2868 }
2869
Johan Hedbergff9ef572012-01-04 14:23:45 +02002870 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002871 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002872 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002873 goto failed;
2874 }
2875
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002876 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002877 if (!cmd) {
2878 err = -ENOMEM;
2879 goto failed;
2880 }
2881
Andre Guedes4aab14e2012-02-17 20:39:36 -03002882 hdev->discovery.type = cp->type;
2883
Andre Guedes7c307722013-04-30 15:29:28 -03002884 hci_req_init(&req, hdev);
2885
Andre Guedes4aab14e2012-02-17 20:39:36 -03002886 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002887 case DISCOV_TYPE_BREDR:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002888 status = mgmt_bredr_support(hdev);
2889 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002890 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002891 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002892 mgmt_pending_remove(cmd);
2893 goto failed;
2894 }
2895
Andre Guedes7c307722013-04-30 15:29:28 -03002896 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
2897 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2898 MGMT_STATUS_BUSY);
2899 mgmt_pending_remove(cmd);
2900 goto failed;
2901 }
2902
2903 hci_inquiry_cache_flush(hdev);
2904
2905 memset(&inq_cp, 0, sizeof(inq_cp));
2906 memcpy(&inq_cp.lap, lap, sizeof(inq_cp.lap));
Andre Guedes0d8cc932013-04-30 15:29:31 -03002907 inq_cp.length = DISCOV_BREDR_INQUIRY_LEN;
Andre Guedes7c307722013-04-30 15:29:28 -03002908 hci_req_add(&req, HCI_OP_INQUIRY, sizeof(inq_cp), &inq_cp);
Andre Guedesf39799f2012-02-17 20:39:35 -03002909 break;
2910
2911 case DISCOV_TYPE_LE:
Andre Guedes7c307722013-04-30 15:29:28 -03002912 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberge6fe7982013-10-02 15:45:22 +03002913 status = mgmt_le_support(hdev);
2914 if (status) {
Johan Hedberg04106752013-01-10 14:54:09 +02002915 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Johan Hedberge6fe7982013-10-02 15:45:22 +03002916 status);
Johan Hedberg04106752013-01-10 14:54:09 +02002917 mgmt_pending_remove(cmd);
2918 goto failed;
2919 }
2920
Andre Guedes7c307722013-04-30 15:29:28 -03002921 if (hdev->discovery.type == DISCOV_TYPE_INTERLEAVED &&
Johan Hedberg56f87902013-10-02 13:43:13 +03002922 !test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
Johan Hedberg04106752013-01-10 14:54:09 +02002923 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2924 MGMT_STATUS_NOT_SUPPORTED);
2925 mgmt_pending_remove(cmd);
2926 goto failed;
2927 }
2928
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02002929 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
Andre Guedes7c307722013-04-30 15:29:28 -03002930 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2931 MGMT_STATUS_REJECTED);
2932 mgmt_pending_remove(cmd);
2933 goto failed;
2934 }
2935
2936 if (test_bit(HCI_LE_SCAN, &hdev->dev_flags)) {
2937 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2938 MGMT_STATUS_BUSY);
2939 mgmt_pending_remove(cmd);
2940 goto failed;
2941 }
2942
2943 memset(&param_cp, 0, sizeof(param_cp));
2944 param_cp.type = LE_SCAN_ACTIVE;
Andre Guedes0d8cc932013-04-30 15:29:31 -03002945 param_cp.interval = cpu_to_le16(DISCOV_LE_SCAN_INT);
2946 param_cp.window = cpu_to_le16(DISCOV_LE_SCAN_WIN);
Marcel Holtmannc25dfc62013-10-06 02:08:36 -07002947 if (bacmp(&hdev->bdaddr, BDADDR_ANY))
2948 param_cp.own_address_type = ADDR_LE_DEV_PUBLIC;
2949 else
2950 param_cp.own_address_type = ADDR_LE_DEV_RANDOM;
Andre Guedes7c307722013-04-30 15:29:28 -03002951 hci_req_add(&req, HCI_OP_LE_SET_SCAN_PARAM, sizeof(param_cp),
2952 &param_cp);
2953
2954 memset(&enable_cp, 0, sizeof(enable_cp));
2955 enable_cp.enable = LE_SCAN_ENABLE;
2956 enable_cp.filter_dup = LE_SCAN_FILTER_DUP_ENABLE;
2957 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE, sizeof(enable_cp),
2958 &enable_cp);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002959 break;
2960
Andre Guedesf39799f2012-02-17 20:39:35 -03002961 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002962 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2963 MGMT_STATUS_INVALID_PARAMS);
2964 mgmt_pending_remove(cmd);
2965 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002966 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002967
Andre Guedes7c307722013-04-30 15:29:28 -03002968 err = hci_req_run(&req, start_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04002969 if (err < 0)
2970 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002971 else
2972 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002973
2974failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002975 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002976 return err;
2977}
2978
Andre Guedes1183fdc2013-04-30 15:29:35 -03002979static int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2980{
2981 struct pending_cmd *cmd;
2982 int err;
2983
2984 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2985 if (!cmd)
2986 return -ENOENT;
2987
2988 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
2989 &hdev->discovery.type, sizeof(hdev->discovery.type));
2990 mgmt_pending_remove(cmd);
2991
2992 return err;
2993}
2994
Andre Guedes0e05bba2013-04-30 15:29:33 -03002995static void stop_discovery_complete(struct hci_dev *hdev, u8 status)
2996{
2997 BT_DBG("status %d", status);
2998
2999 hci_dev_lock(hdev);
3000
3001 if (status) {
3002 mgmt_stop_discovery_failed(hdev, status);
3003 goto unlock;
3004 }
3005
3006 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3007
3008unlock:
3009 hci_dev_unlock(hdev);
3010}
3011
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003012static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003013 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04003014{
Johan Hedbergd9306502012-02-20 23:25:18 +02003015 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04003016 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003017 struct hci_cp_remote_name_req_cancel cp;
3018 struct inquiry_entry *e;
Andre Guedes0e05bba2013-04-30 15:29:33 -03003019 struct hci_request req;
3020 struct hci_cp_le_set_scan_enable enable_cp;
Johan Hedberg14a53662011-04-27 10:29:56 -04003021 int err;
3022
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003023 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04003024
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003025 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003026
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003027 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003028 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003029 MGMT_STATUS_REJECTED, &mgmt_cp->type,
3030 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02003031 goto unlock;
3032 }
3033
3034 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003035 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
3037 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003038 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02003039 }
3040
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003041 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04003042 if (!cmd) {
3043 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003044 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04003045 }
3046
Andre Guedes0e05bba2013-04-30 15:29:33 -03003047 hci_req_init(&req, hdev);
3048
Andre Guedese0d9727e2012-03-20 15:15:36 -03003049 switch (hdev->discovery.state) {
3050 case DISCOVERY_FINDING:
Andre Guedes0e05bba2013-04-30 15:29:33 -03003051 if (test_bit(HCI_INQUIRY, &hdev->flags)) {
3052 hci_req_add(&req, HCI_OP_INQUIRY_CANCEL, 0, NULL);
3053 } else {
3054 cancel_delayed_work(&hdev->le_scan_disable);
3055
3056 memset(&enable_cp, 0, sizeof(enable_cp));
3057 enable_cp.enable = LE_SCAN_DISABLE;
3058 hci_req_add(&req, HCI_OP_LE_SET_SCAN_ENABLE,
3059 sizeof(enable_cp), &enable_cp);
3060 }
Andre Guedesc9ecc482012-03-15 16:52:08 -03003061
Andre Guedese0d9727e2012-03-20 15:15:36 -03003062 break;
3063
3064 case DISCOVERY_RESOLVING:
3065 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003066 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003067 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003068 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003069 err = cmd_complete(sk, hdev->id,
3070 MGMT_OP_STOP_DISCOVERY, 0,
3071 &mgmt_cp->type,
3072 sizeof(mgmt_cp->type));
3073 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3074 goto unlock;
3075 }
3076
3077 bacpy(&cp.bdaddr, &e->data.bdaddr);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003078 hci_req_add(&req, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
3079 &cp);
Andre Guedese0d9727e2012-03-20 15:15:36 -03003080
3081 break;
3082
3083 default:
3084 BT_DBG("unknown discovery state %u", hdev->discovery.state);
Andre Guedes0e05bba2013-04-30 15:29:33 -03003085
3086 mgmt_pending_remove(cmd);
3087 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
3088 MGMT_STATUS_FAILED, &mgmt_cp->type,
3089 sizeof(mgmt_cp->type));
3090 goto unlock;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003091 }
3092
Andre Guedes0e05bba2013-04-30 15:29:33 -03003093 err = hci_req_run(&req, stop_discovery_complete);
Johan Hedberg14a53662011-04-27 10:29:56 -04003094 if (err < 0)
3095 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02003096 else
3097 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04003098
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003099unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003100 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04003101 return err;
3102}
3103
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003104static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003105 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02003106{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003107 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003108 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02003109 int err;
3110
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003111 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003112
Johan Hedberg561aafb2012-01-04 13:31:59 +02003113 hci_dev_lock(hdev);
3114
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003115 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003116 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003117 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02003118 goto failed;
3119 }
3120
Johan Hedberga198e7b2012-02-17 14:27:06 +02003121 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003122 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003123 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003124 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003125 goto failed;
3126 }
3127
3128 if (cp->name_known) {
3129 e->name_state = NAME_KNOWN;
3130 list_del(&e->list);
3131 } else {
3132 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02003133 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003134 }
3135
Johan Hedberge3846622013-01-09 15:29:33 +02003136 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
3137 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02003138
3139failed:
3140 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02003141 return err;
3142}
3143
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003144static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003145 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003146{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003147 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003148 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003149 int err;
3150
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003151 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003152
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003153 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003154 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
3155 MGMT_STATUS_INVALID_PARAMS,
3156 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003157
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003158 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003159
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003160 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003161 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003162 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03003163 else
Szymon Janca6785be2012-12-13 15:11:21 +01003164 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003165
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003166 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003167 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003168
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003169 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003170
3171 return err;
3172}
3173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003174static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003175 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03003176{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003177 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003178 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03003179 int err;
3180
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003181 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03003182
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003183 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02003184 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
3185 MGMT_STATUS_INVALID_PARAMS,
3186 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003187
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003188 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003189
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003190 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03003191 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003192 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03003193 else
Szymon Janca6785be2012-12-13 15:11:21 +01003194 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02003195
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003196 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003197 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03003198
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03003199 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03003200
3201 return err;
3202}
3203
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003204static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
3205 u16 len)
3206{
3207 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05003208 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003209 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01003210 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003211
3212 BT_DBG("%s", hdev->name);
3213
Szymon Jancc72d4b82012-03-16 16:02:57 +01003214 source = __le16_to_cpu(cp->source);
3215
3216 if (source > 0x0002)
3217 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
3218 MGMT_STATUS_INVALID_PARAMS);
3219
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003220 hci_dev_lock(hdev);
3221
Szymon Jancc72d4b82012-03-16 16:02:57 +01003222 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003223 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
3224 hdev->devid_product = __le16_to_cpu(cp->product);
3225 hdev->devid_version = __le16_to_cpu(cp->version);
3226
3227 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
3228
Johan Hedberg890ea892013-03-15 17:06:52 -05003229 hci_req_init(&req, hdev);
3230 update_eir(&req);
3231 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003232
3233 hci_dev_unlock(hdev);
3234
3235 return err;
3236}
3237
Johan Hedberg4375f102013-09-25 13:26:10 +03003238static void set_advertising_complete(struct hci_dev *hdev, u8 status)
3239{
3240 struct cmd_lookup match = { NULL, hdev };
3241
3242 if (status) {
3243 u8 mgmt_err = mgmt_status(status);
3244
3245 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev,
3246 cmd_status_rsp, &mgmt_err);
3247 return;
3248 }
3249
3250 mgmt_pending_foreach(MGMT_OP_SET_ADVERTISING, hdev, settings_rsp,
3251 &match);
3252
3253 new_settings(hdev, match.sk);
3254
3255 if (match.sk)
3256 sock_put(match.sk);
3257}
3258
Marcel Holtmann21b51872013-10-10 09:47:53 -07003259static int set_advertising(struct sock *sk, struct hci_dev *hdev, void *data,
3260 u16 len)
Johan Hedberg4375f102013-09-25 13:26:10 +03003261{
3262 struct mgmt_mode *cp = data;
3263 struct pending_cmd *cmd;
3264 struct hci_request req;
Johan Hedberge6fe7982013-10-02 15:45:22 +03003265 u8 val, enabled, status;
Johan Hedberg4375f102013-09-25 13:26:10 +03003266 int err;
3267
3268 BT_DBG("request for %s", hdev->name);
3269
Johan Hedberge6fe7982013-10-02 15:45:22 +03003270 status = mgmt_le_support(hdev);
3271 if (status)
Johan Hedberg4375f102013-09-25 13:26:10 +03003272 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
Johan Hedberge6fe7982013-10-02 15:45:22 +03003273 status);
Johan Hedberg4375f102013-09-25 13:26:10 +03003274
3275 if (cp->val != 0x00 && cp->val != 0x01)
3276 return cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3277 MGMT_STATUS_INVALID_PARAMS);
3278
3279 hci_dev_lock(hdev);
3280
3281 val = !!cp->val;
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003282 enabled = test_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003283
Johan Hedbergf74ca9b2013-10-08 15:52:18 +02003284 /* The following conditions are ones which mean that we should
3285 * not do any HCI communication but directly send a mgmt
3286 * response to user space (after toggling the flag if
3287 * necessary).
3288 */
3289 if (!hdev_is_powered(hdev) || val == enabled ||
Marcel Holtmannb145edc2013-10-10 09:47:54 -07003290 hci_conn_num(hdev, LE_LINK) > 0) {
Johan Hedberg4375f102013-09-25 13:26:10 +03003291 bool changed = false;
3292
Johan Hedbergf3d3444a2013-10-05 12:01:04 +02003293 if (val != test_bit(HCI_ADVERTISING, &hdev->dev_flags)) {
3294 change_bit(HCI_ADVERTISING, &hdev->dev_flags);
Johan Hedberg4375f102013-09-25 13:26:10 +03003295 changed = true;
3296 }
3297
3298 err = send_settings_rsp(sk, MGMT_OP_SET_ADVERTISING, hdev);
3299 if (err < 0)
3300 goto unlock;
3301
3302 if (changed)
3303 err = new_settings(hdev, sk);
3304
3305 goto unlock;
3306 }
3307
3308 if (mgmt_pending_find(MGMT_OP_SET_ADVERTISING, hdev) ||
3309 mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
3310 err = cmd_status(sk, hdev->id, MGMT_OP_SET_ADVERTISING,
3311 MGMT_STATUS_BUSY);
3312 goto unlock;
3313 }
3314
3315 cmd = mgmt_pending_add(sk, MGMT_OP_SET_ADVERTISING, hdev, data, len);
3316 if (!cmd) {
3317 err = -ENOMEM;
3318 goto unlock;
3319 }
3320
3321 hci_req_init(&req, hdev);
3322
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003323 if (val)
3324 enable_advertising(&req);
3325 else
3326 disable_advertising(&req);
Johan Hedberg4375f102013-09-25 13:26:10 +03003327
3328 err = hci_req_run(&req, set_advertising_complete);
3329 if (err < 0)
3330 mgmt_pending_remove(cmd);
3331
3332unlock:
3333 hci_dev_unlock(hdev);
3334 return err;
3335}
3336
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003337static int set_static_address(struct sock *sk, struct hci_dev *hdev,
3338 void *data, u16 len)
3339{
3340 struct mgmt_cp_set_static_address *cp = data;
3341 int err;
3342
3343 BT_DBG("%s", hdev->name);
3344
Marcel Holtmann62af4442013-10-02 22:10:32 -07003345 if (!lmp_le_capable(hdev))
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003346 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
Marcel Holtmann62af4442013-10-02 22:10:32 -07003347 MGMT_STATUS_NOT_SUPPORTED);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003348
3349 if (hdev_is_powered(hdev))
3350 return cmd_status(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS,
3351 MGMT_STATUS_REJECTED);
3352
3353 if (bacmp(&cp->bdaddr, BDADDR_ANY)) {
3354 if (!bacmp(&cp->bdaddr, BDADDR_NONE))
3355 return cmd_status(sk, hdev->id,
3356 MGMT_OP_SET_STATIC_ADDRESS,
3357 MGMT_STATUS_INVALID_PARAMS);
3358
3359 /* Two most significant bits shall be set */
3360 if ((cp->bdaddr.b[5] & 0xc0) != 0xc0)
3361 return cmd_status(sk, hdev->id,
3362 MGMT_OP_SET_STATIC_ADDRESS,
3363 MGMT_STATUS_INVALID_PARAMS);
3364 }
3365
3366 hci_dev_lock(hdev);
3367
3368 bacpy(&hdev->static_addr, &cp->bdaddr);
3369
3370 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_STATIC_ADDRESS, 0, NULL, 0);
3371
3372 hci_dev_unlock(hdev);
3373
3374 return err;
3375}
3376
Johan Hedberg33e38b32013-03-15 17:07:05 -05003377static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
3378{
3379 struct pending_cmd *cmd;
3380
3381 BT_DBG("status 0x%02x", status);
3382
3383 hci_dev_lock(hdev);
3384
3385 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3386 if (!cmd)
3387 goto unlock;
3388
3389 if (status) {
3390 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3391 mgmt_status(status));
3392 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003393 struct mgmt_mode *cp = cmd->param;
3394
3395 if (cp->val)
3396 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3397 else
3398 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3399
Johan Hedberg33e38b32013-03-15 17:07:05 -05003400 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
3401 new_settings(hdev, cmd->sk);
3402 }
3403
3404 mgmt_pending_remove(cmd);
3405
3406unlock:
3407 hci_dev_unlock(hdev);
3408}
3409
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003410static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003411 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03003412{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003413 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05003414 struct pending_cmd *cmd;
3415 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03003416 int err;
3417
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003418 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003419
Johan Hedberg56f87902013-10-02 13:43:13 +03003420 if (!test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags) ||
3421 hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03003422 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3423 MGMT_STATUS_NOT_SUPPORTED);
3424
Johan Hedberga7e80f22013-01-09 16:05:19 +02003425 if (cp->val != 0x00 && cp->val != 0x01)
3426 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3427 MGMT_STATUS_INVALID_PARAMS);
3428
Johan Hedberg5400c042012-02-21 16:40:33 +02003429 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003430 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003431 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02003432
3433 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003434 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003435 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003436
3437 hci_dev_lock(hdev);
3438
Johan Hedberg05cbf292013-03-15 17:07:07 -05003439 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
3440 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
3441 MGMT_STATUS_BUSY);
3442 goto unlock;
3443 }
3444
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05003445 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
3446 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
3447 hdev);
3448 goto unlock;
3449 }
3450
Johan Hedberg33e38b32013-03-15 17:07:05 -05003451 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3452 data, len);
3453 if (!cmd) {
3454 err = -ENOMEM;
3455 goto unlock;
3456 }
3457
3458 hci_req_init(&req, hdev);
3459
Johan Hedberg406d7802013-03-15 17:07:09 -05003460 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003461
3462 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003463 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003464 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003465 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003466 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003467 }
3468
Johan Hedberg33e38b32013-03-15 17:07:05 -05003469unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003470 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003471
Antti Julkuf6422ec2011-06-22 13:11:56 +03003472 return err;
3473}
3474
Johan Hedberg0663ca22013-10-02 13:43:14 +03003475static void set_bredr_complete(struct hci_dev *hdev, u8 status)
3476{
3477 struct pending_cmd *cmd;
3478
3479 BT_DBG("status 0x%02x", status);
3480
3481 hci_dev_lock(hdev);
3482
3483 cmd = mgmt_pending_find(MGMT_OP_SET_BREDR, hdev);
3484 if (!cmd)
3485 goto unlock;
3486
3487 if (status) {
3488 u8 mgmt_err = mgmt_status(status);
3489
3490 /* We need to restore the flag if related HCI commands
3491 * failed.
3492 */
3493 clear_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3494
3495 cmd_status(cmd->sk, cmd->index, cmd->opcode, mgmt_err);
3496 } else {
3497 send_settings_rsp(cmd->sk, MGMT_OP_SET_BREDR, hdev);
3498 new_settings(hdev, cmd->sk);
3499 }
3500
3501 mgmt_pending_remove(cmd);
3502
3503unlock:
3504 hci_dev_unlock(hdev);
3505}
3506
3507static int set_bredr(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
3508{
3509 struct mgmt_mode *cp = data;
3510 struct pending_cmd *cmd;
3511 struct hci_request req;
3512 int err;
3513
3514 BT_DBG("request for %s", hdev->name);
3515
3516 if (!lmp_bredr_capable(hdev) || !lmp_le_capable(hdev))
3517 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3518 MGMT_STATUS_NOT_SUPPORTED);
3519
3520 if (!test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3521 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3522 MGMT_STATUS_REJECTED);
3523
3524 if (cp->val != 0x00 && cp->val != 0x01)
3525 return cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3526 MGMT_STATUS_INVALID_PARAMS);
3527
3528 hci_dev_lock(hdev);
3529
3530 if (cp->val == test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags)) {
3531 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3532 goto unlock;
3533 }
3534
3535 if (!hdev_is_powered(hdev)) {
3536 if (!cp->val) {
3537 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
3538 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
3539 clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
3540 clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3541 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
3542 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
3543 }
3544
3545 change_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3546
3547 err = send_settings_rsp(sk, MGMT_OP_SET_BREDR, hdev);
3548 if (err < 0)
3549 goto unlock;
3550
3551 err = new_settings(hdev, sk);
3552 goto unlock;
3553 }
3554
3555 /* Reject disabling when powered on */
3556 if (!cp->val) {
3557 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3558 MGMT_STATUS_REJECTED);
3559 goto unlock;
3560 }
3561
3562 if (mgmt_pending_find(MGMT_OP_SET_BREDR, hdev)) {
3563 err = cmd_status(sk, hdev->id, MGMT_OP_SET_BREDR,
3564 MGMT_STATUS_BUSY);
3565 goto unlock;
3566 }
3567
3568 cmd = mgmt_pending_add(sk, MGMT_OP_SET_BREDR, hdev, data, len);
3569 if (!cmd) {
3570 err = -ENOMEM;
3571 goto unlock;
3572 }
3573
3574 /* We need to flip the bit already here so that hci_update_ad
3575 * generates the correct flags.
3576 */
3577 set_bit(HCI_BREDR_ENABLED, &hdev->dev_flags);
3578
3579 hci_req_init(&req, hdev);
3580 hci_update_ad(&req);
3581 err = hci_req_run(&req, set_bredr_complete);
3582 if (err < 0)
3583 mgmt_pending_remove(cmd);
3584
3585unlock:
3586 hci_dev_unlock(hdev);
3587 return err;
3588}
3589
Johan Hedberg3f706b72013-01-20 14:27:16 +02003590static bool ltk_is_valid(struct mgmt_ltk_info *key)
3591{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003592 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3593 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003594 if (key->master != 0x00 && key->master != 0x01)
3595 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003596 if (!bdaddr_type_is_le(key->addr.type))
3597 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003598 return true;
3599}
3600
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003601static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003602 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003603{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003604 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3605 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003606 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003607
Marcel Holtmanncf99ba12013-10-02 21:16:08 -07003608 BT_DBG("request for %s", hdev->name);
3609
3610 if (!lmp_le_capable(hdev))
3611 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
3612 MGMT_STATUS_NOT_SUPPORTED);
3613
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003614 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003615
3616 expected_len = sizeof(*cp) + key_count *
3617 sizeof(struct mgmt_ltk_info);
3618 if (expected_len != len) {
3619 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003620 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003621 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003622 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003623 }
3624
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003625 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003626
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003627 for (i = 0; i < key_count; i++) {
3628 struct mgmt_ltk_info *key = &cp->keys[i];
3629
Johan Hedberg3f706b72013-01-20 14:27:16 +02003630 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003631 return cmd_status(sk, hdev->id,
3632 MGMT_OP_LOAD_LONG_TERM_KEYS,
3633 MGMT_STATUS_INVALID_PARAMS);
3634 }
3635
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003636 hci_dev_lock(hdev);
3637
3638 hci_smp_ltks_clear(hdev);
3639
3640 for (i = 0; i < key_count; i++) {
3641 struct mgmt_ltk_info *key = &cp->keys[i];
3642 u8 type;
3643
3644 if (key->master)
3645 type = HCI_SMP_LTK;
3646 else
3647 type = HCI_SMP_LTK_SLAVE;
3648
Hemant Gupta4596fde2012-04-16 14:57:40 +05303649 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003650 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003651 type, 0, key->authenticated, key->val,
3652 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003653 }
3654
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003655 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3656 NULL, 0);
3657
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003658 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003659
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003660 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003661}
3662
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003663static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003664 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3665 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003666 bool var_len;
3667 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003668} mgmt_handlers[] = {
3669 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003670 { read_version, false, MGMT_READ_VERSION_SIZE },
3671 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3672 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3673 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3674 { set_powered, false, MGMT_SETTING_SIZE },
3675 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3676 { set_connectable, false, MGMT_SETTING_SIZE },
3677 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3678 { set_pairable, false, MGMT_SETTING_SIZE },
3679 { set_link_security, false, MGMT_SETTING_SIZE },
3680 { set_ssp, false, MGMT_SETTING_SIZE },
3681 { set_hs, false, MGMT_SETTING_SIZE },
3682 { set_le, false, MGMT_SETTING_SIZE },
3683 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3684 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3685 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3686 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3687 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3688 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3689 { disconnect, false, MGMT_DISCONNECT_SIZE },
3690 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3691 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3692 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3693 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3694 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3695 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3696 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3697 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3698 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3699 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3700 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3701 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3702 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3703 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3704 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3705 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3706 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3707 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3708 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003709 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg4375f102013-09-25 13:26:10 +03003710 { set_advertising, false, MGMT_SETTING_SIZE },
Johan Hedberg0663ca22013-10-02 13:43:14 +03003711 { set_bredr, false, MGMT_SETTING_SIZE },
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003712 { set_static_address, false, MGMT_SET_STATIC_ADDRESS_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003713};
3714
3715
Johan Hedberg03811012010-12-08 00:21:06 +02003716int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3717{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003718 void *buf;
3719 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003720 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003721 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003722 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003723 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003724 int err;
3725
3726 BT_DBG("got %zu bytes", msglen);
3727
3728 if (msglen < sizeof(*hdr))
3729 return -EINVAL;
3730
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003731 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003732 if (!buf)
3733 return -ENOMEM;
3734
3735 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3736 err = -EFAULT;
3737 goto done;
3738 }
3739
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003740 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003741 opcode = __le16_to_cpu(hdr->opcode);
3742 index = __le16_to_cpu(hdr->index);
3743 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003744
3745 if (len != msglen - sizeof(*hdr)) {
3746 err = -EINVAL;
3747 goto done;
3748 }
3749
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003750 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003751 hdev = hci_dev_get(index);
3752 if (!hdev) {
3753 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003754 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003755 goto done;
3756 }
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003757
Johan Hedbergcebf4cf2013-10-10 18:06:04 +02003758 if (test_bit(HCI_SETUP, &hdev->dev_flags) ||
3759 test_bit(HCI_USER_CHANNEL, &hdev->dev_flags)) {
Marcel Holtmann0736cfa2013-08-26 21:40:51 -07003760 err = cmd_status(sk, index, opcode,
3761 MGMT_STATUS_INVALID_INDEX);
3762 goto done;
3763 }
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003764 }
3765
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003766 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003767 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003768 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003769 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003770 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003771 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003772 }
3773
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003774 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003775 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003776 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003777 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003778 goto done;
3779 }
3780
Johan Hedbergbe22b542012-03-01 22:24:41 +02003781 handler = &mgmt_handlers[opcode];
3782
3783 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003784 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003785 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003786 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003787 goto done;
3788 }
3789
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003790 if (hdev)
3791 mgmt_init_hdev(sk, hdev);
3792
3793 cp = buf + sizeof(*hdr);
3794
Johan Hedbergbe22b542012-03-01 22:24:41 +02003795 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003796 if (err < 0)
3797 goto done;
3798
Johan Hedberg03811012010-12-08 00:21:06 +02003799 err = msglen;
3800
3801done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003802 if (hdev)
3803 hci_dev_put(hdev);
3804
Johan Hedberg03811012010-12-08 00:21:06 +02003805 kfree(buf);
3806 return err;
3807}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003808
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003809void mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003810{
Marcel Holtmann1514b892013-10-06 08:25:01 -07003811 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003812 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003813
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003814 mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003815}
3816
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003817void mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003818{
Johan Hedberg5f159032012-03-02 03:13:19 +02003819 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003820
Marcel Holtmann1514b892013-10-06 08:25:01 -07003821 if (hdev->dev_type != HCI_BREDR)
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003822 return;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003823
Johan Hedberg744cf192011-11-08 20:40:14 +02003824 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003825
Marcel Holtmannbf6b56d2013-10-06 23:55:45 -07003826 mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003827}
3828
Johan Hedberg890ea892013-03-15 17:06:52 -05003829static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003830{
Johan Hedberg890ea892013-03-15 17:06:52 -05003831 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003832 u8 scan = 0;
3833
Johan Hedberg4c01f8b2013-03-15 17:07:14 -05003834 /* Ensure that fast connectable is disabled. This function will
3835 * not do anything if the page scan parameters are already what
3836 * they should be.
3837 */
3838 write_fast_connectable(req, false);
3839
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003840 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3841 scan |= SCAN_PAGE;
3842 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3843 scan |= SCAN_INQUIRY;
3844
Johan Hedberg890ea892013-03-15 17:06:52 -05003845 if (scan)
3846 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003847}
3848
Johan Hedberg229ab392013-03-15 17:06:53 -05003849static void powered_complete(struct hci_dev *hdev, u8 status)
3850{
3851 struct cmd_lookup match = { NULL, hdev };
3852
3853 BT_DBG("status 0x%02x", status);
3854
3855 hci_dev_lock(hdev);
3856
3857 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3858
3859 new_settings(hdev, match.sk);
3860
3861 hci_dev_unlock(hdev);
3862
3863 if (match.sk)
3864 sock_put(match.sk);
3865}
3866
Johan Hedberg70da6242013-03-15 17:06:51 -05003867static int powered_update_hci(struct hci_dev *hdev)
3868{
Johan Hedberg890ea892013-03-15 17:06:52 -05003869 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003870 u8 link_sec;
3871
Johan Hedberg890ea892013-03-15 17:06:52 -05003872 hci_req_init(&req, hdev);
3873
Johan Hedberg70da6242013-03-15 17:06:51 -05003874 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3875 !lmp_host_ssp_capable(hdev)) {
3876 u8 ssp = 1;
3877
Johan Hedberg890ea892013-03-15 17:06:52 -05003878 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003879 }
3880
Johan Hedbergc73eee92013-04-19 18:35:21 +03003881 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags) &&
3882 lmp_bredr_capable(hdev)) {
Johan Hedberg70da6242013-03-15 17:06:51 -05003883 struct hci_cp_write_le_host_supported cp;
3884
3885 cp.le = 1;
3886 cp.simul = lmp_le_br_capable(hdev);
3887
3888 /* Check first if we already have the right
3889 * host state (host features set)
3890 */
3891 if (cp.le != lmp_host_le_capable(hdev) ||
3892 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003893 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3894 sizeof(cp), &cp);
Johan Hedberg0663ca22013-10-02 13:43:14 +03003895
3896 /* In case BR/EDR was toggled during the AUTO_OFF phase */
3897 hci_update_ad(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003898 }
3899
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003900 if (lmp_le_capable(hdev)) {
3901 /* Set random address to static address if configured */
3902 if (bacmp(&hdev->static_addr, BDADDR_ANY))
3903 hci_req_add(&req, HCI_OP_LE_SET_RANDOM_ADDR, 6,
3904 &hdev->static_addr);
Marcel Holtmannd13eafc2013-10-02 04:41:30 -07003905
Marcel Holtmannbba3aa52013-10-06 02:55:21 -07003906 if (test_bit(HCI_ADVERTISING, &hdev->dev_flags))
3907 enable_advertising(&req);
Johan Hedbergeeca6f82013-09-25 13:26:09 +03003908 }
3909
Johan Hedberg70da6242013-03-15 17:06:51 -05003910 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3911 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003912 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3913 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003914
3915 if (lmp_bredr_capable(hdev)) {
Johan Hedberg56f87902013-10-02 13:43:13 +03003916 if (test_bit(HCI_BREDR_ENABLED, &hdev->dev_flags))
3917 set_bredr_scan(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003918 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003919 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003920 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003921 }
3922
Johan Hedberg229ab392013-03-15 17:06:53 -05003923 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003924}
3925
Johan Hedberg744cf192011-11-08 20:40:14 +02003926int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003927{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003928 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003929 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3930 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003931 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003932
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003933 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3934 return 0;
3935
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003936 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003937 if (powered_update_hci(hdev) == 0)
3938 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003939
Johan Hedberg229ab392013-03-15 17:06:53 -05003940 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3941 &match);
3942 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003943 }
3944
Johan Hedberg229ab392013-03-15 17:06:53 -05003945 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3946 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3947
3948 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3949 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3950 zero_cod, sizeof(zero_cod), NULL);
3951
3952new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003953 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003954
3955 if (match.sk)
3956 sock_put(match.sk);
3957
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003958 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003959}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003960
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003961void mgmt_set_powered_failed(struct hci_dev *hdev, int err)
Johan Hedberg96570ff2013-05-29 09:51:29 +03003962{
3963 struct pending_cmd *cmd;
3964 u8 status;
3965
3966 cmd = mgmt_pending_find(MGMT_OP_SET_POWERED, hdev);
3967 if (!cmd)
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003968 return;
Johan Hedberg96570ff2013-05-29 09:51:29 +03003969
3970 if (err == -ERFKILL)
3971 status = MGMT_STATUS_RFKILLED;
3972 else
3973 status = MGMT_STATUS_FAILED;
3974
Marcel Holtmann3eec7052013-10-06 23:55:46 -07003975 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_POWERED, status);
Johan Hedberg96570ff2013-05-29 09:51:29 +03003976
3977 mgmt_pending_remove(cmd);
Johan Hedberg96570ff2013-05-29 09:51:29 +03003978}
3979
Johan Hedberg744cf192011-11-08 20:40:14 +02003980int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003981{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003982 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003983 bool changed = false;
3984 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003985
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003986 if (discoverable) {
3987 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3988 changed = true;
3989 } else {
3990 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3991 changed = true;
3992 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003993
Johan Hedberged9b5f22012-02-21 20:47:06 +02003994 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003995 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003996
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003997 if (changed)
3998 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003999
Johan Hedberg73f22f62010-12-29 16:00:25 +02004000 if (match.sk)
4001 sock_put(match.sk);
4002
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004003 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02004004}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004005
Johan Hedberg744cf192011-11-08 20:40:14 +02004006int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004007{
Johan Hedberg2b76f452013-03-15 17:07:04 -05004008 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004009 bool changed = false;
4010 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004011
Johan Hedberg5e5282b2012-02-21 16:01:30 +02004012 if (connectable) {
4013 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4014 changed = true;
4015 } else {
4016 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
4017 changed = true;
4018 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004019
Johan Hedberg2b76f452013-03-15 17:07:04 -05004020 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02004021
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02004022 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05004023 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004024
Johan Hedberg7bb895d2012-02-17 01:20:00 +02004025 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02004026}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004027
Johan Hedberg744cf192011-11-08 20:40:14 +02004028int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004029{
Johan Hedbergca69b792011-11-11 18:10:00 +02004030 u8 mgmt_err = mgmt_status(status);
4031
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004032 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02004033 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004034 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004035
4036 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02004037 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004038 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02004039
4040 return 0;
4041}
4042
Cristian Chilipirea53168e52012-05-09 08:44:52 +03004043int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
4044 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004045{
Johan Hedberg86742e12011-11-07 23:13:38 +02004046 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004047
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004048 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004049
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004050 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02004051 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004052 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004053 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03004054 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03004055 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004056
Johan Hedberg744cf192011-11-08 20:40:14 +02004057 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02004058}
Johan Hedbergf7520542011-01-20 12:34:39 +02004059
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004060int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
4061{
4062 struct mgmt_ev_new_long_term_key ev;
4063
4064 memset(&ev, 0, sizeof(ev));
4065
4066 ev.store_hint = persistent;
4067 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004068 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004069 ev.key.authenticated = key->authenticated;
4070 ev.key.enc_size = key->enc_size;
4071 ev.key.ediv = key->ediv;
4072
4073 if (key->type == HCI_SMP_LTK)
4074 ev.key.master = 1;
4075
4076 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
4077 memcpy(ev.key.val, key->val, sizeof(key->val));
4078
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004079 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
4080 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03004081}
4082
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004083void mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4084 u8 addr_type, u32 flags, u8 *name, u8 name_len,
4085 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02004086{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004087 char buf[512];
4088 struct mgmt_ev_device_connected *ev = (void *) buf;
4089 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02004090
Johan Hedbergb644ba32012-01-17 21:48:47 +02004091 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004092 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02004093
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02004094 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02004095
Johan Hedbergb644ba32012-01-17 21:48:47 +02004096 if (name_len > 0)
4097 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004098 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004099
4100 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08004101 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004102 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004103
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004104 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004105
Marcel Holtmannecd90ae2013-10-06 23:55:49 -07004106 mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
4107 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02004108}
4109
Johan Hedberg8962ee72011-01-20 12:40:27 +02004110static void disconnect_rsp(struct pending_cmd *cmd, void *data)
4111{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01004112 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004113 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02004114 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004115
Johan Hedberg88c3df12012-02-09 14:27:38 +02004116 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4117 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004118
Johan Hedbergaee9b212012-02-18 15:07:59 +02004119 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004120 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004121
4122 *sk = cmd->sk;
4123 sock_hold(*sk);
4124
Johan Hedberga664b5b2011-02-19 12:06:02 -03004125 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004126}
4127
Johan Hedberg124f6e32012-02-09 13:50:12 +02004128static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02004129{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004130 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02004131 struct mgmt_cp_unpair_device *cp = cmd->param;
4132 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004133
4134 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02004135 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
4136 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02004137
Johan Hedbergb1078ad2012-02-09 17:21:16 +02004138 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
4139
Johan Hedbergaee9b212012-02-18 15:07:59 +02004140 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02004141
4142 mgmt_pending_remove(cmd);
4143}
4144
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004145void mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
4146 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02004147{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004148 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004149 struct sock *sk = NULL;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004150
Johan Hedberg744cf192011-11-08 20:40:14 +02004151 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02004152
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02004153 bacpy(&ev.addr.bdaddr, bdaddr);
4154 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4155 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02004156
Marcel Holtmann9b80ec52013-10-06 23:55:50 -07004157 mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004158
4159 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01004160 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004161
Johan Hedberg124f6e32012-02-09 13:50:12 +02004162 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004163 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004164}
4165
Marcel Holtmann78929242013-10-06 23:55:47 -07004166void mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
4167 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02004168{
Johan Hedberg88c3df12012-02-09 14:27:38 +02004169 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004170 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004171
Jefferson Delfes36a75f12012-09-18 13:36:54 -04004172 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
4173 hdev);
4174
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004175 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02004176 if (!cmd)
Marcel Holtmann78929242013-10-06 23:55:47 -07004177 return;
Johan Hedberg8962ee72011-01-20 12:40:27 +02004178
Johan Hedberg88c3df12012-02-09 14:27:38 +02004179 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004180 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02004181
Marcel Holtmann78929242013-10-06 23:55:47 -07004182 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
4183 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02004184
Johan Hedberga664b5b2011-02-19 12:06:02 -03004185 mgmt_pending_remove(cmd);
Johan Hedbergf7520542011-01-20 12:34:39 +02004186}
Johan Hedberg17d5c042011-01-22 06:09:08 +02004187
Marcel Holtmann445608d2013-10-06 23:55:48 -07004188void mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4189 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02004190{
4191 struct mgmt_ev_connect_failed ev;
4192
Johan Hedberg4c659c32011-11-07 23:13:39 +02004193 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004194 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004195 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004196
Marcel Holtmann445608d2013-10-06 23:55:48 -07004197 mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02004198}
Johan Hedberg980e1a52011-01-22 06:10:07 +02004199
Johan Hedberg744cf192011-11-08 20:40:14 +02004200int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004201{
4202 struct mgmt_ev_pin_code_request ev;
4203
Johan Hedbergd8457692012-02-17 14:24:57 +02004204 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004205 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02004206 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004207
Johan Hedberg744cf192011-11-08 20:40:14 +02004208 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004209 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004210}
4211
Johan Hedberg744cf192011-11-08 20:40:14 +02004212int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004213 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004214{
4215 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004216 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004217 int err;
4218
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004219 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004220 if (!cmd)
4221 return -ENOENT;
4222
Johan Hedbergd8457692012-02-17 14:24:57 +02004223 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004224 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004225
Johan Hedbergaee9b212012-02-18 15:07:59 +02004226 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004227 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004228
Johan Hedberga664b5b2011-02-19 12:06:02 -03004229 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004230
4231 return err;
4232}
4233
Johan Hedberg744cf192011-11-08 20:40:14 +02004234int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004235 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02004236{
4237 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004238 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02004239 int err;
4240
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004241 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004242 if (!cmd)
4243 return -ENOENT;
4244
Johan Hedbergd8457692012-02-17 14:24:57 +02004245 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03004246 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03004247
Johan Hedbergaee9b212012-02-18 15:07:59 +02004248 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004249 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02004250
Johan Hedberga664b5b2011-02-19 12:06:02 -03004251 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02004252
4253 return err;
4254}
Johan Hedberga5c29682011-02-19 12:05:57 -03004255
Johan Hedberg744cf192011-11-08 20:40:14 +02004256int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004257 u8 link_type, u8 addr_type, __le32 value,
4258 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03004259{
4260 struct mgmt_ev_user_confirm_request ev;
4261
Johan Hedberg744cf192011-11-08 20:40:14 +02004262 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03004263
Johan Hedberg272d90d2012-02-09 15:26:12 +02004264 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004265 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07004266 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02004267 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03004268
Johan Hedberg744cf192011-11-08 20:40:14 +02004269 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004270 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03004271}
4272
Johan Hedberg272d90d2012-02-09 15:26:12 +02004273int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004274 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08004275{
4276 struct mgmt_ev_user_passkey_request ev;
4277
4278 BT_DBG("%s", hdev->name);
4279
Johan Hedberg272d90d2012-02-09 15:26:12 +02004280 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004281 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08004282
4283 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004284 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08004285}
4286
Brian Gix0df4c182011-11-16 13:53:13 -08004287static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03004288 u8 link_type, u8 addr_type, u8 status,
4289 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03004290{
4291 struct pending_cmd *cmd;
4292 struct mgmt_rp_user_confirm_reply rp;
4293 int err;
4294
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004295 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03004296 if (!cmd)
4297 return -ENOENT;
4298
Johan Hedberg272d90d2012-02-09 15:26:12 +02004299 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004300 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02004301 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004302 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03004303
Johan Hedberga664b5b2011-02-19 12:06:02 -03004304 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03004305
4306 return err;
4307}
4308
Johan Hedberg744cf192011-11-08 20:40:14 +02004309int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004310 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004311{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004312 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004313 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004314}
4315
Johan Hedberg272d90d2012-02-09 15:26:12 +02004316int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004317 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03004318{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004319 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004320 status,
4321 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03004322}
Johan Hedberg2a611692011-02-19 12:06:00 -03004323
Brian Gix604086b2011-11-23 08:28:33 -08004324int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004325 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004326{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004327 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004328 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004329}
4330
Johan Hedberg272d90d2012-02-09 15:26:12 +02004331int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004332 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08004333{
Johan Hedberg272d90d2012-02-09 15:26:12 +02004334 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03004335 status,
4336 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08004337}
4338
Johan Hedberg92a25252012-09-06 18:39:26 +03004339int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
4340 u8 link_type, u8 addr_type, u32 passkey,
4341 u8 entered)
4342{
4343 struct mgmt_ev_passkey_notify ev;
4344
4345 BT_DBG("%s", hdev->name);
4346
4347 bacpy(&ev.addr.bdaddr, bdaddr);
4348 ev.addr.type = link_to_bdaddr(link_type, addr_type);
4349 ev.passkey = __cpu_to_le32(passkey);
4350 ev.entered = entered;
4351
4352 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
4353}
4354
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004355int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004356 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03004357{
4358 struct mgmt_ev_auth_failed ev;
4359
Johan Hedbergbab73cb2012-02-09 16:07:29 +02004360 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004361 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02004362 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03004363
Johan Hedberg744cf192011-11-08 20:40:14 +02004364 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03004365}
Johan Hedbergb312b1612011-03-16 14:29:37 +02004366
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004367int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
4368{
4369 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02004370 bool changed = false;
4371 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004372
4373 if (status) {
4374 u8 mgmt_err = mgmt_status(status);
4375 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004376 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004377 return 0;
4378 }
4379
Johan Hedberg47990ea2012-02-22 11:58:37 +02004380 if (test_bit(HCI_AUTH, &hdev->flags)) {
4381 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4382 changed = true;
4383 } else {
4384 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
4385 changed = true;
4386 }
4387
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004388 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004389 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004390
Johan Hedberg47990ea2012-02-22 11:58:37 +02004391 if (changed)
4392 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02004393
4394 if (match.sk)
4395 sock_put(match.sk);
4396
4397 return err;
4398}
4399
Johan Hedberg890ea892013-03-15 17:06:52 -05004400static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02004401{
Johan Hedberg890ea892013-03-15 17:06:52 -05004402 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004403 struct hci_cp_write_eir cp;
4404
Johan Hedberg976eb202012-10-24 21:12:01 +03004405 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05004406 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02004407
Johan Hedbergc80da272012-02-22 15:38:48 +02004408 memset(hdev->eir, 0, sizeof(hdev->eir));
4409
Johan Hedbergcacaf522012-02-21 00:52:42 +02004410 memset(&cp, 0, sizeof(cp));
4411
Johan Hedberg890ea892013-03-15 17:06:52 -05004412 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004413}
4414
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004415int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004416{
4417 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05004418 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004419 bool changed = false;
4420 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004421
4422 if (status) {
4423 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004424
4425 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004426 &hdev->dev_flags)) {
4427 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004428 err = new_settings(hdev, NULL);
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004429 }
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004430
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004431 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
4432 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004433
4434 return err;
4435 }
4436
4437 if (enable) {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004438 changed = !test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004439 } else {
Marcel Holtmann9ecb3e22013-10-10 03:08:11 -07004440 changed = test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
4441 if (!changed)
4442 changed = test_and_clear_bit(HCI_HS_ENABLED,
4443 &hdev->dev_flags);
4444 else
4445 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004446 }
4447
4448 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
4449
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02004450 if (changed)
4451 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004452
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004453 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004454 sock_put(match.sk);
4455
Johan Hedberg890ea892013-03-15 17:06:52 -05004456 hci_req_init(&req, hdev);
4457
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004458 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05004459 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02004460 else
Johan Hedberg890ea892013-03-15 17:06:52 -05004461 clear_eir(&req);
4462
4463 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02004464
Johan Hedberged2c4ee2012-02-17 00:56:28 +02004465 return err;
4466}
4467
Johan Hedberg92da6092013-03-15 17:06:55 -05004468static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02004469{
4470 struct cmd_lookup *match = data;
4471
Johan Hedberg90e70452012-02-23 23:09:40 +02004472 if (match->sk == NULL) {
4473 match->sk = cmd->sk;
4474 sock_hold(match->sk);
4475 }
Johan Hedberg90e70452012-02-23 23:09:40 +02004476}
4477
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004478int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004479 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004480{
Johan Hedberg90e70452012-02-23 23:09:40 +02004481 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
4482 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004483
Johan Hedberg92da6092013-03-15 17:06:55 -05004484 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
4485 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
4486 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02004487
4488 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004489 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
4490 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02004491
4492 if (match.sk)
4493 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01004494
4495 return err;
4496}
4497
Johan Hedberg744cf192011-11-08 20:40:14 +02004498int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02004499{
Johan Hedbergb312b1612011-03-16 14:29:37 +02004500 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05004501 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004502
Johan Hedberg13928972013-03-15 17:07:00 -05004503 if (status)
4504 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004505
4506 memset(&ev, 0, sizeof(ev));
4507 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02004508 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004509
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004510 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05004511 if (!cmd) {
4512 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02004513
Johan Hedberg13928972013-03-15 17:07:00 -05004514 /* If this is a HCI command related to powering on the
4515 * HCI dev don't send any mgmt signals.
4516 */
4517 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
4518 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02004519 }
4520
Johan Hedberg13928972013-03-15 17:07:00 -05004521 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
4522 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02004523}
Szymon Jancc35938b2011-03-22 13:12:21 +01004524
Johan Hedberg744cf192011-11-08 20:40:14 +02004525int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004526 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01004527{
4528 struct pending_cmd *cmd;
4529 int err;
4530
Johan Hedberg744cf192011-11-08 20:40:14 +02004531 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01004532
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004533 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01004534 if (!cmd)
4535 return -ENOENT;
4536
4537 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004538 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
4539 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01004540 } else {
4541 struct mgmt_rp_read_local_oob_data rp;
4542
4543 memcpy(rp.hash, hash, sizeof(rp.hash));
4544 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
4545
Johan Hedberg744cf192011-11-08 20:40:14 +02004546 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004547 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
4548 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01004549 }
4550
4551 mgmt_pending_remove(cmd);
4552
4553 return err;
4554}
Johan Hedberge17acd42011-03-30 23:57:16 +03004555
Marcel Holtmann901801b2013-10-06 23:55:51 -07004556void mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4557 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4558 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004559{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004560 char buf[512];
4561 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004562 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004563
Andre Guedes12602d02013-04-30 15:29:40 -03004564 if (!hci_discovery_active(hdev))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004565 return;
Andre Guedes12602d02013-04-30 15:29:40 -03004566
Johan Hedberg1dc06092012-01-15 21:01:23 +02004567 /* Leave 5 bytes for a potential CoD field */
4568 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Marcel Holtmann901801b2013-10-06 23:55:51 -07004569 return;
Andre Guedes7d262f82012-01-10 18:20:49 -03004570
Johan Hedberg1dc06092012-01-15 21:01:23 +02004571 memset(buf, 0, sizeof(buf));
4572
Johan Hedberge319d2e2012-01-15 19:51:59 +02004573 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004574 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004575 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004576 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304577 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004578 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304579 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004580
Johan Hedberg1dc06092012-01-15 21:01:23 +02004581 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004582 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004583
Johan Hedberg1dc06092012-01-15 21:01:23 +02004584 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4585 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004586 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004587
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004588 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004589 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004590
Marcel Holtmann901801b2013-10-06 23:55:51 -07004591 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004592}
Johan Hedberga88a9652011-03-30 13:18:12 +03004593
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004594void mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
4595 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004596{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004597 struct mgmt_ev_device_found *ev;
4598 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4599 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004600
Johan Hedbergb644ba32012-01-17 21:48:47 +02004601 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004602
Johan Hedbergb644ba32012-01-17 21:48:47 +02004603 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004604
Johan Hedbergb644ba32012-01-17 21:48:47 +02004605 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004606 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004607 ev->rssi = rssi;
4608
4609 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004610 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004611
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004612 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004613
Marcel Holtmann9cf12ae2013-10-06 23:55:52 -07004614 mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004615}
Johan Hedberg314b2382011-04-27 10:29:57 -04004616
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004617void mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004618{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004619 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004620 struct pending_cmd *cmd;
4621
Andre Guedes343fb142011-11-22 17:14:19 -03004622 BT_DBG("%s discovering %u", hdev->name, discovering);
4623
Johan Hedberg164a6e72011-11-01 17:06:44 +02004624 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004625 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004626 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004627 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004628
4629 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004630 u8 type = hdev->discovery.type;
4631
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004632 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4633 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004634 mgmt_pending_remove(cmd);
4635 }
4636
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004637 memset(&ev, 0, sizeof(ev));
4638 ev.type = hdev->discovery.type;
4639 ev.discovering = discovering;
4640
Marcel Holtmann2f1e0632013-10-06 23:55:53 -07004641 mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004642}
Antti Julku5e762442011-08-25 16:48:02 +03004643
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004644int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004645{
4646 struct pending_cmd *cmd;
4647 struct mgmt_ev_device_blocked ev;
4648
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004649 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004650
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004651 bacpy(&ev.addr.bdaddr, bdaddr);
4652 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004653
Johan Hedberg744cf192011-11-08 20:40:14 +02004654 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004655 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004656}
4657
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004658int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004659{
4660 struct pending_cmd *cmd;
4661 struct mgmt_ev_device_unblocked ev;
4662
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004663 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004664
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004665 bacpy(&ev.addr.bdaddr, bdaddr);
4666 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004667
Johan Hedberg744cf192011-11-08 20:40:14 +02004668 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004669 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004670}
Marcel Holtmann5976e602013-10-06 04:08:14 -07004671
4672static void adv_enable_complete(struct hci_dev *hdev, u8 status)
4673{
4674 BT_DBG("%s status %u", hdev->name, status);
4675
4676 /* Clear the advertising mgmt setting if we failed to re-enable it */
4677 if (status) {
4678 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004679 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004680 }
4681}
4682
4683void mgmt_reenable_advertising(struct hci_dev *hdev)
4684{
4685 struct hci_request req;
4686
Marcel Holtmannb145edc2013-10-10 09:47:54 -07004687 if (hci_conn_num(hdev, LE_LINK) > 0)
Marcel Holtmann5976e602013-10-06 04:08:14 -07004688 return;
4689
4690 if (!test_bit(HCI_ADVERTISING, &hdev->dev_flags))
4691 return;
4692
4693 hci_req_init(&req, hdev);
4694 enable_advertising(&req);
4695
4696 /* If this fails we have no option but to let user space know
4697 * that we've disabled advertising.
4698 */
4699 if (hci_req_run(&req, adv_enable_complete) < 0) {
4700 clear_bit(HCI_ADVERTISING, &hdev->dev_flags);
Marcel Holtmanna6d811e2013-10-06 04:11:12 -07004701 new_settings(hdev, NULL);
Marcel Holtmann5976e602013-10-06 04:08:14 -07004702 }
4703}