blob: 98f6295edbecd791b777ebfca7dc0f7cbce4dda5 [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>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010035bool enable_hs;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010036
Johan Hedberg2da9c552012-02-17 14:39:28 +020037#define MGMT_VERSION 1
Johan Hedberg38102852013-01-27 08:32:01 -060038#define MGMT_REVISION 3
Johan Hedberg02d98122010-12-13 21:07:04 +020039
Johan Hedberge70bb2e2012-02-13 16:59:33 +020040static const u16 mgmt_commands[] = {
41 MGMT_OP_READ_INDEX_LIST,
42 MGMT_OP_READ_INFO,
43 MGMT_OP_SET_POWERED,
44 MGMT_OP_SET_DISCOVERABLE,
45 MGMT_OP_SET_CONNECTABLE,
46 MGMT_OP_SET_FAST_CONNECTABLE,
47 MGMT_OP_SET_PAIRABLE,
48 MGMT_OP_SET_LINK_SECURITY,
49 MGMT_OP_SET_SSP,
50 MGMT_OP_SET_HS,
51 MGMT_OP_SET_LE,
52 MGMT_OP_SET_DEV_CLASS,
53 MGMT_OP_SET_LOCAL_NAME,
54 MGMT_OP_ADD_UUID,
55 MGMT_OP_REMOVE_UUID,
56 MGMT_OP_LOAD_LINK_KEYS,
57 MGMT_OP_LOAD_LONG_TERM_KEYS,
58 MGMT_OP_DISCONNECT,
59 MGMT_OP_GET_CONNECTIONS,
60 MGMT_OP_PIN_CODE_REPLY,
61 MGMT_OP_PIN_CODE_NEG_REPLY,
62 MGMT_OP_SET_IO_CAPABILITY,
63 MGMT_OP_PAIR_DEVICE,
64 MGMT_OP_CANCEL_PAIR_DEVICE,
65 MGMT_OP_UNPAIR_DEVICE,
66 MGMT_OP_USER_CONFIRM_REPLY,
67 MGMT_OP_USER_CONFIRM_NEG_REPLY,
68 MGMT_OP_USER_PASSKEY_REPLY,
69 MGMT_OP_USER_PASSKEY_NEG_REPLY,
70 MGMT_OP_READ_LOCAL_OOB_DATA,
71 MGMT_OP_ADD_REMOTE_OOB_DATA,
72 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
73 MGMT_OP_START_DISCOVERY,
74 MGMT_OP_STOP_DISCOVERY,
75 MGMT_OP_CONFIRM_NAME,
76 MGMT_OP_BLOCK_DEVICE,
77 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070078 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020079};
80
81static const u16 mgmt_events[] = {
82 MGMT_EV_CONTROLLER_ERROR,
83 MGMT_EV_INDEX_ADDED,
84 MGMT_EV_INDEX_REMOVED,
85 MGMT_EV_NEW_SETTINGS,
86 MGMT_EV_CLASS_OF_DEV_CHANGED,
87 MGMT_EV_LOCAL_NAME_CHANGED,
88 MGMT_EV_NEW_LINK_KEY,
89 MGMT_EV_NEW_LONG_TERM_KEY,
90 MGMT_EV_DEVICE_CONNECTED,
91 MGMT_EV_DEVICE_DISCONNECTED,
92 MGMT_EV_CONNECT_FAILED,
93 MGMT_EV_PIN_CODE_REQUEST,
94 MGMT_EV_USER_CONFIRM_REQUEST,
95 MGMT_EV_USER_PASSKEY_REQUEST,
96 MGMT_EV_AUTH_FAILED,
97 MGMT_EV_DEVICE_FOUND,
98 MGMT_EV_DISCOVERING,
99 MGMT_EV_DEVICE_BLOCKED,
100 MGMT_EV_DEVICE_UNBLOCKED,
101 MGMT_EV_DEVICE_UNPAIRED,
Johan Hedberg92a25252012-09-06 18:39:26 +0300102 MGMT_EV_PASSKEY_NOTIFY,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200103};
104
Andre Guedes3fd24152012-02-03 17:48:01 -0300105/*
106 * These LE scan and inquiry parameters were chosen according to LE General
107 * Discovery Procedure specification.
108 */
109#define LE_SCAN_TYPE 0x01
110#define LE_SCAN_WIN 0x12
111#define LE_SCAN_INT 0x12
112#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300113#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300114
Andre Guedese8777522012-02-03 17:48:02 -0300115#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300116#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300117
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800118#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200119
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200120#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
121 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
122
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200123struct pending_cmd {
124 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200125 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200126 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100127 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200128 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300129 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200130};
131
Johan Hedbergca69b792011-11-11 18:10:00 +0200132/* HCI to MGMT error code conversion table */
133static u8 mgmt_status_table[] = {
134 MGMT_STATUS_SUCCESS,
135 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
136 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
137 MGMT_STATUS_FAILED, /* Hardware Failure */
138 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
139 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
140 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
141 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
142 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
143 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
145 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
146 MGMT_STATUS_BUSY, /* Command Disallowed */
147 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
148 MGMT_STATUS_REJECTED, /* Rejected Security */
149 MGMT_STATUS_REJECTED, /* Rejected Personal */
150 MGMT_STATUS_TIMEOUT, /* Host Timeout */
151 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
152 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
153 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
154 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
155 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
156 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
157 MGMT_STATUS_BUSY, /* Repeated Attempts */
158 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
159 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
160 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
161 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
162 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
163 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
164 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
165 MGMT_STATUS_FAILED, /* Unspecified Error */
166 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
167 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
168 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
169 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
170 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
171 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
172 MGMT_STATUS_FAILED, /* Unit Link Key Used */
173 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
174 MGMT_STATUS_TIMEOUT, /* Instant Passed */
175 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
176 MGMT_STATUS_FAILED, /* Transaction Collision */
177 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
178 MGMT_STATUS_REJECTED, /* QoS Rejected */
179 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
180 MGMT_STATUS_REJECTED, /* Insufficient Security */
181 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
182 MGMT_STATUS_BUSY, /* Role Switch Pending */
183 MGMT_STATUS_FAILED, /* Slot Violation */
184 MGMT_STATUS_FAILED, /* Role Switch Failed */
185 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
186 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
187 MGMT_STATUS_BUSY, /* Host Busy Pairing */
188 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
189 MGMT_STATUS_BUSY, /* Controller Busy */
190 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
191 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
192 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
193 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
194 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
195};
196
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300197bool mgmt_valid_hdev(struct hci_dev *hdev)
198{
199 return hdev->dev_type == HCI_BREDR;
200}
201
Johan Hedbergca69b792011-11-11 18:10:00 +0200202static u8 mgmt_status(u8 hci_status)
203{
204 if (hci_status < ARRAY_SIZE(mgmt_status_table))
205 return mgmt_status_table[hci_status];
206
207 return MGMT_STATUS_FAILED;
208}
209
Szymon Janc4e51eae2011-02-25 19:05:48 +0100210static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200211{
212 struct sk_buff *skb;
213 struct mgmt_hdr *hdr;
214 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300215 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200216
Szymon Janc34eb5252011-02-28 14:10:08 +0100217 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200218
Andre Guedes790eff42012-06-07 19:05:46 -0300219 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200220 if (!skb)
221 return -ENOMEM;
222
223 hdr = (void *) skb_put(skb, sizeof(*hdr));
224
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530225 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100226 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200227 hdr->len = cpu_to_le16(sizeof(*ev));
228
229 ev = (void *) skb_put(skb, sizeof(*ev));
230 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200231 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 err = sock_queue_rcv_skb(sk, skb);
234 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200235 kfree_skb(skb);
236
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300237 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200238}
239
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200240static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300241 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200242{
243 struct sk_buff *skb;
244 struct mgmt_hdr *hdr;
245 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300246 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200247
248 BT_DBG("sock %p", sk);
249
Andre Guedes790eff42012-06-07 19:05:46 -0300250 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_KERNEL);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251 if (!skb)
252 return -ENOMEM;
253
254 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200255
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530256 hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100257 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200258 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200259
Johan Hedberga38528f2011-01-22 06:46:43 +0200260 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200261 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200262 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100263
264 if (rp)
265 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200266
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300267 err = sock_queue_rcv_skb(sk, skb);
268 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200269 kfree_skb(skb);
270
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100271 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200272}
273
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300274static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
275 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200276{
277 struct mgmt_rp_read_version rp;
278
279 BT_DBG("sock %p", sk);
280
281 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200282 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200283
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200284 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300285 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200286}
287
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300288static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
289 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200290{
291 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200292 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
293 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200294 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200295 size_t rp_size;
296 int i, err;
297
298 BT_DBG("sock %p", sk);
299
300 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
301
302 rp = kmalloc(rp_size, GFP_KERNEL);
303 if (!rp)
304 return -ENOMEM;
305
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200306 rp->num_commands = __constant_cpu_to_le16(num_commands);
307 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200308
309 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
310 put_unaligned_le16(mgmt_commands[i], opcode);
311
312 for (i = 0; i < num_events; i++, opcode++)
313 put_unaligned_le16(mgmt_events[i], opcode);
314
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200315 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300316 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200317 kfree(rp);
318
319 return err;
320}
321
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300322static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
323 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200325 struct mgmt_rp_read_index_list *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200326 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200327 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328 u16 count;
Johan Hedberg476e44c2012-10-19 20:10:46 +0300329 int err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330
331 BT_DBG("sock %p", sk);
332
333 read_lock(&hci_dev_list_lock);
334
335 count = 0;
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300336 list_for_each_entry(d, &hci_dev_list, list) {
337 if (!mgmt_valid_hdev(d))
338 continue;
339
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340 count++;
341 }
342
Johan Hedberga38528f2011-01-22 06:46:43 +0200343 rp_len = sizeof(*rp) + (2 * count);
344 rp = kmalloc(rp_len, GFP_ATOMIC);
345 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100346 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200347 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100348 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200349
Johan Hedberg476e44c2012-10-19 20:10:46 +0300350 count = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200351 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200352 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200353 continue;
354
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +0300355 if (!mgmt_valid_hdev(d))
356 continue;
357
Johan Hedberg476e44c2012-10-19 20:10:46 +0300358 rp->index[count++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359 BT_DBG("Added hci%u", d->id);
360 }
361
Johan Hedberg476e44c2012-10-19 20:10:46 +0300362 rp->num_controllers = cpu_to_le16(count);
363 rp_len = sizeof(*rp) + (2 * count);
364
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200365 read_unlock(&hci_dev_list_lock);
366
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200367 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300368 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200369
Johan Hedberga38528f2011-01-22 06:46:43 +0200370 kfree(rp);
371
372 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200373}
374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200376{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200377 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200378
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200379 settings |= MGMT_SETTING_POWERED;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200380 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200381
Andre Guedes9a1a1992012-07-24 15:03:48 -0300382 if (lmp_ssp_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200383 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200384
Andre Guedesed3fa312012-07-24 15:03:46 -0300385 if (lmp_bredr_capable(hdev)) {
Johan Hedberg33c525c2012-10-24 21:11:58 +0300386 settings |= MGMT_SETTING_CONNECTABLE;
Johan Hedberg1a47aee2013-03-15 17:07:06 -0500387 if (hdev->hci_ver >= BLUETOOTH_VER_1_2)
388 settings |= MGMT_SETTING_FAST_CONNECTABLE;
Johan Hedberg33c525c2012-10-24 21:11:58 +0300389 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200390 settings |= MGMT_SETTING_BREDR;
391 settings |= MGMT_SETTING_LINK_SECURITY;
392 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200393
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100394 if (enable_hs)
395 settings |= MGMT_SETTING_HS;
396
Andre Guedesc383ddc2012-07-24 15:03:47 -0300397 if (lmp_le_capable(hdev))
Marcel Holtmann9d428202012-05-03 07:12:31 +0200398 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200399
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200400 return settings;
401}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200402
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403static u32 get_current_settings(struct hci_dev *hdev)
404{
405 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200406
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200407 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100408 settings |= MGMT_SETTING_POWERED;
409
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200410 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_CONNECTABLE;
412
Johan Hedberg1a4d3c42013-03-15 17:07:08 -0500413 if (test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
414 settings |= MGMT_SETTING_FAST_CONNECTABLE;
415
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200416 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_DISCOVERABLE;
418
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200419 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_PAIRABLE;
421
Andre Guedesed3fa312012-07-24 15:03:46 -0300422 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200423 settings |= MGMT_SETTING_BREDR;
424
Johan Hedberg06199cf2012-02-22 16:37:11 +0200425 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200426 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200427
Johan Hedberg47990ea2012-02-22 11:58:37 +0200428 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200429 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200430
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200431 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200432 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200433
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200434 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
435 settings |= MGMT_SETTING_HS;
436
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200437 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200438}
439
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300440#define PNP_INFO_SVCLASS_ID 0x1200
441
Johan Hedberg213202e2013-01-27 00:31:33 +0200442static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
443{
444 u8 *ptr = data, *uuids_start = NULL;
445 struct bt_uuid *uuid;
446
447 if (len < 4)
448 return ptr;
449
450 list_for_each_entry(uuid, &hdev->uuids, list) {
451 u16 uuid16;
452
453 if (uuid->size != 16)
454 continue;
455
456 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
457 if (uuid16 < 0x1100)
458 continue;
459
460 if (uuid16 == PNP_INFO_SVCLASS_ID)
461 continue;
462
463 if (!uuids_start) {
464 uuids_start = ptr;
465 uuids_start[0] = 1;
466 uuids_start[1] = EIR_UUID16_ALL;
467 ptr += 2;
468 }
469
470 /* Stop if not enough space to put next UUID */
471 if ((ptr - data) + sizeof(u16) > len) {
472 uuids_start[1] = EIR_UUID16_SOME;
473 break;
474 }
475
476 *ptr++ = (uuid16 & 0x00ff);
477 *ptr++ = (uuid16 & 0xff00) >> 8;
478 uuids_start[0] += sizeof(uuid16);
479 }
480
481 return ptr;
482}
483
Johan Hedbergcdf19632013-01-27 00:31:34 +0200484static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
485{
486 u8 *ptr = data, *uuids_start = NULL;
487 struct bt_uuid *uuid;
488
489 if (len < 6)
490 return ptr;
491
492 list_for_each_entry(uuid, &hdev->uuids, list) {
493 if (uuid->size != 32)
494 continue;
495
496 if (!uuids_start) {
497 uuids_start = ptr;
498 uuids_start[0] = 1;
499 uuids_start[1] = EIR_UUID32_ALL;
500 ptr += 2;
501 }
502
503 /* Stop if not enough space to put next UUID */
504 if ((ptr - data) + sizeof(u32) > len) {
505 uuids_start[1] = EIR_UUID32_SOME;
506 break;
507 }
508
509 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
510 ptr += sizeof(u32);
511 uuids_start[0] += sizeof(u32);
512 }
513
514 return ptr;
515}
516
Johan Hedbergc00d5752013-01-27 00:31:35 +0200517static u8 *create_uuid128_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
518{
519 u8 *ptr = data, *uuids_start = NULL;
520 struct bt_uuid *uuid;
521
522 if (len < 18)
523 return ptr;
524
525 list_for_each_entry(uuid, &hdev->uuids, list) {
526 if (uuid->size != 128)
527 continue;
528
529 if (!uuids_start) {
530 uuids_start = ptr;
531 uuids_start[0] = 1;
532 uuids_start[1] = EIR_UUID128_ALL;
533 ptr += 2;
534 }
535
536 /* Stop if not enough space to put next UUID */
537 if ((ptr - data) + 16 > len) {
538 uuids_start[1] = EIR_UUID128_SOME;
539 break;
540 }
541
542 memcpy(ptr, uuid->uuid, 16);
543 ptr += 16;
544 uuids_start[0] += 16;
545 }
546
547 return ptr;
548}
549
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300550static void create_eir(struct hci_dev *hdev, u8 *data)
551{
552 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300553 size_t name_len;
554
555 name_len = strlen(hdev->dev_name);
556
557 if (name_len > 0) {
558 /* EIR Data type */
559 if (name_len > 48) {
560 name_len = 48;
561 ptr[1] = EIR_NAME_SHORT;
562 } else
563 ptr[1] = EIR_NAME_COMPLETE;
564
565 /* EIR Data length */
566 ptr[0] = name_len + 1;
567
568 memcpy(ptr + 2, hdev->dev_name, name_len);
569
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300570 ptr += (name_len + 2);
571 }
572
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100573 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700574 ptr[0] = 2;
575 ptr[1] = EIR_TX_POWER;
576 ptr[2] = (u8) hdev->inq_tx_power;
577
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700578 ptr += 3;
579 }
580
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700581 if (hdev->devid_source > 0) {
582 ptr[0] = 9;
583 ptr[1] = EIR_DEVICE_ID;
584
585 put_unaligned_le16(hdev->devid_source, ptr + 2);
586 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
587 put_unaligned_le16(hdev->devid_product, ptr + 6);
588 put_unaligned_le16(hdev->devid_version, ptr + 8);
589
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700590 ptr += 10;
591 }
592
Johan Hedberg213202e2013-01-27 00:31:33 +0200593 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200594 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergc00d5752013-01-27 00:31:35 +0200595 ptr = create_uuid128_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300596}
597
Johan Hedberg890ea892013-03-15 17:06:52 -0500598static void update_eir(struct hci_request *req)
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300599{
Johan Hedberg890ea892013-03-15 17:06:52 -0500600 struct hci_dev *hdev = req->hdev;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300601 struct hci_cp_write_eir cp;
602
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200603 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500604 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200605
Johan Hedberg976eb202012-10-24 21:12:01 +0300606 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500607 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300608
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200609 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500610 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300611
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200612 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500613 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300614
615 memset(&cp, 0, sizeof(cp));
616
617 create_eir(hdev, cp.data);
618
619 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500620 return;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300621
622 memcpy(hdev->eir, cp.data, sizeof(cp.data));
623
Johan Hedberg890ea892013-03-15 17:06:52 -0500624 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300625}
626
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200627static u8 get_service_classes(struct hci_dev *hdev)
628{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300629 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200630 u8 val = 0;
631
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300632 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200633 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200634
635 return val;
636}
637
Johan Hedberg890ea892013-03-15 17:06:52 -0500638static void update_class(struct hci_request *req)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200639{
Johan Hedberg890ea892013-03-15 17:06:52 -0500640 struct hci_dev *hdev = req->hdev;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200641 u8 cod[3];
642
643 BT_DBG("%s", hdev->name);
644
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200645 if (!hdev_is_powered(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -0500646 return;
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200647
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200648 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -0500649 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200650
651 cod[0] = hdev->minor_class;
652 cod[1] = hdev->major_class;
653 cod[2] = get_service_classes(hdev);
654
655 if (memcmp(cod, hdev->dev_class, 3) == 0)
Johan Hedberg890ea892013-03-15 17:06:52 -0500656 return;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200657
Johan Hedberg890ea892013-03-15 17:06:52 -0500658 hci_req_add(req, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200659}
660
Johan Hedberg7d785252011-12-15 00:47:39 +0200661static void service_cache_off(struct work_struct *work)
662{
663 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300664 service_cache.work);
Johan Hedberg890ea892013-03-15 17:06:52 -0500665 struct hci_request req;
Johan Hedberg7d785252011-12-15 00:47:39 +0200666
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200667 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200668 return;
669
Johan Hedberg890ea892013-03-15 17:06:52 -0500670 hci_req_init(&req, hdev);
671
Johan Hedberg7d785252011-12-15 00:47:39 +0200672 hci_dev_lock(hdev);
673
Johan Hedberg890ea892013-03-15 17:06:52 -0500674 update_eir(&req);
675 update_class(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +0200676
677 hci_dev_unlock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -0500678
679 hci_req_run(&req, NULL);
Johan Hedberg7d785252011-12-15 00:47:39 +0200680}
681
Johan Hedberg6a919082012-02-28 06:17:26 +0200682static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200683{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200684 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200685 return;
686
Johan Hedberg4f87da82012-03-02 19:55:56 +0200687 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200688
Johan Hedberg4f87da82012-03-02 19:55:56 +0200689 /* Non-mgmt controlled devices get this bit set
690 * implicitly so that pairing works for them, however
691 * for mgmt we require user-space to explicitly enable
692 * it
693 */
694 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200695}
696
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200697static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300698 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200699{
700 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200701
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200702 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200703
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300704 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200705
Johan Hedberg03811012010-12-08 00:21:06 +0200706 memset(&rp, 0, sizeof(rp));
707
Johan Hedberg03811012010-12-08 00:21:06 +0200708 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200709
710 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200711 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200712
713 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
714 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
715
716 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200717
718 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200719 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200720
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300721 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200722
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200723 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300724 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200725}
726
727static void mgmt_pending_free(struct pending_cmd *cmd)
728{
729 sock_put(cmd->sk);
730 kfree(cmd->param);
731 kfree(cmd);
732}
733
734static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300735 struct hci_dev *hdev, void *data,
736 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200737{
738 struct pending_cmd *cmd;
739
Andre Guedes12b94562012-06-07 19:05:45 -0300740 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200741 if (!cmd)
742 return NULL;
743
744 cmd->opcode = opcode;
745 cmd->index = hdev->id;
746
Andre Guedes12b94562012-06-07 19:05:45 -0300747 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200748 if (!cmd->param) {
749 kfree(cmd);
750 return NULL;
751 }
752
753 if (data)
754 memcpy(cmd->param, data, len);
755
756 cmd->sk = sk;
757 sock_hold(sk);
758
759 list_add(&cmd->list, &hdev->mgmt_pending);
760
761 return cmd;
762}
763
764static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300765 void (*cb)(struct pending_cmd *cmd,
766 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300767 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200768{
Andre Guedesa3d09352013-02-01 11:21:30 -0300769 struct pending_cmd *cmd, *tmp;
Johan Hedberg03811012010-12-08 00:21:06 +0200770
Andre Guedesa3d09352013-02-01 11:21:30 -0300771 list_for_each_entry_safe(cmd, tmp, &hdev->mgmt_pending, list) {
Johan Hedberg03811012010-12-08 00:21:06 +0200772 if (opcode > 0 && cmd->opcode != opcode)
773 continue;
774
775 cb(cmd, data);
776 }
777}
778
779static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
780{
781 struct pending_cmd *cmd;
782
783 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
784 if (cmd->opcode == opcode)
785 return cmd;
786 }
787
788 return NULL;
789}
790
791static void mgmt_pending_remove(struct pending_cmd *cmd)
792{
793 list_del(&cmd->list);
794 mgmt_pending_free(cmd);
795}
796
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200797static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200798{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200799 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200800
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200801 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300802 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200803}
804
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200805static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300806 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200807{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300808 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200809 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200810 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200811
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200812 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200813
Johan Hedberga7e80f22013-01-09 16:05:19 +0200814 if (cp->val != 0x00 && cp->val != 0x01)
815 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
816 MGMT_STATUS_INVALID_PARAMS);
817
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300818 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200819
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100820 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
821 cancel_delayed_work(&hdev->power_off);
822
823 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200824 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
825 data, len);
826 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100827 goto failed;
828 }
829 }
830
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200831 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200832 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200833 goto failed;
834 }
835
836 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200837 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300838 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200839 goto failed;
840 }
841
842 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
843 if (!cmd) {
844 err = -ENOMEM;
845 goto failed;
846 }
847
848 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200849 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200850 else
Johan Hedberg19202572013-01-14 22:33:51 +0200851 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200852
853 err = 0;
854
855failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300856 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200857 return err;
858}
859
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300860static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
861 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200862{
863 struct sk_buff *skb;
864 struct mgmt_hdr *hdr;
865
Andre Guedes790eff42012-06-07 19:05:46 -0300866 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200867 if (!skb)
868 return -ENOMEM;
869
870 hdr = (void *) skb_put(skb, sizeof(*hdr));
871 hdr->opcode = cpu_to_le16(event);
872 if (hdev)
873 hdr->index = cpu_to_le16(hdev->id);
874 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530875 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200876 hdr->len = cpu_to_le16(data_len);
877
878 if (data)
879 memcpy(skb_put(skb, data_len), data, data_len);
880
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100881 /* Time stamp */
882 __net_timestamp(skb);
883
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200884 hci_send_to_control(skb, skip_sk);
885 kfree_skb(skb);
886
887 return 0;
888}
889
890static int new_settings(struct hci_dev *hdev, struct sock *skip)
891{
892 __le32 ev;
893
894 ev = cpu_to_le32(get_current_settings(hdev));
895
896 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
897}
898
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200899static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300900 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200901{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300902 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200903 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200904 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200905 u8 scan;
906 int err;
907
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200908 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200909
Johan Hedberg33c525c2012-10-24 21:11:58 +0300910 if (!lmp_bredr_capable(hdev))
911 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
912 MGMT_STATUS_NOT_SUPPORTED);
913
Johan Hedberga7e80f22013-01-09 16:05:19 +0200914 if (cp->val != 0x00 && cp->val != 0x01)
915 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
916 MGMT_STATUS_INVALID_PARAMS);
917
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700918 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100919 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200920 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300921 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200922
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300923 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200924
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200925 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200926 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300927 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200928 goto failed;
929 }
930
931 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300932 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200933 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300934 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200935 goto failed;
936 }
937
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200938 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200939 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300940 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200941 goto failed;
942 }
943
944 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200945 bool changed = false;
946
947 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
948 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
949 changed = true;
950 }
951
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200952 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200953 if (err < 0)
954 goto failed;
955
956 if (changed)
957 err = new_settings(hdev, sk);
958
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200959 goto failed;
960 }
961
962 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100963 if (hdev->discov_timeout > 0) {
964 cancel_delayed_work(&hdev->discov_off);
965 hdev->discov_timeout = 0;
966 }
967
968 if (cp->val && timeout > 0) {
969 hdev->discov_timeout = timeout;
970 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
971 msecs_to_jiffies(hdev->discov_timeout * 1000));
972 }
973
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200974 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200975 goto failed;
976 }
977
978 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
979 if (!cmd) {
980 err = -ENOMEM;
981 goto failed;
982 }
983
984 scan = SCAN_PAGE;
985
986 if (cp->val)
987 scan |= SCAN_INQUIRY;
988 else
989 cancel_delayed_work(&hdev->discov_off);
990
991 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
992 if (err < 0)
993 mgmt_pending_remove(cmd);
994
Johan Hedberg03811012010-12-08 00:21:06 +0200995 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200996 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200997
998failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300999 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02001000 return err;
1001}
1002
Johan Hedberg406d7802013-03-15 17:07:09 -05001003static void write_fast_connectable(struct hci_request *req, bool enable)
1004{
1005 struct hci_cp_write_page_scan_activity acp;
1006 u8 type;
1007
1008 if (enable) {
1009 type = PAGE_SCAN_TYPE_INTERLACED;
1010
1011 /* 160 msec page scan interval */
1012 acp.interval = __constant_cpu_to_le16(0x0100);
1013 } else {
1014 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1015
1016 /* default 1.28 sec page scan */
1017 acp.interval = __constant_cpu_to_le16(0x0800);
1018 }
1019
1020 acp.window = __constant_cpu_to_le16(0x0012);
1021
1022 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp), &acp);
1023 hci_req_add(req, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1024}
1025
Johan Hedberg2b76f452013-03-15 17:07:04 -05001026static void set_connectable_complete(struct hci_dev *hdev, u8 status)
1027{
1028 struct pending_cmd *cmd;
1029
1030 BT_DBG("status 0x%02x", status);
1031
1032 hci_dev_lock(hdev);
1033
1034 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
1035 if (!cmd)
1036 goto unlock;
1037
1038 send_settings_rsp(cmd->sk, MGMT_OP_SET_CONNECTABLE, hdev);
1039
1040 mgmt_pending_remove(cmd);
1041
1042unlock:
1043 hci_dev_unlock(hdev);
1044}
1045
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001046static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001047 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +02001048{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001049 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +02001050 struct pending_cmd *cmd;
Johan Hedberg2b76f452013-03-15 17:07:04 -05001051 struct hci_request req;
Johan Hedberg03811012010-12-08 00:21:06 +02001052 u8 scan;
1053 int err;
1054
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001055 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +02001056
Johan Hedberg33c525c2012-10-24 21:11:58 +03001057 if (!lmp_bredr_capable(hdev))
1058 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1059 MGMT_STATUS_NOT_SUPPORTED);
1060
Johan Hedberga7e80f22013-01-09 16:05:19 +02001061 if (cp->val != 0x00 && cp->val != 0x01)
1062 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
1063 MGMT_STATUS_INVALID_PARAMS);
1064
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001065 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001066
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001067 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001068 bool changed = false;
1069
1070 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
1071 changed = true;
1072
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001073 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001074 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001075 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001076 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
1077 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
1078 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001079
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001080 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001081 if (err < 0)
1082 goto failed;
1083
1084 if (changed)
1085 err = new_settings(hdev, sk);
1086
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001087 goto failed;
1088 }
1089
1090 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001091 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001092 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001093 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001094 goto failed;
1095 }
1096
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001097 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001098 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001099 goto failed;
1100 }
1101
1102 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1103 if (!cmd) {
1104 err = -ENOMEM;
1105 goto failed;
1106 }
1107
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001108 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001109 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001110 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001111 scan = 0;
1112
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001113 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001114 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001115 cancel_delayed_work(&hdev->discov_off);
1116 }
1117
Johan Hedberg2b76f452013-03-15 17:07:04 -05001118 hci_req_init(&req, hdev);
1119
1120 hci_req_add(&req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1121
Johan Hedberge36a3762013-03-15 17:07:10 -05001122 if (!cp->val && test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags))
1123 write_fast_connectable(&req, false);
1124
Johan Hedberg2b76f452013-03-15 17:07:04 -05001125 err = hci_req_run(&req, set_connectable_complete);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001126 if (err < 0)
1127 mgmt_pending_remove(cmd);
1128
1129failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001130 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001131 return err;
1132}
1133
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001134static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001135 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001136{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001137 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001138 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001139
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001140 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001141
Johan Hedberga7e80f22013-01-09 16:05:19 +02001142 if (cp->val != 0x00 && cp->val != 0x01)
1143 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1144 MGMT_STATUS_INVALID_PARAMS);
1145
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001146 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001147
1148 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001149 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001150 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001151 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001152
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001153 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001154 if (err < 0)
1155 goto failed;
1156
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001157 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001158
1159failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001160 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001161 return err;
1162}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001163
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001164static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1165 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001166{
1167 struct mgmt_mode *cp = data;
1168 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001169 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001170 int err;
1171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001172 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001173
Johan Hedberg33c525c2012-10-24 21:11:58 +03001174 if (!lmp_bredr_capable(hdev))
1175 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1176 MGMT_STATUS_NOT_SUPPORTED);
1177
Johan Hedberga7e80f22013-01-09 16:05:19 +02001178 if (cp->val != 0x00 && cp->val != 0x01)
1179 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1180 MGMT_STATUS_INVALID_PARAMS);
1181
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001182 hci_dev_lock(hdev);
1183
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001184 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001185 bool changed = false;
1186
1187 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001188 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001189 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1190 changed = true;
1191 }
1192
1193 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1194 if (err < 0)
1195 goto failed;
1196
1197 if (changed)
1198 err = new_settings(hdev, sk);
1199
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001200 goto failed;
1201 }
1202
1203 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001204 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001205 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001206 goto failed;
1207 }
1208
1209 val = !!cp->val;
1210
1211 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1212 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1213 goto failed;
1214 }
1215
1216 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1217 if (!cmd) {
1218 err = -ENOMEM;
1219 goto failed;
1220 }
1221
1222 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1223 if (err < 0) {
1224 mgmt_pending_remove(cmd);
1225 goto failed;
1226 }
1227
1228failed:
1229 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001230 return err;
1231}
1232
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001233static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001234{
1235 struct mgmt_mode *cp = data;
1236 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001237 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001238 int err;
1239
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001240 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001241
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001242 if (!lmp_ssp_capable(hdev))
1243 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1244 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001245
Johan Hedberga7e80f22013-01-09 16:05:19 +02001246 if (cp->val != 0x00 && cp->val != 0x01)
1247 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1248 MGMT_STATUS_INVALID_PARAMS);
1249
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001250 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001251
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001252 val = !!cp->val;
1253
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001254 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001255 bool changed = false;
1256
1257 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1258 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1259 changed = true;
1260 }
1261
1262 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1263 if (err < 0)
1264 goto failed;
1265
1266 if (changed)
1267 err = new_settings(hdev, sk);
1268
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001269 goto failed;
1270 }
1271
1272 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001273 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1274 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001275 goto failed;
1276 }
1277
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001278 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1279 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1280 goto failed;
1281 }
1282
1283 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1284 if (!cmd) {
1285 err = -ENOMEM;
1286 goto failed;
1287 }
1288
1289 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1290 if (err < 0) {
1291 mgmt_pending_remove(cmd);
1292 goto failed;
1293 }
1294
1295failed:
1296 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001297 return err;
1298}
1299
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001300static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001301{
1302 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001303
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001304 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001305
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001306 if (!enable_hs)
1307 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001308 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001309
Johan Hedberga7e80f22013-01-09 16:05:19 +02001310 if (cp->val != 0x00 && cp->val != 0x01)
1311 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1312 MGMT_STATUS_INVALID_PARAMS);
1313
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001314 if (cp->val)
1315 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1316 else
1317 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1318
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001319 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001320}
1321
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001322static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001323{
1324 struct mgmt_mode *cp = data;
1325 struct hci_cp_write_le_host_supported hci_cp;
1326 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001327 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001328 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001329
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001330 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001331
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001332 if (!lmp_le_capable(hdev))
1333 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1334 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001335
Johan Hedberga7e80f22013-01-09 16:05:19 +02001336 if (cp->val != 0x00 && cp->val != 0x01)
1337 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1338 MGMT_STATUS_INVALID_PARAMS);
1339
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001340 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001341
1342 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001343 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001344
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001345 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001346 bool changed = false;
1347
1348 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1349 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1350 changed = true;
1351 }
1352
1353 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1354 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001355 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001356
1357 if (changed)
1358 err = new_settings(hdev, sk);
1359
Johan Hedberg1de028c2012-02-29 19:55:35 -08001360 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001361 }
1362
1363 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001364 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001365 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001366 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001367 }
1368
1369 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1370 if (!cmd) {
1371 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001372 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001373 }
1374
1375 memset(&hci_cp, 0, sizeof(hci_cp));
1376
1377 if (val) {
1378 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001379 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001380 }
1381
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001382 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1383 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301384 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001385 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001386
Johan Hedberg1de028c2012-02-29 19:55:35 -08001387unlock:
1388 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001389 return err;
1390}
1391
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001392/* This is a helper function to test for pending mgmt commands that can
1393 * cause CoD or EIR HCI commands. We can only allow one such pending
1394 * mgmt command at a time since otherwise we cannot easily track what
1395 * the current values are, will be, and based on that calculate if a new
1396 * HCI command needs to be sent and if yes with what value.
1397 */
1398static bool pending_eir_or_class(struct hci_dev *hdev)
1399{
1400 struct pending_cmd *cmd;
1401
1402 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
1403 switch (cmd->opcode) {
1404 case MGMT_OP_ADD_UUID:
1405 case MGMT_OP_REMOVE_UUID:
1406 case MGMT_OP_SET_DEV_CLASS:
1407 case MGMT_OP_SET_POWERED:
1408 return true;
1409 }
1410 }
1411
1412 return false;
1413}
1414
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001415static const u8 bluetooth_base_uuid[] = {
1416 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1417 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1418};
1419
1420static u8 get_uuid_size(const u8 *uuid)
1421{
1422 u32 val;
1423
1424 if (memcmp(uuid, bluetooth_base_uuid, 12))
1425 return 128;
1426
1427 val = get_unaligned_le32(&uuid[12]);
1428 if (val > 0xffff)
1429 return 32;
1430
1431 return 16;
1432}
1433
Johan Hedberg92da6092013-03-15 17:06:55 -05001434static void mgmt_class_complete(struct hci_dev *hdev, u16 mgmt_op, u8 status)
1435{
1436 struct pending_cmd *cmd;
1437
1438 hci_dev_lock(hdev);
1439
1440 cmd = mgmt_pending_find(mgmt_op, hdev);
1441 if (!cmd)
1442 goto unlock;
1443
1444 cmd_complete(cmd->sk, cmd->index, cmd->opcode, mgmt_status(status),
1445 hdev->dev_class, 3);
1446
1447 mgmt_pending_remove(cmd);
1448
1449unlock:
1450 hci_dev_unlock(hdev);
1451}
1452
1453static void add_uuid_complete(struct hci_dev *hdev, u8 status)
1454{
1455 BT_DBG("status 0x%02x", status);
1456
1457 mgmt_class_complete(hdev, MGMT_OP_ADD_UUID, status);
1458}
1459
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001460static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001461{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001462 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001463 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001464 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001465 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001466 int err;
1467
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001468 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001469
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001470 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001471
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001472 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001473 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001474 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001475 goto failed;
1476 }
1477
Andre Guedes92c4c202012-06-07 19:05:44 -03001478 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001479 if (!uuid) {
1480 err = -ENOMEM;
1481 goto failed;
1482 }
1483
1484 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001485 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001486 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001487
Johan Hedbergde66aa62013-01-27 00:31:27 +02001488 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001489
Johan Hedberg890ea892013-03-15 17:06:52 -05001490 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001491
Johan Hedberg890ea892013-03-15 17:06:52 -05001492 update_class(&req);
1493 update_eir(&req);
1494
Johan Hedberg92da6092013-03-15 17:06:55 -05001495 err = hci_req_run(&req, add_uuid_complete);
1496 if (err < 0) {
1497 if (err != -ENODATA)
1498 goto failed;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001499
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001500 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001501 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001502 goto failed;
1503 }
1504
1505 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001506 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001507 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001508 goto failed;
1509 }
1510
1511 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001512
1513failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001514 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001515 return err;
1516}
1517
Johan Hedberg24b78d02012-02-23 23:24:30 +02001518static bool enable_service_cache(struct hci_dev *hdev)
1519{
1520 if (!hdev_is_powered(hdev))
1521 return false;
1522
1523 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001524 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1525 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001526 return true;
1527 }
1528
1529 return false;
1530}
1531
Johan Hedberg92da6092013-03-15 17:06:55 -05001532static void remove_uuid_complete(struct hci_dev *hdev, u8 status)
1533{
1534 BT_DBG("status 0x%02x", status);
1535
1536 mgmt_class_complete(hdev, MGMT_OP_REMOVE_UUID, status);
1537}
1538
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001539static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001540 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001541{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001542 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001543 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001544 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001545 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 -05001546 struct hci_request req;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001547 int err, found;
1548
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001549 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001550
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001551 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001552
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001553 if (pending_eir_or_class(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001554 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001555 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001556 goto unlock;
1557 }
1558
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001559 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1560 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001561
Johan Hedberg24b78d02012-02-23 23:24:30 +02001562 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001563 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001564 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001565 goto unlock;
1566 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001567
Johan Hedberg9246a862012-02-23 21:33:16 +02001568 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001569 }
1570
1571 found = 0;
1572
Johan Hedberg056341c2013-01-27 00:31:30 +02001573 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001574 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1575 continue;
1576
1577 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001578 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001579 found++;
1580 }
1581
1582 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001583 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001584 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001585 goto unlock;
1586 }
1587
Johan Hedberg9246a862012-02-23 21:33:16 +02001588update_class:
Johan Hedberg890ea892013-03-15 17:06:52 -05001589 hci_req_init(&req, hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001590
Johan Hedberg890ea892013-03-15 17:06:52 -05001591 update_class(&req);
1592 update_eir(&req);
1593
Johan Hedberg92da6092013-03-15 17:06:55 -05001594 err = hci_req_run(&req, remove_uuid_complete);
1595 if (err < 0) {
1596 if (err != -ENODATA)
1597 goto unlock;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001598
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001599 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001600 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001601 goto unlock;
1602 }
1603
1604 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001605 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001606 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001607 goto unlock;
1608 }
1609
1610 err = 0;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001611
1612unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001613 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001614 return err;
1615}
1616
Johan Hedberg92da6092013-03-15 17:06:55 -05001617static void set_class_complete(struct hci_dev *hdev, u8 status)
1618{
1619 BT_DBG("status 0x%02x", status);
1620
1621 mgmt_class_complete(hdev, MGMT_OP_SET_DEV_CLASS, status);
1622}
1623
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001624static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001625 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001626{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001627 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001628 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05001629 struct hci_request req;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001630 int err;
1631
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001632 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001633
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001634 if (!lmp_bredr_capable(hdev))
1635 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1636 MGMT_STATUS_NOT_SUPPORTED);
1637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001638 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001639
Johan Hedberg0cab9c82013-03-15 17:06:54 -05001640 if (pending_eir_or_class(hdev)) {
1641 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1642 MGMT_STATUS_BUSY);
1643 goto unlock;
1644 }
1645
1646 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0) {
1647 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1648 MGMT_STATUS_INVALID_PARAMS);
1649 goto unlock;
1650 }
1651
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001652 hdev->major_class = cp->major;
1653 hdev->minor_class = cp->minor;
1654
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001655 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001656 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001657 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001658 goto unlock;
1659 }
1660
Johan Hedberg890ea892013-03-15 17:06:52 -05001661 hci_req_init(&req, hdev);
1662
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001663 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001664 hci_dev_unlock(hdev);
1665 cancel_delayed_work_sync(&hdev->service_cache);
1666 hci_dev_lock(hdev);
Johan Hedberg890ea892013-03-15 17:06:52 -05001667 update_eir(&req);
Johan Hedberg7d785252011-12-15 00:47:39 +02001668 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001669
Johan Hedberg890ea892013-03-15 17:06:52 -05001670 update_class(&req);
1671
Johan Hedberg92da6092013-03-15 17:06:55 -05001672 err = hci_req_run(&req, set_class_complete);
1673 if (err < 0) {
1674 if (err != -ENODATA)
1675 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001676
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001677 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001678 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001679 goto unlock;
1680 }
1681
1682 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Johan Hedberg890ea892013-03-15 17:06:52 -05001683 if (!cmd) {
Johan Hedberg90e70452012-02-23 23:09:40 +02001684 err = -ENOMEM;
Johan Hedberg890ea892013-03-15 17:06:52 -05001685 goto unlock;
1686 }
1687
1688 err = 0;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001689
Johan Hedbergb5235a62012-02-21 14:32:24 +02001690unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001691 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001692 return err;
1693}
1694
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001695static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001696 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001697{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001698 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001699 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001700 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001701
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001702 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001703
Johan Hedberg86742e12011-11-07 23:13:38 +02001704 expected_len = sizeof(*cp) + key_count *
1705 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001706 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001707 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001708 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001709 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001710 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001711 }
1712
Johan Hedberg4ae143012013-01-20 14:27:13 +02001713 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1714 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1715 MGMT_STATUS_INVALID_PARAMS);
1716
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001717 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001718 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001719
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001720 for (i = 0; i < key_count; i++) {
1721 struct mgmt_link_key_info *key = &cp->keys[i];
1722
1723 if (key->addr.type != BDADDR_BREDR)
1724 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1725 MGMT_STATUS_INVALID_PARAMS);
1726 }
1727
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001728 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001729
1730 hci_link_keys_clear(hdev);
1731
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001732 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001733
1734 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001735 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001736 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001737 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001738
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001739 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001740 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001741
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001742 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001743 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001744 }
1745
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001746 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001747
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001748 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001749
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001750 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001751}
1752
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001753static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001754 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001755{
1756 struct mgmt_ev_device_unpaired ev;
1757
1758 bacpy(&ev.addr.bdaddr, bdaddr);
1759 ev.addr.type = addr_type;
1760
1761 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001762 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001763}
1764
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001765static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001766 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001767{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001768 struct mgmt_cp_unpair_device *cp = data;
1769 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001770 struct hci_cp_disconnect dc;
1771 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001772 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001773 int err;
1774
Johan Hedberga8a1d192011-11-10 15:54:38 +02001775 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001776 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1777 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001778
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001779 if (!bdaddr_type_is_valid(cp->addr.type))
1780 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1781 MGMT_STATUS_INVALID_PARAMS,
1782 &rp, sizeof(rp));
1783
Johan Hedberg118da702013-01-20 14:27:20 +02001784 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1785 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1786 MGMT_STATUS_INVALID_PARAMS,
1787 &rp, sizeof(rp));
1788
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001789 hci_dev_lock(hdev);
1790
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001791 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001792 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001793 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001794 goto unlock;
1795 }
1796
Andre Guedes591f47f2012-04-24 21:02:49 -03001797 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001798 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1799 else
1800 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001801
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001802 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001803 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001804 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001805 goto unlock;
1806 }
1807
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001808 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001809 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001810 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001811 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001812 else
1813 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001814 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001815 } else {
1816 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001817 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001818
Johan Hedberga8a1d192011-11-10 15:54:38 +02001819 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001820 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001821 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001822 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001823 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001824 }
1825
Johan Hedberg124f6e32012-02-09 13:50:12 +02001826 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001827 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001828 if (!cmd) {
1829 err = -ENOMEM;
1830 goto unlock;
1831 }
1832
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001833 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001834 dc.reason = 0x13; /* Remote User Terminated Connection */
1835 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1836 if (err < 0)
1837 mgmt_pending_remove(cmd);
1838
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001839unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001840 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001841 return err;
1842}
1843
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001844static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001845 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001846{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001847 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001848 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001849 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001850 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001851 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001852 int err;
1853
1854 BT_DBG("");
1855
Johan Hedberg06a63b12013-01-20 14:27:21 +02001856 memset(&rp, 0, sizeof(rp));
1857 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1858 rp.addr.type = cp->addr.type;
1859
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001860 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001861 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1862 MGMT_STATUS_INVALID_PARAMS,
1863 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001864
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001865 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001866
1867 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001868 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1869 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001870 goto failed;
1871 }
1872
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001873 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001874 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1875 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001876 goto failed;
1877 }
1878
Andre Guedes591f47f2012-04-24 21:02:49 -03001879 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001880 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1881 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001882 else
1883 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001884
Vishal Agarwalf9607272012-06-13 05:32:43 +05301885 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001886 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1887 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001888 goto failed;
1889 }
1890
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001891 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001892 if (!cmd) {
1893 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001894 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001895 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001896
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001897 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001898 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001899
1900 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1901 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001902 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001903
1904failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001905 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001906 return err;
1907}
1908
Andre Guedes57c14772012-04-24 21:02:50 -03001909static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001910{
1911 switch (link_type) {
1912 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001913 switch (addr_type) {
1914 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001915 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001916
Johan Hedberg48264f02011-11-09 13:58:58 +02001917 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001918 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001919 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001920 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001921
Johan Hedberg4c659c32011-11-07 23:13:39 +02001922 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001923 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001924 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001925 }
1926}
1927
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001928static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1929 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001930{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001931 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001932 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001933 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001934 int err;
1935 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001936
1937 BT_DBG("");
1938
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001939 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001940
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001941 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001942 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001943 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001944 goto unlock;
1945 }
1946
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001947 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001948 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1949 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001950 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001951 }
1952
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001953 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03001954 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001955 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001956 err = -ENOMEM;
1957 goto unlock;
1958 }
1959
Johan Hedberg2784eb42011-01-21 13:56:35 +02001960 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001961 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001962 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1963 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001964 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001965 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001966 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001967 continue;
1968 i++;
1969 }
1970
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001971 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001972
Johan Hedberg4c659c32011-11-07 23:13:39 +02001973 /* Recalculate length in case of filtered SCO connections, etc */
1974 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001975
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001976 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001977 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001978
Johan Hedberga38528f2011-01-22 06:46:43 +02001979 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001980
1981unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001982 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001983 return err;
1984}
1985
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001986static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001987 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001988{
1989 struct pending_cmd *cmd;
1990 int err;
1991
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001992 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001993 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001994 if (!cmd)
1995 return -ENOMEM;
1996
Johan Hedbergd8457692012-02-17 14:24:57 +02001997 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001998 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001999 if (err < 0)
2000 mgmt_pending_remove(cmd);
2001
2002 return err;
2003}
2004
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002005static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002006 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002007{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002008 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002009 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002010 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03002011 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002012 int err;
2013
2014 BT_DBG("");
2015
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002016 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002017
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002018 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002019 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002020 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002021 goto failed;
2022 }
2023
Johan Hedbergd8457692012-02-17 14:24:57 +02002024 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002025 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002026 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002027 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002028 goto failed;
2029 }
2030
2031 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02002032 struct mgmt_cp_pin_code_neg_reply ncp;
2033
2034 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002035
2036 BT_ERR("PIN code is not 16 bytes long");
2037
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002038 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002039 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002040 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002041 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02002042
2043 goto failed;
2044 }
2045
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03002046 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03002047 if (!cmd) {
2048 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002049 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03002050 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02002051
Johan Hedbergd8457692012-02-17 14:24:57 +02002052 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002053 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02002054 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002055
2056 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
2057 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03002058 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002059
2060failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002061 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002062 return err;
2063}
2064
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002065static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
2066 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002067{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002068 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002069
2070 BT_DBG("");
2071
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002072 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002073
2074 hdev->io_capability = cp->io_capability;
2075
2076 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002077 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002078
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002079 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002080
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002081 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
2082 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002083}
2084
Gustavo Padovan6039aa732012-05-23 04:04:18 -03002085static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002086{
2087 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02002088 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002089
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002090 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03002091 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
2092 continue;
2093
Johan Hedberge9a416b2011-02-19 12:05:56 -03002094 if (cmd->user_data != conn)
2095 continue;
2096
2097 return cmd;
2098 }
2099
2100 return NULL;
2101}
2102
2103static void pairing_complete(struct pending_cmd *cmd, u8 status)
2104{
2105 struct mgmt_rp_pair_device rp;
2106 struct hci_conn *conn = cmd->user_data;
2107
Johan Hedbergba4e5642011-11-11 00:07:34 +02002108 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03002109 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002110
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002111 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002112 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002113
2114 /* So we don't get further callbacks for this connection */
2115 conn->connect_cfm_cb = NULL;
2116 conn->security_cfm_cb = NULL;
2117 conn->disconn_cfm_cb = NULL;
2118
2119 hci_conn_put(conn);
2120
Johan Hedberga664b5b2011-02-19 12:06:02 -03002121 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002122}
2123
2124static void pairing_complete_cb(struct hci_conn *conn, u8 status)
2125{
2126 struct pending_cmd *cmd;
2127
2128 BT_DBG("status %u", status);
2129
Johan Hedberg56e5cb82011-11-08 20:40:16 +02002130 cmd = find_pairing(conn);
2131 if (!cmd)
2132 BT_DBG("Unable to find a pending command");
2133 else
Johan Hedberge2113262012-02-18 15:20:03 +02002134 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002135}
2136
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302137static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
2138{
2139 struct pending_cmd *cmd;
2140
2141 BT_DBG("status %u", status);
2142
2143 if (!status)
2144 return;
2145
2146 cmd = find_pairing(conn);
2147 if (!cmd)
2148 BT_DBG("Unable to find a pending command");
2149 else
2150 pairing_complete(cmd, mgmt_status(status));
2151}
2152
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002153static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002154 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002155{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002156 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02002157 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002158 struct pending_cmd *cmd;
2159 u8 sec_level, auth_type;
2160 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002161 int err;
2162
2163 BT_DBG("");
2164
Szymon Jancf950a30e2013-01-18 12:48:07 +01002165 memset(&rp, 0, sizeof(rp));
2166 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2167 rp.addr.type = cp->addr.type;
2168
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002169 if (!bdaddr_type_is_valid(cp->addr.type))
2170 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2171 MGMT_STATUS_INVALID_PARAMS,
2172 &rp, sizeof(rp));
2173
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002174 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002175
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002176 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002177 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2178 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002179 goto unlock;
2180 }
2181
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002182 sec_level = BT_SECURITY_MEDIUM;
2183 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002184 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002185 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002186 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002187
Andre Guedes591f47f2012-04-24 21:02:49 -03002188 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002189 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2190 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002191 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002192 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2193 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002194
Ville Tervo30e76272011-02-22 16:10:53 -03002195 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002196 int status;
2197
2198 if (PTR_ERR(conn) == -EBUSY)
2199 status = MGMT_STATUS_BUSY;
2200 else
2201 status = MGMT_STATUS_CONNECT_FAILED;
2202
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002203 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002204 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002205 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002206 goto unlock;
2207 }
2208
2209 if (conn->connect_cfm_cb) {
2210 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002211 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002212 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002213 goto unlock;
2214 }
2215
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002216 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002217 if (!cmd) {
2218 err = -ENOMEM;
2219 hci_conn_put(conn);
2220 goto unlock;
2221 }
2222
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002223 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002224 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002225 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302226 else
2227 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002228
Johan Hedberge9a416b2011-02-19 12:05:56 -03002229 conn->security_cfm_cb = pairing_complete_cb;
2230 conn->disconn_cfm_cb = pairing_complete_cb;
2231 conn->io_capability = cp->io_cap;
2232 cmd->user_data = conn;
2233
2234 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002235 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002236 pairing_complete(cmd, 0);
2237
2238 err = 0;
2239
2240unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002241 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002242 return err;
2243}
2244
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002245static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2246 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002247{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002248 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002249 struct pending_cmd *cmd;
2250 struct hci_conn *conn;
2251 int err;
2252
2253 BT_DBG("");
2254
Johan Hedberg28424702012-02-02 04:02:29 +02002255 hci_dev_lock(hdev);
2256
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002257 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002258 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002259 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002260 goto unlock;
2261 }
2262
Johan Hedberg28424702012-02-02 04:02:29 +02002263 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2264 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002266 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002267 goto unlock;
2268 }
2269
2270 conn = cmd->user_data;
2271
2272 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002273 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002274 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002275 goto unlock;
2276 }
2277
2278 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002280 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002281 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002282unlock:
2283 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002284 return err;
2285}
2286
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002287static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002288 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2289 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002290{
Johan Hedberga5c29682011-02-19 12:05:57 -03002291 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002292 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002293 int err;
2294
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002295 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002296
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002297 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002298 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002299 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002300 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002301 }
2302
Andre Guedes591f47f2012-04-24 21:02:49 -03002303 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002304 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2305 else
Brian Gix47c15e22011-11-16 13:53:14 -08002306 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002307
Johan Hedberg272d90d2012-02-09 15:26:12 +02002308 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002309 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002310 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002311 goto done;
2312 }
2313
Andre Guedes591f47f2012-04-24 21:02:49 -03002314 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002315 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002316 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002317
Brian Gix5fe57d92011-12-21 16:12:13 -08002318 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002319 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002320 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002321 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002322 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002323 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002324
Brian Gix47c15e22011-11-16 13:53:14 -08002325 goto done;
2326 }
2327
Brian Gix0df4c182011-11-16 13:53:13 -08002328 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002329 if (!cmd) {
2330 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002331 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002332 }
2333
Brian Gix0df4c182011-11-16 13:53:13 -08002334 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002335 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2336 struct hci_cp_user_passkey_reply cp;
2337
2338 bacpy(&cp.bdaddr, bdaddr);
2339 cp.passkey = passkey;
2340 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2341 } else
2342 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2343
Johan Hedberga664b5b2011-02-19 12:06:02 -03002344 if (err < 0)
2345 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002346
Brian Gix0df4c182011-11-16 13:53:13 -08002347done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002348 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002349 return err;
2350}
2351
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302352static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2353 void *data, u16 len)
2354{
2355 struct mgmt_cp_pin_code_neg_reply *cp = data;
2356
2357 BT_DBG("");
2358
2359 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
2360 MGMT_OP_PIN_CODE_NEG_REPLY,
2361 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2362}
2363
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002364static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2365 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002366{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002367 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002368
2369 BT_DBG("");
2370
2371 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002372 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002373 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002374
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002375 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002376 MGMT_OP_USER_CONFIRM_REPLY,
2377 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002378}
2379
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002380static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002381 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002382{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002383 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002384
2385 BT_DBG("");
2386
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002387 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002388 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2389 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002390}
2391
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002392static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2393 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002394{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002395 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002396
2397 BT_DBG("");
2398
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002399 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002400 MGMT_OP_USER_PASSKEY_REPLY,
2401 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002402}
2403
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002404static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002405 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002406{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002407 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002408
2409 BT_DBG("");
2410
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002411 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002412 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2413 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002414}
2415
Johan Hedberg13928972013-03-15 17:07:00 -05002416static void update_name(struct hci_request *req)
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002417{
Johan Hedberg13928972013-03-15 17:07:00 -05002418 struct hci_dev *hdev = req->hdev;
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002419 struct hci_cp_write_local_name cp;
2420
Johan Hedberg13928972013-03-15 17:07:00 -05002421 memcpy(cp.name, hdev->dev_name, sizeof(cp.name));
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002422
Johan Hedberg890ea892013-03-15 17:06:52 -05002423 hci_req_add(req, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002424}
2425
Johan Hedberg13928972013-03-15 17:07:00 -05002426static void set_name_complete(struct hci_dev *hdev, u8 status)
2427{
2428 struct mgmt_cp_set_local_name *cp;
2429 struct pending_cmd *cmd;
2430
2431 BT_DBG("status 0x%02x", status);
2432
2433 hci_dev_lock(hdev);
2434
2435 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
2436 if (!cmd)
2437 goto unlock;
2438
2439 cp = cmd->param;
2440
2441 if (status)
2442 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
2443 mgmt_status(status));
2444 else
2445 cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2446 cp, sizeof(*cp));
2447
2448 mgmt_pending_remove(cmd);
2449
2450unlock:
2451 hci_dev_unlock(hdev);
2452}
2453
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002454static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002455 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002456{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002457 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002458 struct pending_cmd *cmd;
Johan Hedberg890ea892013-03-15 17:06:52 -05002459 struct hci_request req;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002460 int err;
2461
2462 BT_DBG("");
2463
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002464 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002465
Johan Hedbergb3f2ca92013-03-15 17:07:03 -05002466 /* If the old values are the same as the new ones just return a
2467 * direct command complete event.
2468 */
2469 if (!memcmp(hdev->dev_name, cp->name, sizeof(hdev->dev_name)) &&
2470 !memcmp(hdev->short_name, cp->short_name,
2471 sizeof(hdev->short_name))) {
2472 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
2473 data, len);
2474 goto failed;
2475 }
2476
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002477 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002478
Johan Hedbergb5235a62012-02-21 14:32:24 +02002479 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002480 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002481
2482 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002483 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002484 if (err < 0)
2485 goto failed;
2486
2487 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002488 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002489
Johan Hedbergb5235a62012-02-21 14:32:24 +02002490 goto failed;
2491 }
2492
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002493 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002494 if (!cmd) {
2495 err = -ENOMEM;
2496 goto failed;
2497 }
2498
Johan Hedberg13928972013-03-15 17:07:00 -05002499 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
2500
Johan Hedberg890ea892013-03-15 17:06:52 -05002501 hci_req_init(&req, hdev);
Johan Hedberg3f985052013-03-15 17:07:02 -05002502
2503 if (lmp_bredr_capable(hdev)) {
2504 update_name(&req);
2505 update_eir(&req);
2506 }
2507
2508 if (lmp_le_capable(hdev))
2509 hci_update_ad(&req);
2510
Johan Hedberg13928972013-03-15 17:07:00 -05002511 err = hci_req_run(&req, set_name_complete);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002512 if (err < 0)
2513 mgmt_pending_remove(cmd);
2514
2515failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002516 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002517 return err;
2518}
2519
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002520static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002521 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002522{
Szymon Jancc35938b2011-03-22 13:12:21 +01002523 struct pending_cmd *cmd;
2524 int err;
2525
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002526 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002527
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002528 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002529
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002530 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002531 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002532 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002533 goto unlock;
2534 }
2535
Andre Guedes9a1a1992012-07-24 15:03:48 -03002536 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002537 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002538 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002539 goto unlock;
2540 }
2541
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002542 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002543 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002544 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002545 goto unlock;
2546 }
2547
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002548 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002549 if (!cmd) {
2550 err = -ENOMEM;
2551 goto unlock;
2552 }
2553
2554 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2555 if (err < 0)
2556 mgmt_pending_remove(cmd);
2557
2558unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002559 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002560 return err;
2561}
2562
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002563static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002564 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002565{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002566 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002567 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002568 int err;
2569
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002570 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002571
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002572 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002573
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002574 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002575 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002576 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002577 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002578 else
Szymon Janca6785be2012-12-13 15:11:21 +01002579 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002580
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002581 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002582 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002583
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002584 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002585 return err;
2586}
2587
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002588static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002589 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002590{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002591 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002592 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002593 int err;
2594
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002595 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002596
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002597 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002598
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002599 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002600 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002601 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002602 else
Szymon Janca6785be2012-12-13 15:11:21 +01002603 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002604
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002605 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002606 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002607
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002608 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002609 return err;
2610}
2611
Andre Guedes5e0452c2012-02-17 20:39:38 -03002612int mgmt_interleaved_discovery(struct hci_dev *hdev)
2613{
2614 int err;
2615
2616 BT_DBG("%s", hdev->name);
2617
2618 hci_dev_lock(hdev);
2619
2620 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2621 if (err < 0)
2622 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2623
2624 hci_dev_unlock(hdev);
2625
2626 return err;
2627}
2628
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002629static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002630 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002631{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002632 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002633 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002634 int err;
2635
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002636 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002638 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002639
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002640 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002641 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002642 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002643 goto failed;
2644 }
2645
Andre Guedes642be6c2012-03-21 00:03:37 -03002646 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2647 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2648 MGMT_STATUS_BUSY);
2649 goto failed;
2650 }
2651
Johan Hedbergff9ef572012-01-04 14:23:45 +02002652 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002653 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002654 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002655 goto failed;
2656 }
2657
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002658 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002659 if (!cmd) {
2660 err = -ENOMEM;
2661 goto failed;
2662 }
2663
Andre Guedes4aab14e2012-02-17 20:39:36 -03002664 hdev->discovery.type = cp->type;
2665
2666 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002667 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002668 if (!lmp_bredr_capable(hdev)) {
2669 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2670 MGMT_STATUS_NOT_SUPPORTED);
2671 mgmt_pending_remove(cmd);
2672 goto failed;
2673 }
2674
2675 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002676 break;
2677
2678 case DISCOV_TYPE_LE:
Johan Hedberg04106752013-01-10 14:54:09 +02002679 if (!lmp_host_le_capable(hdev)) {
2680 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2681 MGMT_STATUS_NOT_SUPPORTED);
2682 mgmt_pending_remove(cmd);
2683 goto failed;
2684 }
2685
2686 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2687 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002688 break;
2689
Andre Guedes5e0452c2012-02-17 20:39:38 -03002690 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg04106752013-01-10 14:54:09 +02002691 if (!lmp_host_le_capable(hdev) || !lmp_bredr_capable(hdev)) {
2692 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2693 MGMT_STATUS_NOT_SUPPORTED);
2694 mgmt_pending_remove(cmd);
2695 goto failed;
2696 }
2697
2698 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN,
2699 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002700 break;
2701
Andre Guedesf39799f2012-02-17 20:39:35 -03002702 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002703 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2704 MGMT_STATUS_INVALID_PARAMS);
2705 mgmt_pending_remove(cmd);
2706 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002707 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002708
Johan Hedberg14a53662011-04-27 10:29:56 -04002709 if (err < 0)
2710 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002711 else
2712 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002713
2714failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002715 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002716 return err;
2717}
2718
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002719static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002720 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002721{
Johan Hedbergd9306502012-02-20 23:25:18 +02002722 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002723 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002724 struct hci_cp_remote_name_req_cancel cp;
2725 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002726 int err;
2727
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002728 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002729
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002730 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002731
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002732 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002733 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002734 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2735 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002736 goto unlock;
2737 }
2738
2739 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002740 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002741 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2742 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002743 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002744 }
2745
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002746 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002747 if (!cmd) {
2748 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002749 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002750 }
2751
Andre Guedese0d9727e2012-03-20 15:15:36 -03002752 switch (hdev->discovery.state) {
2753 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002754 if (test_bit(HCI_INQUIRY, &hdev->flags))
2755 err = hci_cancel_inquiry(hdev);
2756 else
2757 err = hci_cancel_le_scan(hdev);
2758
Andre Guedese0d9727e2012-03-20 15:15:36 -03002759 break;
2760
2761 case DISCOVERY_RESOLVING:
2762 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002763 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002764 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002765 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002766 err = cmd_complete(sk, hdev->id,
2767 MGMT_OP_STOP_DISCOVERY, 0,
2768 &mgmt_cp->type,
2769 sizeof(mgmt_cp->type));
2770 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2771 goto unlock;
2772 }
2773
2774 bacpy(&cp.bdaddr, &e->data.bdaddr);
2775 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2776 sizeof(cp), &cp);
2777
2778 break;
2779
2780 default:
2781 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2782 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002783 }
2784
Johan Hedberg14a53662011-04-27 10:29:56 -04002785 if (err < 0)
2786 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002787 else
2788 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002789
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002790unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002791 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002792 return err;
2793}
2794
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002795static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002796 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002797{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002798 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002799 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002800 int err;
2801
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002802 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002803
Johan Hedberg561aafb2012-01-04 13:31:59 +02002804 hci_dev_lock(hdev);
2805
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002806 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002807 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002808 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002809 goto failed;
2810 }
2811
Johan Hedberga198e7b2012-02-17 14:27:06 +02002812 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002813 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002814 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002815 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002816 goto failed;
2817 }
2818
2819 if (cp->name_known) {
2820 e->name_state = NAME_KNOWN;
2821 list_del(&e->list);
2822 } else {
2823 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002824 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002825 }
2826
Johan Hedberge3846622013-01-09 15:29:33 +02002827 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
2828 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02002829
2830failed:
2831 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002832 return err;
2833}
2834
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002835static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002836 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002837{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002838 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002839 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002840 int err;
2841
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002842 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002843
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002844 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002845 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
2846 MGMT_STATUS_INVALID_PARAMS,
2847 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002848
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002849 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002850
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002851 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002852 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002853 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002854 else
Szymon Janca6785be2012-12-13 15:11:21 +01002855 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002856
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002857 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002858 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002859
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002860 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002861
2862 return err;
2863}
2864
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002865static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002866 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002867{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002868 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002869 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002870 int err;
2871
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002872 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002873
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002874 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002875 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
2876 MGMT_STATUS_INVALID_PARAMS,
2877 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002878
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002879 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002880
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002881 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002882 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002883 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002884 else
Szymon Janca6785be2012-12-13 15:11:21 +01002885 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002886
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002887 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002888 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002889
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002890 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002891
2892 return err;
2893}
2894
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002895static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2896 u16 len)
2897{
2898 struct mgmt_cp_set_device_id *cp = data;
Johan Hedberg890ea892013-03-15 17:06:52 -05002899 struct hci_request req;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002900 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002901 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002902
2903 BT_DBG("%s", hdev->name);
2904
Szymon Jancc72d4b82012-03-16 16:02:57 +01002905 source = __le16_to_cpu(cp->source);
2906
2907 if (source > 0x0002)
2908 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2909 MGMT_STATUS_INVALID_PARAMS);
2910
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002911 hci_dev_lock(hdev);
2912
Szymon Jancc72d4b82012-03-16 16:02:57 +01002913 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002914 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2915 hdev->devid_product = __le16_to_cpu(cp->product);
2916 hdev->devid_version = __le16_to_cpu(cp->version);
2917
2918 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2919
Johan Hedberg890ea892013-03-15 17:06:52 -05002920 hci_req_init(&req, hdev);
2921 update_eir(&req);
2922 hci_req_run(&req, NULL);
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002923
2924 hci_dev_unlock(hdev);
2925
2926 return err;
2927}
2928
Johan Hedberg33e38b32013-03-15 17:07:05 -05002929static void fast_connectable_complete(struct hci_dev *hdev, u8 status)
2930{
2931 struct pending_cmd *cmd;
2932
2933 BT_DBG("status 0x%02x", status);
2934
2935 hci_dev_lock(hdev);
2936
2937 cmd = mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev);
2938 if (!cmd)
2939 goto unlock;
2940
2941 if (status) {
2942 cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2943 mgmt_status(status));
2944 } else {
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05002945 struct mgmt_mode *cp = cmd->param;
2946
2947 if (cp->val)
2948 set_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
2949 else
2950 clear_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags);
2951
Johan Hedberg33e38b32013-03-15 17:07:05 -05002952 send_settings_rsp(cmd->sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev);
2953 new_settings(hdev, cmd->sk);
2954 }
2955
2956 mgmt_pending_remove(cmd);
2957
2958unlock:
2959 hci_dev_unlock(hdev);
2960}
2961
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002962static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002963 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002964{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002965 struct mgmt_mode *cp = data;
Johan Hedberg33e38b32013-03-15 17:07:05 -05002966 struct pending_cmd *cmd;
2967 struct hci_request req;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002968 int err;
2969
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002970 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002971
Johan Hedberg1a47aee2013-03-15 17:07:06 -05002972 if (!lmp_bredr_capable(hdev) || hdev->hci_ver < BLUETOOTH_VER_1_2)
Johan Hedberg33c525c2012-10-24 21:11:58 +03002973 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2974 MGMT_STATUS_NOT_SUPPORTED);
2975
Johan Hedberga7e80f22013-01-09 16:05:19 +02002976 if (cp->val != 0x00 && cp->val != 0x01)
2977 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2978 MGMT_STATUS_INVALID_PARAMS);
2979
Johan Hedberg5400c042012-02-21 16:40:33 +02002980 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002981 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002982 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002983
2984 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002985 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002986 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002987
2988 hci_dev_lock(hdev);
2989
Johan Hedberg05cbf292013-03-15 17:07:07 -05002990 if (mgmt_pending_find(MGMT_OP_SET_FAST_CONNECTABLE, hdev)) {
2991 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2992 MGMT_STATUS_BUSY);
2993 goto unlock;
2994 }
2995
Johan Hedberg1a4d3c42013-03-15 17:07:08 -05002996 if (!!cp->val == test_bit(HCI_FAST_CONNECTABLE, &hdev->dev_flags)) {
2997 err = send_settings_rsp(sk, MGMT_OP_SET_FAST_CONNECTABLE,
2998 hdev);
2999 goto unlock;
3000 }
3001
Johan Hedberg33e38b32013-03-15 17:07:05 -05003002 cmd = mgmt_pending_add(sk, MGMT_OP_SET_FAST_CONNECTABLE, hdev,
3003 data, len);
3004 if (!cmd) {
3005 err = -ENOMEM;
3006 goto unlock;
3007 }
3008
3009 hci_req_init(&req, hdev);
3010
Johan Hedberg406d7802013-03-15 17:07:09 -05003011 write_fast_connectable(&req, cp->val);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003012
3013 err = hci_req_run(&req, fast_connectable_complete);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003014 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003015 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003016 MGMT_STATUS_FAILED);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003017 mgmt_pending_remove(cmd);
Antti Julkuf6422ec2011-06-22 13:11:56 +03003018 }
3019
Johan Hedberg33e38b32013-03-15 17:07:05 -05003020unlock:
Antti Julkuf6422ec2011-06-22 13:11:56 +03003021 hci_dev_unlock(hdev);
Johan Hedberg33e38b32013-03-15 17:07:05 -05003022
Antti Julkuf6422ec2011-06-22 13:11:56 +03003023 return err;
3024}
3025
Johan Hedberg3f706b72013-01-20 14:27:16 +02003026static bool ltk_is_valid(struct mgmt_ltk_info *key)
3027{
Johan Hedberg44b20d32013-01-20 14:27:17 +02003028 if (key->authenticated != 0x00 && key->authenticated != 0x01)
3029 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003030 if (key->master != 0x00 && key->master != 0x01)
3031 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02003032 if (!bdaddr_type_is_le(key->addr.type))
3033 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02003034 return true;
3035}
3036
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003037static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003038 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003039{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003040 struct mgmt_cp_load_long_term_keys *cp = cp_data;
3041 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003042 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003043
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003044 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003045
3046 expected_len = sizeof(*cp) + key_count *
3047 sizeof(struct mgmt_ltk_info);
3048 if (expected_len != len) {
3049 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003050 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003051 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02003052 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003053 }
3054
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003055 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003056
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003057 for (i = 0; i < key_count; i++) {
3058 struct mgmt_ltk_info *key = &cp->keys[i];
3059
Johan Hedberg3f706b72013-01-20 14:27:16 +02003060 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02003061 return cmd_status(sk, hdev->id,
3062 MGMT_OP_LOAD_LONG_TERM_KEYS,
3063 MGMT_STATUS_INVALID_PARAMS);
3064 }
3065
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003066 hci_dev_lock(hdev);
3067
3068 hci_smp_ltks_clear(hdev);
3069
3070 for (i = 0; i < key_count; i++) {
3071 struct mgmt_ltk_info *key = &cp->keys[i];
3072 u8 type;
3073
3074 if (key->master)
3075 type = HCI_SMP_LTK;
3076 else
3077 type = HCI_SMP_LTK_SLAVE;
3078
Hemant Gupta4596fde52012-04-16 14:57:40 +05303079 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03003080 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003081 type, 0, key->authenticated, key->val,
3082 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003083 }
3084
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003085 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
3086 NULL, 0);
3087
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003088 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003089
Johan Hedberg715a5bf2013-01-09 15:29:34 +02003090 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003091}
3092
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003093static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003094 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
3095 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003096 bool var_len;
3097 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003098} mgmt_handlers[] = {
3099 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02003100 { read_version, false, MGMT_READ_VERSION_SIZE },
3101 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
3102 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
3103 { read_controller_info, false, MGMT_READ_INFO_SIZE },
3104 { set_powered, false, MGMT_SETTING_SIZE },
3105 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
3106 { set_connectable, false, MGMT_SETTING_SIZE },
3107 { set_fast_connectable, false, MGMT_SETTING_SIZE },
3108 { set_pairable, false, MGMT_SETTING_SIZE },
3109 { set_link_security, false, MGMT_SETTING_SIZE },
3110 { set_ssp, false, MGMT_SETTING_SIZE },
3111 { set_hs, false, MGMT_SETTING_SIZE },
3112 { set_le, false, MGMT_SETTING_SIZE },
3113 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
3114 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
3115 { add_uuid, false, MGMT_ADD_UUID_SIZE },
3116 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
3117 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
3118 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
3119 { disconnect, false, MGMT_DISCONNECT_SIZE },
3120 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
3121 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
3122 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
3123 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
3124 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
3125 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
3126 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
3127 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
3128 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
3129 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
3130 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
3131 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
3132 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
3133 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
3134 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
3135 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
3136 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
3137 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
3138 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07003139 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003140};
3141
3142
Johan Hedberg03811012010-12-08 00:21:06 +02003143int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
3144{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003145 void *buf;
3146 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02003147 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01003148 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003149 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02003150 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02003151 int err;
3152
3153 BT_DBG("got %zu bytes", msglen);
3154
3155 if (msglen < sizeof(*hdr))
3156 return -EINVAL;
3157
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03003158 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02003159 if (!buf)
3160 return -ENOMEM;
3161
3162 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
3163 err = -EFAULT;
3164 goto done;
3165 }
3166
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03003167 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07003168 opcode = __le16_to_cpu(hdr->opcode);
3169 index = __le16_to_cpu(hdr->index);
3170 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02003171
3172 if (len != msglen - sizeof(*hdr)) {
3173 err = -EINVAL;
3174 goto done;
3175 }
3176
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003177 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003178 hdev = hci_dev_get(index);
3179 if (!hdev) {
3180 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003181 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003182 goto done;
3183 }
3184 }
3185
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003186 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003187 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02003188 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02003189 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003190 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003191 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02003192 }
3193
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003194 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003195 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003196 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003197 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003198 goto done;
3199 }
3200
Johan Hedbergbe22b542012-03-01 22:24:41 +02003201 handler = &mgmt_handlers[opcode];
3202
3203 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003204 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02003205 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003206 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02003207 goto done;
3208 }
3209
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02003210 if (hdev)
3211 mgmt_init_hdev(sk, hdev);
3212
3213 cp = buf + sizeof(*hdr);
3214
Johan Hedbergbe22b542012-03-01 22:24:41 +02003215 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02003216 if (err < 0)
3217 goto done;
3218
Johan Hedberg03811012010-12-08 00:21:06 +02003219 err = msglen;
3220
3221done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02003222 if (hdev)
3223 hci_dev_put(hdev);
3224
Johan Hedberg03811012010-12-08 00:21:06 +02003225 kfree(buf);
3226 return err;
3227}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003228
Johan Hedbergb24752f2011-11-03 14:40:33 +02003229static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
3230{
3231 u8 *status = data;
3232
3233 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
3234 mgmt_pending_remove(cmd);
3235}
3236
Johan Hedberg744cf192011-11-08 20:40:14 +02003237int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003238{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003239 if (!mgmt_valid_hdev(hdev))
3240 return -ENOTSUPP;
3241
Johan Hedberg744cf192011-11-08 20:40:14 +02003242 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003243}
3244
Johan Hedberg744cf192011-11-08 20:40:14 +02003245int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003246{
Johan Hedberg5f159032012-03-02 03:13:19 +02003247 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003248
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03003249 if (!mgmt_valid_hdev(hdev))
3250 return -ENOTSUPP;
3251
Johan Hedberg744cf192011-11-08 20:40:14 +02003252 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003253
Johan Hedberg744cf192011-11-08 20:40:14 +02003254 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003255}
3256
Johan Hedberg73f22f62010-12-29 16:00:25 +02003257struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003258 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003259 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02003260 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003261};
3262
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003263static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003264{
Johan Hedberg73f22f62010-12-29 16:00:25 +02003265 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003266
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003267 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003268
3269 list_del(&cmd->list);
3270
3271 if (match->sk == NULL) {
3272 match->sk = cmd->sk;
3273 sock_hold(match->sk);
3274 }
3275
3276 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003277}
Johan Hedberg5add6af2010-12-16 10:00:37 +02003278
Johan Hedberg890ea892013-03-15 17:06:52 -05003279static void set_bredr_scan(struct hci_request *req)
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003280{
Johan Hedberg890ea892013-03-15 17:06:52 -05003281 struct hci_dev *hdev = req->hdev;
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003282 u8 scan = 0;
3283
3284 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3285 scan |= SCAN_PAGE;
3286 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3287 scan |= SCAN_INQUIRY;
3288
Johan Hedberg890ea892013-03-15 17:06:52 -05003289 if (scan)
3290 hci_req_add(req, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003291}
3292
Johan Hedberg229ab392013-03-15 17:06:53 -05003293static void powered_complete(struct hci_dev *hdev, u8 status)
3294{
3295 struct cmd_lookup match = { NULL, hdev };
3296
3297 BT_DBG("status 0x%02x", status);
3298
3299 hci_dev_lock(hdev);
3300
3301 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3302
3303 new_settings(hdev, match.sk);
3304
3305 hci_dev_unlock(hdev);
3306
3307 if (match.sk)
3308 sock_put(match.sk);
3309}
3310
Johan Hedberg70da6242013-03-15 17:06:51 -05003311static int powered_update_hci(struct hci_dev *hdev)
3312{
Johan Hedberg890ea892013-03-15 17:06:52 -05003313 struct hci_request req;
Johan Hedberg70da6242013-03-15 17:06:51 -05003314 u8 link_sec;
3315
Johan Hedberg890ea892013-03-15 17:06:52 -05003316 hci_req_init(&req, hdev);
3317
Johan Hedberg70da6242013-03-15 17:06:51 -05003318 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3319 !lmp_host_ssp_capable(hdev)) {
3320 u8 ssp = 1;
3321
Johan Hedberg890ea892013-03-15 17:06:52 -05003322 hci_req_add(&req, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003323 }
3324
3325 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
3326 struct hci_cp_write_le_host_supported cp;
3327
3328 cp.le = 1;
3329 cp.simul = lmp_le_br_capable(hdev);
3330
3331 /* Check first if we already have the right
3332 * host state (host features set)
3333 */
3334 if (cp.le != lmp_host_le_capable(hdev) ||
3335 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003336 hci_req_add(&req, HCI_OP_WRITE_LE_HOST_SUPPORTED,
3337 sizeof(cp), &cp);
Johan Hedberg70da6242013-03-15 17:06:51 -05003338 }
3339
3340 link_sec = test_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
3341 if (link_sec != test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003342 hci_req_add(&req, HCI_OP_WRITE_AUTH_ENABLE,
3343 sizeof(link_sec), &link_sec);
Johan Hedberg70da6242013-03-15 17:06:51 -05003344
3345 if (lmp_bredr_capable(hdev)) {
Johan Hedberg890ea892013-03-15 17:06:52 -05003346 set_bredr_scan(&req);
3347 update_class(&req);
Johan Hedberg13928972013-03-15 17:07:00 -05003348 update_name(&req);
Johan Hedberg890ea892013-03-15 17:06:52 -05003349 update_eir(&req);
Johan Hedberg70da6242013-03-15 17:06:51 -05003350 }
3351
Johan Hedberg229ab392013-03-15 17:06:53 -05003352 return hci_req_run(&req, powered_complete);
Johan Hedberg70da6242013-03-15 17:06:51 -05003353}
3354
Johan Hedberg744cf192011-11-08 20:40:14 +02003355int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003356{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003357 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg229ab392013-03-15 17:06:53 -05003358 u8 status_not_powered = MGMT_STATUS_NOT_POWERED;
3359 u8 zero_cod[] = { 0, 0, 0 };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003360 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003361
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003362 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3363 return 0;
3364
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003365 if (powered) {
Johan Hedberg229ab392013-03-15 17:06:53 -05003366 if (powered_update_hci(hdev) == 0)
3367 return 0;
Johan Hedbergfe038882013-01-16 16:15:34 +02003368
Johan Hedberg229ab392013-03-15 17:06:53 -05003369 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp,
3370 &match);
3371 goto new_settings;
Johan Hedbergb24752f2011-11-03 14:40:33 +02003372 }
3373
Johan Hedberg229ab392013-03-15 17:06:53 -05003374 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
3375 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status_not_powered);
3376
3377 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3378 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3379 zero_cod, sizeof(zero_cod), NULL);
3380
3381new_settings:
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003382 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003383
3384 if (match.sk)
3385 sock_put(match.sk);
3386
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003387 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003388}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003389
Johan Hedberg744cf192011-11-08 20:40:14 +02003390int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003391{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003392 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003393 bool changed = false;
3394 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003395
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003396 if (discoverable) {
3397 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3398 changed = true;
3399 } else {
3400 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3401 changed = true;
3402 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003403
Johan Hedberged9b5f22012-02-21 20:47:06 +02003404 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003405 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003406
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003407 if (changed)
3408 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003409
Johan Hedberg73f22f62010-12-29 16:00:25 +02003410 if (match.sk)
3411 sock_put(match.sk);
3412
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003413 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003414}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003415
Johan Hedberg744cf192011-11-08 20:40:14 +02003416int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003417{
Johan Hedberg2b76f452013-03-15 17:07:04 -05003418 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003419 bool changed = false;
3420 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003421
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003422 if (connectable) {
3423 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3424 changed = true;
3425 } else {
3426 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3427 changed = true;
3428 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003429
Johan Hedberg2b76f452013-03-15 17:07:04 -05003430 cmd = mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003431
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003432 if (changed)
Johan Hedberg2b76f452013-03-15 17:07:04 -05003433 err = new_settings(hdev, cmd ? cmd->sk : NULL);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003434
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003435 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003436}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003437
Johan Hedberg744cf192011-11-08 20:40:14 +02003438int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003439{
Johan Hedbergca69b792011-11-11 18:10:00 +02003440 u8 mgmt_err = mgmt_status(status);
3441
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003442 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003443 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003444 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003445
3446 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003447 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003448 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003449
3450 return 0;
3451}
3452
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003453int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3454 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003455{
Johan Hedberg86742e12011-11-07 23:13:38 +02003456 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003457
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003458 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003459
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003460 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003461 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003462 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003463 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003464 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003465 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003466
Johan Hedberg744cf192011-11-08 20:40:14 +02003467 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003468}
Johan Hedbergf7520542011-01-20 12:34:39 +02003469
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003470int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3471{
3472 struct mgmt_ev_new_long_term_key ev;
3473
3474 memset(&ev, 0, sizeof(ev));
3475
3476 ev.store_hint = persistent;
3477 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003478 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003479 ev.key.authenticated = key->authenticated;
3480 ev.key.enc_size = key->enc_size;
3481 ev.key.ediv = key->ediv;
3482
3483 if (key->type == HCI_SMP_LTK)
3484 ev.key.master = 1;
3485
3486 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3487 memcpy(ev.key.val, key->val, sizeof(key->val));
3488
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003489 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3490 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003491}
3492
Johan Hedbergafc747a2012-01-15 18:11:07 +02003493int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003494 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3495 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003496{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003497 char buf[512];
3498 struct mgmt_ev_device_connected *ev = (void *) buf;
3499 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003500
Johan Hedbergb644ba32012-01-17 21:48:47 +02003501 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003502 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003503
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003504 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003505
Johan Hedbergb644ba32012-01-17 21:48:47 +02003506 if (name_len > 0)
3507 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003508 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003509
3510 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003511 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003512 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003513
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003514 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003515
3516 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003517 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003518}
3519
Johan Hedberg8962ee72011-01-20 12:40:27 +02003520static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3521{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003522 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003523 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003524 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003525
Johan Hedberg88c3df12012-02-09 14:27:38 +02003526 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3527 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003528
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003529 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003530 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003531
3532 *sk = cmd->sk;
3533 sock_hold(*sk);
3534
Johan Hedberga664b5b2011-02-19 12:06:02 -03003535 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003536}
3537
Johan Hedberg124f6e32012-02-09 13:50:12 +02003538static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003539{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003540 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003541 struct mgmt_cp_unpair_device *cp = cmd->param;
3542 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003543
3544 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003545 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3546 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003547
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003548 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3549
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003550 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003551
3552 mgmt_pending_remove(cmd);
3553}
3554
Johan Hedbergafc747a2012-01-15 18:11:07 +02003555int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003556 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003557{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003558 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003559 struct sock *sk = NULL;
3560 int err;
3561
Johan Hedberg744cf192011-11-08 20:40:14 +02003562 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003563
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003564 bacpy(&ev.addr.bdaddr, bdaddr);
3565 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3566 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003567
Johan Hedbergafc747a2012-01-15 18:11:07 +02003568 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003569 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003570
3571 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003572 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003573
Johan Hedberg124f6e32012-02-09 13:50:12 +02003574 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003575 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003576
Johan Hedberg8962ee72011-01-20 12:40:27 +02003577 return err;
3578}
3579
Johan Hedberg88c3df12012-02-09 14:27:38 +02003580int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003581 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003582{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003583 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003584 struct pending_cmd *cmd;
3585 int err;
3586
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003587 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3588 hdev);
3589
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003590 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003591 if (!cmd)
3592 return -ENOENT;
3593
Johan Hedberg88c3df12012-02-09 14:27:38 +02003594 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003595 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003596
Johan Hedberg88c3df12012-02-09 14:27:38 +02003597 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003598 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003599
Johan Hedberga664b5b2011-02-19 12:06:02 -03003600 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003601
3602 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003603}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003604
Johan Hedberg48264f02011-11-09 13:58:58 +02003605int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003606 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003607{
3608 struct mgmt_ev_connect_failed ev;
3609
Johan Hedberg4c659c32011-11-07 23:13:39 +02003610 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003611 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003612 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003613
Johan Hedberg744cf192011-11-08 20:40:14 +02003614 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003615}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003616
Johan Hedberg744cf192011-11-08 20:40:14 +02003617int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003618{
3619 struct mgmt_ev_pin_code_request ev;
3620
Johan Hedbergd8457692012-02-17 14:24:57 +02003621 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003622 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003623 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003624
Johan Hedberg744cf192011-11-08 20:40:14 +02003625 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003626 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003627}
3628
Johan Hedberg744cf192011-11-08 20:40:14 +02003629int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003630 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003631{
3632 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003633 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003634 int err;
3635
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003636 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003637 if (!cmd)
3638 return -ENOENT;
3639
Johan Hedbergd8457692012-02-17 14:24:57 +02003640 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003641 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003642
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003643 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003644 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003645
Johan Hedberga664b5b2011-02-19 12:06:02 -03003646 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003647
3648 return err;
3649}
3650
Johan Hedberg744cf192011-11-08 20:40:14 +02003651int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003652 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003653{
3654 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003655 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003656 int err;
3657
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003658 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003659 if (!cmd)
3660 return -ENOENT;
3661
Johan Hedbergd8457692012-02-17 14:24:57 +02003662 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003663 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003664
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003665 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003666 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003667
Johan Hedberga664b5b2011-02-19 12:06:02 -03003668 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003669
3670 return err;
3671}
Johan Hedberga5c29682011-02-19 12:05:57 -03003672
Johan Hedberg744cf192011-11-08 20:40:14 +02003673int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003674 u8 link_type, u8 addr_type, __le32 value,
3675 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003676{
3677 struct mgmt_ev_user_confirm_request ev;
3678
Johan Hedberg744cf192011-11-08 20:40:14 +02003679 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003680
Johan Hedberg272d90d2012-02-09 15:26:12 +02003681 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003682 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003683 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003684 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003685
Johan Hedberg744cf192011-11-08 20:40:14 +02003686 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003687 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003688}
3689
Johan Hedberg272d90d2012-02-09 15:26:12 +02003690int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003691 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003692{
3693 struct mgmt_ev_user_passkey_request ev;
3694
3695 BT_DBG("%s", hdev->name);
3696
Johan Hedberg272d90d2012-02-09 15:26:12 +02003697 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003698 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003699
3700 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003701 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003702}
3703
Brian Gix0df4c182011-11-16 13:53:13 -08003704static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003705 u8 link_type, u8 addr_type, u8 status,
3706 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003707{
3708 struct pending_cmd *cmd;
3709 struct mgmt_rp_user_confirm_reply rp;
3710 int err;
3711
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003712 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003713 if (!cmd)
3714 return -ENOENT;
3715
Johan Hedberg272d90d2012-02-09 15:26:12 +02003716 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003717 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003718 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003719 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003720
Johan Hedberga664b5b2011-02-19 12:06:02 -03003721 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003722
3723 return err;
3724}
3725
Johan Hedberg744cf192011-11-08 20:40:14 +02003726int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003727 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003728{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003729 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003730 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003731}
3732
Johan Hedberg272d90d2012-02-09 15:26:12 +02003733int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003734 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003735{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003736 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003737 status,
3738 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003739}
Johan Hedberg2a611692011-02-19 12:06:00 -03003740
Brian Gix604086b2011-11-23 08:28:33 -08003741int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003742 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003743{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003744 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003745 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003746}
3747
Johan Hedberg272d90d2012-02-09 15:26:12 +02003748int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003749 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003750{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003751 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003752 status,
3753 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003754}
3755
Johan Hedberg92a25252012-09-06 18:39:26 +03003756int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
3757 u8 link_type, u8 addr_type, u32 passkey,
3758 u8 entered)
3759{
3760 struct mgmt_ev_passkey_notify ev;
3761
3762 BT_DBG("%s", hdev->name);
3763
3764 bacpy(&ev.addr.bdaddr, bdaddr);
3765 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3766 ev.passkey = __cpu_to_le32(passkey);
3767 ev.entered = entered;
3768
3769 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
3770}
3771
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003772int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003773 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003774{
3775 struct mgmt_ev_auth_failed ev;
3776
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003777 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003778 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003779 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003780
Johan Hedberg744cf192011-11-08 20:40:14 +02003781 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003782}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003783
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003784int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3785{
3786 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003787 bool changed = false;
3788 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003789
3790 if (status) {
3791 u8 mgmt_err = mgmt_status(status);
3792 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003793 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003794 return 0;
3795 }
3796
Johan Hedberg47990ea2012-02-22 11:58:37 +02003797 if (test_bit(HCI_AUTH, &hdev->flags)) {
3798 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3799 changed = true;
3800 } else {
3801 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3802 changed = true;
3803 }
3804
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003805 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003806 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003807
Johan Hedberg47990ea2012-02-22 11:58:37 +02003808 if (changed)
3809 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003810
3811 if (match.sk)
3812 sock_put(match.sk);
3813
3814 return err;
3815}
3816
Johan Hedberg890ea892013-03-15 17:06:52 -05003817static void clear_eir(struct hci_request *req)
Johan Hedbergcacaf522012-02-21 00:52:42 +02003818{
Johan Hedberg890ea892013-03-15 17:06:52 -05003819 struct hci_dev *hdev = req->hdev;
Johan Hedbergcacaf522012-02-21 00:52:42 +02003820 struct hci_cp_write_eir cp;
3821
Johan Hedberg976eb202012-10-24 21:12:01 +03003822 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg890ea892013-03-15 17:06:52 -05003823 return;
Johan Hedbergcacaf522012-02-21 00:52:42 +02003824
Johan Hedbergc80da272012-02-22 15:38:48 +02003825 memset(hdev->eir, 0, sizeof(hdev->eir));
3826
Johan Hedbergcacaf522012-02-21 00:52:42 +02003827 memset(&cp, 0, sizeof(cp));
3828
Johan Hedberg890ea892013-03-15 17:06:52 -05003829 hci_req_add(req, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003830}
3831
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003832int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003833{
3834 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg890ea892013-03-15 17:06:52 -05003835 struct hci_request req;
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003836 bool changed = false;
3837 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003838
3839 if (status) {
3840 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003841
3842 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003843 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003844 err = new_settings(hdev, NULL);
3845
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003846 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3847 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003848
3849 return err;
3850 }
3851
3852 if (enable) {
3853 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3854 changed = true;
3855 } else {
3856 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3857 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003858 }
3859
3860 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3861
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003862 if (changed)
3863 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003864
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003865 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003866 sock_put(match.sk);
3867
Johan Hedberg890ea892013-03-15 17:06:52 -05003868 hci_req_init(&req, hdev);
3869
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003870 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg890ea892013-03-15 17:06:52 -05003871 update_eir(&req);
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003872 else
Johan Hedberg890ea892013-03-15 17:06:52 -05003873 clear_eir(&req);
3874
3875 hci_req_run(&req, NULL);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003876
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003877 return err;
3878}
3879
Johan Hedberg92da6092013-03-15 17:06:55 -05003880static void sk_lookup(struct pending_cmd *cmd, void *data)
Johan Hedberg90e70452012-02-23 23:09:40 +02003881{
3882 struct cmd_lookup *match = data;
3883
Johan Hedberg90e70452012-02-23 23:09:40 +02003884 if (match->sk == NULL) {
3885 match->sk = cmd->sk;
3886 sock_hold(match->sk);
3887 }
Johan Hedberg90e70452012-02-23 23:09:40 +02003888}
3889
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003890int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003891 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003892{
Johan Hedberg90e70452012-02-23 23:09:40 +02003893 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3894 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003895
Johan Hedberg92da6092013-03-15 17:06:55 -05003896 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, sk_lookup, &match);
3897 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, sk_lookup, &match);
3898 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, sk_lookup, &match);
Johan Hedberg90e70452012-02-23 23:09:40 +02003899
3900 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003901 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3902 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003903
3904 if (match.sk)
3905 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003906
3907 return err;
3908}
3909
Johan Hedberg744cf192011-11-08 20:40:14 +02003910int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003911{
Johan Hedbergb312b1612011-03-16 14:29:37 +02003912 struct mgmt_cp_set_local_name ev;
Johan Hedberg13928972013-03-15 17:07:00 -05003913 struct pending_cmd *cmd;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003914
Johan Hedberg13928972013-03-15 17:07:00 -05003915 if (status)
3916 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003917
3918 memset(&ev, 0, sizeof(ev));
3919 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003920 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003921
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003922 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedberg13928972013-03-15 17:07:00 -05003923 if (!cmd) {
3924 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003925
Johan Hedberg13928972013-03-15 17:07:00 -05003926 /* If this is a HCI command related to powering on the
3927 * HCI dev don't send any mgmt signals.
3928 */
3929 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev))
3930 return 0;
Johan Hedbergb312b1612011-03-16 14:29:37 +02003931 }
3932
Johan Hedberg13928972013-03-15 17:07:00 -05003933 return mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
3934 cmd ? cmd->sk : NULL);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003935}
Szymon Jancc35938b2011-03-22 13:12:21 +01003936
Johan Hedberg744cf192011-11-08 20:40:14 +02003937int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003938 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003939{
3940 struct pending_cmd *cmd;
3941 int err;
3942
Johan Hedberg744cf192011-11-08 20:40:14 +02003943 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003944
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003945 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003946 if (!cmd)
3947 return -ENOENT;
3948
3949 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003950 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3951 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003952 } else {
3953 struct mgmt_rp_read_local_oob_data rp;
3954
3955 memcpy(rp.hash, hash, sizeof(rp.hash));
3956 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3957
Johan Hedberg744cf192011-11-08 20:40:14 +02003958 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003959 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3960 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003961 }
3962
3963 mgmt_pending_remove(cmd);
3964
3965 return err;
3966}
Johan Hedberge17acd42011-03-30 23:57:16 +03003967
Johan Hedberg06199cf2012-02-22 16:37:11 +02003968int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3969{
3970 struct cmd_lookup match = { NULL, hdev };
3971 bool changed = false;
3972 int err = 0;
3973
3974 if (status) {
3975 u8 mgmt_err = mgmt_status(status);
3976
3977 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003978 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003979 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003980
Szymon Jancd97dcb62012-03-16 16:02:56 +01003981 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3982 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003983
3984 return err;
3985 }
3986
3987 if (enable) {
3988 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3989 changed = true;
3990 } else {
3991 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3992 changed = true;
3993 }
3994
3995 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3996
3997 if (changed)
3998 err = new_settings(hdev, match.sk);
3999
4000 if (match.sk)
4001 sock_put(match.sk);
4002
4003 return err;
4004}
4005
Johan Hedberg48264f02011-11-09 13:58:58 +02004006int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004007 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
4008 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03004009{
Johan Hedberge319d2e2012-01-15 19:51:59 +02004010 char buf[512];
4011 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02004012 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03004013
Johan Hedberg1dc06092012-01-15 21:01:23 +02004014 /* Leave 5 bytes for a potential CoD field */
4015 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03004016 return -EINVAL;
4017
Johan Hedberg1dc06092012-01-15 21:01:23 +02004018 memset(buf, 0, sizeof(buf));
4019
Johan Hedberge319d2e2012-01-15 19:51:59 +02004020 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004021 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02004022 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02004023 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304024 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02004025 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05304026 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03004027
Johan Hedberg1dc06092012-01-15 21:01:23 +02004028 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02004029 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03004030
Johan Hedberg1dc06092012-01-15 21:01:23 +02004031 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
4032 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004033 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004034
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004035 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02004036 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03004037
Johan Hedberge319d2e2012-01-15 19:51:59 +02004038 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03004039}
Johan Hedberga88a9652011-03-30 13:18:12 +03004040
Johan Hedbergb644ba32012-01-17 21:48:47 +02004041int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004042 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03004043{
Johan Hedbergb644ba32012-01-17 21:48:47 +02004044 struct mgmt_ev_device_found *ev;
4045 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
4046 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03004047
Johan Hedbergb644ba32012-01-17 21:48:47 +02004048 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03004049
Johan Hedbergb644ba32012-01-17 21:48:47 +02004050 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03004051
Johan Hedbergb644ba32012-01-17 21:48:47 +02004052 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03004053 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004054 ev->rssi = rssi;
4055
4056 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004057 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004058
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02004059 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02004060
Johan Hedberg053c7e02012-02-04 00:06:00 +02004061 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004062 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03004063}
Johan Hedberg314b2382011-04-27 10:29:57 -04004064
Andre Guedes7a135102011-11-09 17:14:25 -03004065int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02004066{
4067 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02004068 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004069 int err;
4070
Andre Guedes203159d2012-02-13 15:41:01 -03004071 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
4072
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004073 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004074 if (!cmd)
4075 return -ENOENT;
4076
Johan Hedbergf808e162012-02-19 12:52:07 +02004077 type = hdev->discovery.type;
4078
4079 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004080 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004081 mgmt_pending_remove(cmd);
4082
4083 return err;
4084}
4085
Andre Guedese6d465c2011-11-09 17:14:26 -03004086int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
4087{
4088 struct pending_cmd *cmd;
4089 int err;
4090
4091 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
4092 if (!cmd)
4093 return -ENOENT;
4094
Johan Hedbergd9306502012-02-20 23:25:18 +02004095 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004096 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02004097 mgmt_pending_remove(cmd);
4098
4099 return err;
4100}
Johan Hedberg314b2382011-04-27 10:29:57 -04004101
Johan Hedberg744cf192011-11-08 20:40:14 +02004102int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04004103{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004104 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02004105 struct pending_cmd *cmd;
4106
Andre Guedes343fb142011-11-22 17:14:19 -03004107 BT_DBG("%s discovering %u", hdev->name, discovering);
4108
Johan Hedberg164a6e72011-11-01 17:06:44 +02004109 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004110 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004111 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004112 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02004113
4114 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02004115 u8 type = hdev->discovery.type;
4116
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004117 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
4118 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02004119 mgmt_pending_remove(cmd);
4120 }
4121
Johan Hedbergf963e8e2012-02-20 23:30:44 +02004122 memset(&ev, 0, sizeof(ev));
4123 ev.type = hdev->discovery.type;
4124 ev.discovering = discovering;
4125
4126 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04004127}
Antti Julku5e762442011-08-25 16:48:02 +03004128
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004129int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004130{
4131 struct pending_cmd *cmd;
4132 struct mgmt_ev_device_blocked ev;
4133
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004134 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004135
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004136 bacpy(&ev.addr.bdaddr, bdaddr);
4137 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004138
Johan Hedberg744cf192011-11-08 20:40:14 +02004139 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004140 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004141}
4142
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004143int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03004144{
4145 struct pending_cmd *cmd;
4146 struct mgmt_ev_device_unblocked ev;
4147
Johan Hedberg2e58ef32011-11-08 20:40:15 +02004148 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03004149
Johan Hedberg88c1fe42012-02-09 15:56:11 +02004150 bacpy(&ev.addr.bdaddr, bdaddr);
4151 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03004152
Johan Hedberg744cf192011-11-08 20:40:14 +02004153 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03004154 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03004155}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01004156
4157module_param(enable_hs, bool, 0644);
4158MODULE_PARM_DESC(enable_hs, "Enable High Speed support");