blob: 0110a75661ef218b889d819fec94b5e9e448cf3f [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 Hedberg23b3b132012-09-06 18:39:27 +030038#define MGMT_REVISION 2
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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200218
Andre Guedes790eff42012-06-07 19:05:46 -0300219 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_KERNEL);
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200235 kfree_skb(skb);
236
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300237 return err;
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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;
387 settings |= MGMT_SETTING_FAST_CONNECTABLE;
388 settings |= MGMT_SETTING_DISCOVERABLE;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389 settings |= MGMT_SETTING_BREDR;
390 settings |= MGMT_SETTING_LINK_SECURITY;
391 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200392
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100393 if (enable_hs)
394 settings |= MGMT_SETTING_HS;
395
Andre Guedesc383ddc2012-07-24 15:03:47 -0300396 if (lmp_le_capable(hdev))
Marcel Holtmann9d428202012-05-03 07:12:31 +0200397 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200398
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 return settings;
400}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200401
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402static u32 get_current_settings(struct hci_dev *hdev)
403{
404 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200405
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200406 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100407 settings |= MGMT_SETTING_POWERED;
408
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200409 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_CONNECTABLE;
411
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200412 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_DISCOVERABLE;
414
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200415 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_PAIRABLE;
417
Andre Guedesed3fa312012-07-24 15:03:46 -0300418 if (lmp_bredr_capable(hdev))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_BREDR;
420
Johan Hedberg06199cf2012-02-22 16:37:11 +0200421 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200423
Johan Hedberg47990ea2012-02-22 11:58:37 +0200424 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200426
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200427 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200428 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200429
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200430 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
431 settings |= MGMT_SETTING_HS;
432
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200433 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200434}
435
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300436#define PNP_INFO_SVCLASS_ID 0x1200
437
Johan Hedberg213202e2013-01-27 00:31:33 +0200438static u8 *create_uuid16_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
439{
440 u8 *ptr = data, *uuids_start = NULL;
441 struct bt_uuid *uuid;
442
443 if (len < 4)
444 return ptr;
445
446 list_for_each_entry(uuid, &hdev->uuids, list) {
447 u16 uuid16;
448
449 if (uuid->size != 16)
450 continue;
451
452 uuid16 = get_unaligned_le16(&uuid->uuid[12]);
453 if (uuid16 < 0x1100)
454 continue;
455
456 if (uuid16 == PNP_INFO_SVCLASS_ID)
457 continue;
458
459 if (!uuids_start) {
460 uuids_start = ptr;
461 uuids_start[0] = 1;
462 uuids_start[1] = EIR_UUID16_ALL;
463 ptr += 2;
464 }
465
466 /* Stop if not enough space to put next UUID */
467 if ((ptr - data) + sizeof(u16) > len) {
468 uuids_start[1] = EIR_UUID16_SOME;
469 break;
470 }
471
472 *ptr++ = (uuid16 & 0x00ff);
473 *ptr++ = (uuid16 & 0xff00) >> 8;
474 uuids_start[0] += sizeof(uuid16);
475 }
476
477 return ptr;
478}
479
Johan Hedbergcdf19632013-01-27 00:31:34 +0200480static u8 *create_uuid32_list(struct hci_dev *hdev, u8 *data, ptrdiff_t len)
481{
482 u8 *ptr = data, *uuids_start = NULL;
483 struct bt_uuid *uuid;
484
485 if (len < 6)
486 return ptr;
487
488 list_for_each_entry(uuid, &hdev->uuids, list) {
489 if (uuid->size != 32)
490 continue;
491
492 if (!uuids_start) {
493 uuids_start = ptr;
494 uuids_start[0] = 1;
495 uuids_start[1] = EIR_UUID32_ALL;
496 ptr += 2;
497 }
498
499 /* Stop if not enough space to put next UUID */
500 if ((ptr - data) + sizeof(u32) > len) {
501 uuids_start[1] = EIR_UUID32_SOME;
502 break;
503 }
504
505 memcpy(ptr, &uuid->uuid[12], sizeof(u32));
506 ptr += sizeof(u32);
507 uuids_start[0] += sizeof(u32);
508 }
509
510 return ptr;
511}
512
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300513static void create_eir(struct hci_dev *hdev, u8 *data)
514{
515 u8 *ptr = data;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300516 size_t name_len;
517
518 name_len = strlen(hdev->dev_name);
519
520 if (name_len > 0) {
521 /* EIR Data type */
522 if (name_len > 48) {
523 name_len = 48;
524 ptr[1] = EIR_NAME_SHORT;
525 } else
526 ptr[1] = EIR_NAME_COMPLETE;
527
528 /* EIR Data length */
529 ptr[0] = name_len + 1;
530
531 memcpy(ptr + 2, hdev->dev_name, name_len);
532
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300533 ptr += (name_len + 2);
534 }
535
Johan Hedbergbbaf4442012-11-08 01:22:59 +0100536 if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700537 ptr[0] = 2;
538 ptr[1] = EIR_TX_POWER;
539 ptr[2] = (u8) hdev->inq_tx_power;
540
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700541 ptr += 3;
542 }
543
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700544 if (hdev->devid_source > 0) {
545 ptr[0] = 9;
546 ptr[1] = EIR_DEVICE_ID;
547
548 put_unaligned_le16(hdev->devid_source, ptr + 2);
549 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
550 put_unaligned_le16(hdev->devid_product, ptr + 6);
551 put_unaligned_le16(hdev->devid_version, ptr + 8);
552
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700553 ptr += 10;
554 }
555
Johan Hedberg213202e2013-01-27 00:31:33 +0200556 ptr = create_uuid16_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedbergcdf19632013-01-27 00:31:34 +0200557 ptr = create_uuid32_list(hdev, ptr, HCI_MAX_EIR_LENGTH - (ptr - data));
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300558}
559
560static int update_eir(struct hci_dev *hdev)
561{
562 struct hci_cp_write_eir cp;
563
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200564 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200565 return 0;
566
Johan Hedberg976eb202012-10-24 21:12:01 +0300567 if (!lmp_ext_inq_capable(hdev))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300568 return 0;
569
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200570 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300571 return 0;
572
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200573 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300574 return 0;
575
576 memset(&cp, 0, sizeof(cp));
577
578 create_eir(hdev, cp.data);
579
580 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
581 return 0;
582
583 memcpy(hdev->eir, cp.data, sizeof(cp.data));
584
585 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
586}
587
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200588static u8 get_service_classes(struct hci_dev *hdev)
589{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300590 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200591 u8 val = 0;
592
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300593 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200594 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200595
596 return val;
597}
598
599static int update_class(struct hci_dev *hdev)
600{
601 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200602 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200603
604 BT_DBG("%s", hdev->name);
605
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200606 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200607 return 0;
608
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200609 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200610 return 0;
611
612 cod[0] = hdev->minor_class;
613 cod[1] = hdev->major_class;
614 cod[2] = get_service_classes(hdev);
615
616 if (memcmp(cod, hdev->dev_class, 3) == 0)
617 return 0;
618
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200619 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
620 if (err == 0)
621 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
622
623 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200624}
625
Johan Hedberg7d785252011-12-15 00:47:39 +0200626static void service_cache_off(struct work_struct *work)
627{
628 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300629 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200630
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200631 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200632 return;
633
634 hci_dev_lock(hdev);
635
636 update_eir(hdev);
637 update_class(hdev);
638
639 hci_dev_unlock(hdev);
640}
641
Johan Hedberg6a919082012-02-28 06:17:26 +0200642static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200643{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200644 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200645 return;
646
Johan Hedberg4f87da82012-03-02 19:55:56 +0200647 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200648
Johan Hedberg4f87da82012-03-02 19:55:56 +0200649 /* Non-mgmt controlled devices get this bit set
650 * implicitly so that pairing works for them, however
651 * for mgmt we require user-space to explicitly enable
652 * it
653 */
654 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200655}
656
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200657static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300658 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200659{
660 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200661
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200662 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200663
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300664 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200665
Johan Hedberg03811012010-12-08 00:21:06 +0200666 memset(&rp, 0, sizeof(rp));
667
Johan Hedberg03811012010-12-08 00:21:06 +0200668 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200669
670 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200671 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200672
673 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
674 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
675
676 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200677
678 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200679 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200680
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300681 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200682
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200683 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300684 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200685}
686
687static void mgmt_pending_free(struct pending_cmd *cmd)
688{
689 sock_put(cmd->sk);
690 kfree(cmd->param);
691 kfree(cmd);
692}
693
694static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300695 struct hci_dev *hdev, void *data,
696 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200697{
698 struct pending_cmd *cmd;
699
Andre Guedes12b94562012-06-07 19:05:45 -0300700 cmd = kmalloc(sizeof(*cmd), GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200701 if (!cmd)
702 return NULL;
703
704 cmd->opcode = opcode;
705 cmd->index = hdev->id;
706
Andre Guedes12b94562012-06-07 19:05:45 -0300707 cmd->param = kmalloc(len, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +0200708 if (!cmd->param) {
709 kfree(cmd);
710 return NULL;
711 }
712
713 if (data)
714 memcpy(cmd->param, data, len);
715
716 cmd->sk = sk;
717 sock_hold(sk);
718
719 list_add(&cmd->list, &hdev->mgmt_pending);
720
721 return cmd;
722}
723
724static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300725 void (*cb)(struct pending_cmd *cmd,
726 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300727 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200728{
729 struct list_head *p, *n;
730
731 list_for_each_safe(p, n, &hdev->mgmt_pending) {
732 struct pending_cmd *cmd;
733
734 cmd = list_entry(p, struct pending_cmd, list);
735
736 if (opcode > 0 && cmd->opcode != opcode)
737 continue;
738
739 cb(cmd, data);
740 }
741}
742
743static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
744{
745 struct pending_cmd *cmd;
746
747 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
748 if (cmd->opcode == opcode)
749 return cmd;
750 }
751
752 return NULL;
753}
754
755static void mgmt_pending_remove(struct pending_cmd *cmd)
756{
757 list_del(&cmd->list);
758 mgmt_pending_free(cmd);
759}
760
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200761static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200762{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200763 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200764
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200765 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300766 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200767}
768
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200769static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300770 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200771{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300772 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200773 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200774 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200775
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200776 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200777
Johan Hedberga7e80f22013-01-09 16:05:19 +0200778 if (cp->val != 0x00 && cp->val != 0x01)
779 return cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
780 MGMT_STATUS_INVALID_PARAMS);
781
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300782 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200783
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100784 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
785 cancel_delayed_work(&hdev->power_off);
786
787 if (cp->val) {
Johan Hedberga1d70452013-01-09 15:29:40 +0200788 mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev,
789 data, len);
790 err = mgmt_powered(hdev, 1);
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100791 goto failed;
792 }
793 }
794
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200795 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200796 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200797 goto failed;
798 }
799
800 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200801 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300802 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200803 goto failed;
804 }
805
806 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
807 if (!cmd) {
808 err = -ENOMEM;
809 goto failed;
810 }
811
812 if (cp->val)
Johan Hedberg19202572013-01-14 22:33:51 +0200813 queue_work(hdev->req_workqueue, &hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200814 else
Johan Hedberg19202572013-01-14 22:33:51 +0200815 queue_work(hdev->req_workqueue, &hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200816
817 err = 0;
818
819failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300820 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200821 return err;
822}
823
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300824static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
825 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200826{
827 struct sk_buff *skb;
828 struct mgmt_hdr *hdr;
829
Andre Guedes790eff42012-06-07 19:05:46 -0300830 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_KERNEL);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200831 if (!skb)
832 return -ENOMEM;
833
834 hdr = (void *) skb_put(skb, sizeof(*hdr));
835 hdr->opcode = cpu_to_le16(event);
836 if (hdev)
837 hdr->index = cpu_to_le16(hdev->id);
838 else
Syam Sidhardhan612dfce2012-10-29 22:37:36 +0530839 hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200840 hdr->len = cpu_to_le16(data_len);
841
842 if (data)
843 memcpy(skb_put(skb, data_len), data, data_len);
844
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100845 /* Time stamp */
846 __net_timestamp(skb);
847
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200848 hci_send_to_control(skb, skip_sk);
849 kfree_skb(skb);
850
851 return 0;
852}
853
854static int new_settings(struct hci_dev *hdev, struct sock *skip)
855{
856 __le32 ev;
857
858 ev = cpu_to_le32(get_current_settings(hdev));
859
860 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
861}
862
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200863static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300864 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200865{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300866 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200867 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200868 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200869 u8 scan;
870 int err;
871
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200872 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200873
Johan Hedberg33c525c2012-10-24 21:11:58 +0300874 if (!lmp_bredr_capable(hdev))
875 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
876 MGMT_STATUS_NOT_SUPPORTED);
877
Johan Hedberga7e80f22013-01-09 16:05:19 +0200878 if (cp->val != 0x00 && cp->val != 0x01)
879 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
880 MGMT_STATUS_INVALID_PARAMS);
881
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700882 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100883 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200884 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300885 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200886
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300887 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200888
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200889 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200890 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300891 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200892 goto failed;
893 }
894
895 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300896 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200897 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300898 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200899 goto failed;
900 }
901
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200902 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200903 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300904 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200905 goto failed;
906 }
907
908 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200909 bool changed = false;
910
911 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
912 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
913 changed = true;
914 }
915
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200916 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200917 if (err < 0)
918 goto failed;
919
920 if (changed)
921 err = new_settings(hdev, sk);
922
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200923 goto failed;
924 }
925
926 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100927 if (hdev->discov_timeout > 0) {
928 cancel_delayed_work(&hdev->discov_off);
929 hdev->discov_timeout = 0;
930 }
931
932 if (cp->val && timeout > 0) {
933 hdev->discov_timeout = timeout;
934 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
935 msecs_to_jiffies(hdev->discov_timeout * 1000));
936 }
937
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200938 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200939 goto failed;
940 }
941
942 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
943 if (!cmd) {
944 err = -ENOMEM;
945 goto failed;
946 }
947
948 scan = SCAN_PAGE;
949
950 if (cp->val)
951 scan |= SCAN_INQUIRY;
952 else
953 cancel_delayed_work(&hdev->discov_off);
954
955 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
956 if (err < 0)
957 mgmt_pending_remove(cmd);
958
Johan Hedberg03811012010-12-08 00:21:06 +0200959 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200960 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200961
962failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300963 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200964 return err;
965}
966
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200967static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300968 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200969{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300970 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200971 struct pending_cmd *cmd;
972 u8 scan;
973 int err;
974
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200975 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200976
Johan Hedberg33c525c2012-10-24 21:11:58 +0300977 if (!lmp_bredr_capable(hdev))
978 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
979 MGMT_STATUS_NOT_SUPPORTED);
980
Johan Hedberga7e80f22013-01-09 16:05:19 +0200981 if (cp->val != 0x00 && cp->val != 0x01)
982 return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
983 MGMT_STATUS_INVALID_PARAMS);
984
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300985 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200986
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200987 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200988 bool changed = false;
989
990 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
991 changed = true;
992
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200993 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200994 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200995 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200996 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
997 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
998 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200999
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001000 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +02001001 if (err < 0)
1002 goto failed;
1003
1004 if (changed)
1005 err = new_settings(hdev, sk);
1006
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001007 goto failed;
1008 }
1009
1010 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001011 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001012 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001013 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001014 goto failed;
1015 }
1016
Johan Hedberg5e5282b2012-02-21 16:01:30 +02001017 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001018 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001019 goto failed;
1020 }
1021
1022 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
1023 if (!cmd) {
1024 err = -ENOMEM;
1025 goto failed;
1026 }
1027
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001028 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001029 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001030 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001031 scan = 0;
1032
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001033 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001034 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001035 cancel_delayed_work(&hdev->discov_off);
1036 }
1037
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001038 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1039 if (err < 0)
1040 mgmt_pending_remove(cmd);
1041
1042failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001043 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001044 return err;
1045}
1046
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001047static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001048 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001049{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001050 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001051 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001052
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001053 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001054
Johan Hedberga7e80f22013-01-09 16:05:19 +02001055 if (cp->val != 0x00 && cp->val != 0x01)
1056 return cmd_status(sk, hdev->id, MGMT_OP_SET_PAIRABLE,
1057 MGMT_STATUS_INVALID_PARAMS);
1058
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001059 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001060
1061 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001062 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001063 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001064 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001065
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001066 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001067 if (err < 0)
1068 goto failed;
1069
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001070 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001071
1072failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001073 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001074 return err;
1075}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001076
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001077static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1078 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001079{
1080 struct mgmt_mode *cp = data;
1081 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001082 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001083 int err;
1084
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001085 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001086
Johan Hedberg33c525c2012-10-24 21:11:58 +03001087 if (!lmp_bredr_capable(hdev))
1088 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1089 MGMT_STATUS_NOT_SUPPORTED);
1090
Johan Hedberga7e80f22013-01-09 16:05:19 +02001091 if (cp->val != 0x00 && cp->val != 0x01)
1092 return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
1093 MGMT_STATUS_INVALID_PARAMS);
1094
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001095 hci_dev_lock(hdev);
1096
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001097 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001098 bool changed = false;
1099
1100 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001101 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001102 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1103 changed = true;
1104 }
1105
1106 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1107 if (err < 0)
1108 goto failed;
1109
1110 if (changed)
1111 err = new_settings(hdev, sk);
1112
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001113 goto failed;
1114 }
1115
1116 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001117 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001118 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001119 goto failed;
1120 }
1121
1122 val = !!cp->val;
1123
1124 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1125 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1126 goto failed;
1127 }
1128
1129 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1130 if (!cmd) {
1131 err = -ENOMEM;
1132 goto failed;
1133 }
1134
1135 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1136 if (err < 0) {
1137 mgmt_pending_remove(cmd);
1138 goto failed;
1139 }
1140
1141failed:
1142 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001143 return err;
1144}
1145
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001146static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001147{
1148 struct mgmt_mode *cp = data;
1149 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001150 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001151 int err;
1152
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001153 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001154
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001155 if (!lmp_ssp_capable(hdev))
1156 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1157 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001158
Johan Hedberga7e80f22013-01-09 16:05:19 +02001159 if (cp->val != 0x00 && cp->val != 0x01)
1160 return cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1161 MGMT_STATUS_INVALID_PARAMS);
1162
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001163 hci_dev_lock(hdev);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001164
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001165 val = !!cp->val;
1166
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001167 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001168 bool changed = false;
1169
1170 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1171 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1172 changed = true;
1173 }
1174
1175 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1176 if (err < 0)
1177 goto failed;
1178
1179 if (changed)
1180 err = new_settings(hdev, sk);
1181
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001182 goto failed;
1183 }
1184
1185 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001186 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1187 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001188 goto failed;
1189 }
1190
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001191 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1192 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1193 goto failed;
1194 }
1195
1196 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1197 if (!cmd) {
1198 err = -ENOMEM;
1199 goto failed;
1200 }
1201
1202 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1203 if (err < 0) {
1204 mgmt_pending_remove(cmd);
1205 goto failed;
1206 }
1207
1208failed:
1209 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001210 return err;
1211}
1212
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001213static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001214{
1215 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001216
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001217 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001218
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001219 if (!enable_hs)
1220 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001221 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001222
Johan Hedberga7e80f22013-01-09 16:05:19 +02001223 if (cp->val != 0x00 && cp->val != 0x01)
1224 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
1225 MGMT_STATUS_INVALID_PARAMS);
1226
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001227 if (cp->val)
1228 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1229 else
1230 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1231
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001232 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001233}
1234
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001235static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001236{
1237 struct mgmt_mode *cp = data;
1238 struct hci_cp_write_le_host_supported hci_cp;
1239 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001240 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001241 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001242
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001243 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001244
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001245 if (!lmp_le_capable(hdev))
1246 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1247 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001248
Johan Hedberga7e80f22013-01-09 16:05:19 +02001249 if (cp->val != 0x00 && cp->val != 0x01)
1250 return cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
1251 MGMT_STATUS_INVALID_PARAMS);
1252
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001253 hci_dev_lock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001254
1255 val = !!cp->val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001256 enabled = lmp_host_le_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001257
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001258 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001259 bool changed = false;
1260
1261 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1262 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1263 changed = true;
1264 }
1265
1266 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1267 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001268 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001269
1270 if (changed)
1271 err = new_settings(hdev, sk);
1272
Johan Hedberg1de028c2012-02-29 19:55:35 -08001273 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001274 }
1275
1276 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001277 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001278 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001279 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001280 }
1281
1282 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1283 if (!cmd) {
1284 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001285 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001286 }
1287
1288 memset(&hci_cp, 0, sizeof(hci_cp));
1289
1290 if (val) {
1291 hci_cp.le = val;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02001292 hci_cp.simul = lmp_le_br_capable(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001293 }
1294
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001295 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1296 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301297 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001298 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001299
Johan Hedberg1de028c2012-02-29 19:55:35 -08001300unlock:
1301 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001302 return err;
1303}
1304
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001305static const u8 bluetooth_base_uuid[] = {
1306 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
1307 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1308};
1309
1310static u8 get_uuid_size(const u8 *uuid)
1311{
1312 u32 val;
1313
1314 if (memcmp(uuid, bluetooth_base_uuid, 12))
1315 return 128;
1316
1317 val = get_unaligned_le32(&uuid[12]);
1318 if (val > 0xffff)
1319 return 32;
1320
1321 return 16;
1322}
1323
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001324static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001325{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001326 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001327 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001328 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001329 int err;
1330
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001331 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001332
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001333 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001334
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001335 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001336 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001337 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001338 goto failed;
1339 }
1340
Andre Guedes92c4c202012-06-07 19:05:44 -03001341 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001342 if (!uuid) {
1343 err = -ENOMEM;
1344 goto failed;
1345 }
1346
1347 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001348 uuid->svc_hint = cp->svc_hint;
Johan Hedberg83be8ec2013-01-27 00:31:29 +02001349 uuid->size = get_uuid_size(cp->uuid);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001350
Johan Hedbergde66aa62013-01-27 00:31:27 +02001351 list_add_tail(&uuid->list, &hdev->uuids);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001352
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001353 err = update_class(hdev);
1354 if (err < 0)
1355 goto failed;
1356
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001357 err = update_eir(hdev);
1358 if (err < 0)
1359 goto failed;
1360
Johan Hedberg90e70452012-02-23 23:09:40 +02001361 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001362 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001363 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001364 goto failed;
1365 }
1366
1367 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301368 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001369 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001370
1371failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001372 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001373 return err;
1374}
1375
Johan Hedberg24b78d02012-02-23 23:24:30 +02001376static bool enable_service_cache(struct hci_dev *hdev)
1377{
1378 if (!hdev_is_powered(hdev))
1379 return false;
1380
1381 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg46818ed2013-01-14 22:33:52 +02001382 queue_delayed_work(hdev->workqueue, &hdev->service_cache,
1383 CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001384 return true;
1385 }
1386
1387 return false;
1388}
1389
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001390static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001391 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001392{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001393 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001394 struct pending_cmd *cmd;
Johan Hedberg056341c2013-01-27 00:31:30 +02001395 struct bt_uuid *match, *tmp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001396 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001397 int err, found;
1398
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001399 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001400
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001401 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001402
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001403 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001404 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001405 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001406 goto unlock;
1407 }
1408
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001409 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1410 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001411
Johan Hedberg24b78d02012-02-23 23:24:30 +02001412 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001413 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001414 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001415 goto unlock;
1416 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001417
Johan Hedberg9246a862012-02-23 21:33:16 +02001418 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001419 }
1420
1421 found = 0;
1422
Johan Hedberg056341c2013-01-27 00:31:30 +02001423 list_for_each_entry_safe(match, tmp, &hdev->uuids, list) {
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001424 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1425 continue;
1426
1427 list_del(&match->list);
Johan Hedberg482049f2012-11-08 10:25:26 +01001428 kfree(match);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001429 found++;
1430 }
1431
1432 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001433 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001434 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001435 goto unlock;
1436 }
1437
Johan Hedberg9246a862012-02-23 21:33:16 +02001438update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001439 err = update_class(hdev);
1440 if (err < 0)
1441 goto unlock;
1442
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001443 err = update_eir(hdev);
1444 if (err < 0)
1445 goto unlock;
1446
Johan Hedberg90e70452012-02-23 23:09:40 +02001447 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001448 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001449 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001450 goto unlock;
1451 }
1452
1453 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301454 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001455 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001456
1457unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001458 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001459 return err;
1460}
1461
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001462static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001463 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001464{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001465 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001466 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001467 int err;
1468
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001469 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001470
Johan Hedberg13ecd8b2013-01-09 15:29:38 +02001471 if (!lmp_bredr_capable(hdev))
1472 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1473 MGMT_STATUS_NOT_SUPPORTED);
1474
1475 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags))
1476 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1477 MGMT_STATUS_BUSY);
1478
1479 if ((cp->minor & 0x03) != 0 || (cp->major & 0xe0) != 0)
1480 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
1481 MGMT_STATUS_INVALID_PARAMS);
1482
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001483 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001484
1485 hdev->major_class = cp->major;
1486 hdev->minor_class = cp->minor;
1487
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001488 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001489 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001490 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001491 goto unlock;
1492 }
1493
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001494 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001495 hci_dev_unlock(hdev);
1496 cancel_delayed_work_sync(&hdev->service_cache);
1497 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001498 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001499 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001500
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001501 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001502 if (err < 0)
1503 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001504
Johan Hedberg90e70452012-02-23 23:09:40 +02001505 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001506 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001507 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001508 goto unlock;
1509 }
1510
1511 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301512 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001513 err = -ENOMEM;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001514
Johan Hedbergb5235a62012-02-21 14:32:24 +02001515unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001516 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001517 return err;
1518}
1519
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001520static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001521 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001522{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001523 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001524 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001525 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001526
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001527 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001528
Johan Hedberg86742e12011-11-07 23:13:38 +02001529 expected_len = sizeof(*cp) + key_count *
1530 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001531 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001532 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001533 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001534 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001535 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001536 }
1537
Johan Hedberg4ae14302013-01-20 14:27:13 +02001538 if (cp->debug_keys != 0x00 && cp->debug_keys != 0x01)
1539 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1540 MGMT_STATUS_INVALID_PARAMS);
1541
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001542 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001543 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001544
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001545 for (i = 0; i < key_count; i++) {
1546 struct mgmt_link_key_info *key = &cp->keys[i];
1547
1548 if (key->addr.type != BDADDR_BREDR)
1549 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
1550 MGMT_STATUS_INVALID_PARAMS);
1551 }
1552
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001553 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001554
1555 hci_link_keys_clear(hdev);
1556
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001557 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001558
1559 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001560 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001561 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001562 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001563
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001564 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001565 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001566
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001567 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001568 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001569 }
1570
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001571 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001572
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001573 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001574
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001575 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001576}
1577
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001578static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001579 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001580{
1581 struct mgmt_ev_device_unpaired ev;
1582
1583 bacpy(&ev.addr.bdaddr, bdaddr);
1584 ev.addr.type = addr_type;
1585
1586 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001587 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001588}
1589
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001590static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001591 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001592{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001593 struct mgmt_cp_unpair_device *cp = data;
1594 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001595 struct hci_cp_disconnect dc;
1596 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001597 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001598 int err;
1599
Johan Hedberga8a1d192011-11-10 15:54:38 +02001600 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001601 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1602 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001603
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001604 if (!bdaddr_type_is_valid(cp->addr.type))
1605 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1606 MGMT_STATUS_INVALID_PARAMS,
1607 &rp, sizeof(rp));
1608
Johan Hedberg118da702013-01-20 14:27:20 +02001609 if (cp->disconnect != 0x00 && cp->disconnect != 0x01)
1610 return cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
1611 MGMT_STATUS_INVALID_PARAMS,
1612 &rp, sizeof(rp));
1613
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001614 hci_dev_lock(hdev);
1615
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001616 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001617 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001618 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001619 goto unlock;
1620 }
1621
Andre Guedes591f47f2012-04-24 21:02:49 -03001622 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001623 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1624 else
1625 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001626
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001627 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001628 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001629 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001630 goto unlock;
1631 }
1632
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001633 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001634 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001635 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001636 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001637 else
1638 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001639 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001640 } else {
1641 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001642 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001643
Johan Hedberga8a1d192011-11-10 15:54:38 +02001644 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001645 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001646 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001647 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001648 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001649 }
1650
Johan Hedberg124f6e32012-02-09 13:50:12 +02001651 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001652 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001653 if (!cmd) {
1654 err = -ENOMEM;
1655 goto unlock;
1656 }
1657
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001658 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001659 dc.reason = 0x13; /* Remote User Terminated Connection */
1660 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1661 if (err < 0)
1662 mgmt_pending_remove(cmd);
1663
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001664unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001665 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001666 return err;
1667}
1668
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001669static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001670 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001671{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001672 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg06a63b12013-01-20 14:27:21 +02001673 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001674 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001675 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001676 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001677 int err;
1678
1679 BT_DBG("");
1680
Johan Hedberg06a63b12013-01-20 14:27:21 +02001681 memset(&rp, 0, sizeof(rp));
1682 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1683 rp.addr.type = cp->addr.type;
1684
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001685 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg06a63b12013-01-20 14:27:21 +02001686 return cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1687 MGMT_STATUS_INVALID_PARAMS,
1688 &rp, sizeof(rp));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001689
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001690 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001691
1692 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001693 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1694 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001695 goto failed;
1696 }
1697
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001698 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001699 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1700 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001701 goto failed;
1702 }
1703
Andre Guedes591f47f2012-04-24 21:02:49 -03001704 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001705 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1706 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001707 else
1708 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001709
Vishal Agarwalf9607272012-06-13 05:32:43 +05301710 if (!conn || conn->state == BT_OPEN || conn->state == BT_CLOSED) {
Johan Hedberg06a63b12013-01-20 14:27:21 +02001711 err = cmd_complete(sk, hdev->id, MGMT_OP_DISCONNECT,
1712 MGMT_STATUS_NOT_CONNECTED, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02001713 goto failed;
1714 }
1715
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001716 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001717 if (!cmd) {
1718 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001719 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001720 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001721
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001722 dc.handle = cpu_to_le16(conn->handle);
Andre Guedes3701f942012-06-11 18:41:12 -03001723 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001724
1725 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1726 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001727 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001728
1729failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001730 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001731 return err;
1732}
1733
Andre Guedes57c14772012-04-24 21:02:50 -03001734static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001735{
1736 switch (link_type) {
1737 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001738 switch (addr_type) {
1739 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001740 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001741
Johan Hedberg48264f02011-11-09 13:58:58 +02001742 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001743 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001744 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001745 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001746
Johan Hedberg4c659c32011-11-07 23:13:39 +02001747 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001748 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001749 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001750 }
1751}
1752
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001753static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1754 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001755{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001756 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001757 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001758 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001759 int err;
1760 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001761
1762 BT_DBG("");
1763
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001764 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001765
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001766 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001767 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001768 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001769 goto unlock;
1770 }
1771
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001772 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001773 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1774 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001775 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001776 }
1777
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001778 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Andre Guedes92c4c202012-06-07 19:05:44 -03001779 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001780 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001781 err = -ENOMEM;
1782 goto unlock;
1783 }
1784
Johan Hedberg2784eb42011-01-21 13:56:35 +02001785 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001786 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001787 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1788 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001789 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001790 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001791 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001792 continue;
1793 i++;
1794 }
1795
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001796 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001797
Johan Hedberg4c659c32011-11-07 23:13:39 +02001798 /* Recalculate length in case of filtered SCO connections, etc */
1799 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001800
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001801 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001802 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001803
Johan Hedberga38528f2011-01-22 06:46:43 +02001804 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001805
1806unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001807 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001808 return err;
1809}
1810
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001811static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001812 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001813{
1814 struct pending_cmd *cmd;
1815 int err;
1816
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001817 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001818 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001819 if (!cmd)
1820 return -ENOMEM;
1821
Johan Hedbergd8457692012-02-17 14:24:57 +02001822 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001823 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001824 if (err < 0)
1825 mgmt_pending_remove(cmd);
1826
1827 return err;
1828}
1829
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001830static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001831 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001832{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001833 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001834 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001835 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001836 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001837 int err;
1838
1839 BT_DBG("");
1840
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001841 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001842
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001843 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001844 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001845 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001846 goto failed;
1847 }
1848
Johan Hedbergd8457692012-02-17 14:24:57 +02001849 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001850 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001851 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001852 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001853 goto failed;
1854 }
1855
1856 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001857 struct mgmt_cp_pin_code_neg_reply ncp;
1858
1859 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001860
1861 BT_ERR("PIN code is not 16 bytes long");
1862
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001863 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001864 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001865 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001866 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001867
1868 goto failed;
1869 }
1870
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001871 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001872 if (!cmd) {
1873 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001874 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001875 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001876
Johan Hedbergd8457692012-02-17 14:24:57 +02001877 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001878 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001879 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001880
1881 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1882 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001883 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001884
1885failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001886 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001887 return err;
1888}
1889
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001890static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1891 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001892{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001893 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001894
1895 BT_DBG("");
1896
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001897 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001898
1899 hdev->io_capability = cp->io_capability;
1900
1901 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001902 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001903
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001904 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001905
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001906 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1907 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001908}
1909
Gustavo Padovan6039aa732012-05-23 04:04:18 -03001910static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001911{
1912 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001913 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001914
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001915 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001916 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1917 continue;
1918
Johan Hedberge9a416b2011-02-19 12:05:56 -03001919 if (cmd->user_data != conn)
1920 continue;
1921
1922 return cmd;
1923 }
1924
1925 return NULL;
1926}
1927
1928static void pairing_complete(struct pending_cmd *cmd, u8 status)
1929{
1930 struct mgmt_rp_pair_device rp;
1931 struct hci_conn *conn = cmd->user_data;
1932
Johan Hedbergba4e5642011-11-11 00:07:34 +02001933 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001934 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001935
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001936 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001937 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001938
1939 /* So we don't get further callbacks for this connection */
1940 conn->connect_cfm_cb = NULL;
1941 conn->security_cfm_cb = NULL;
1942 conn->disconn_cfm_cb = NULL;
1943
1944 hci_conn_put(conn);
1945
Johan Hedberga664b5b2011-02-19 12:06:02 -03001946 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001947}
1948
1949static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1950{
1951 struct pending_cmd *cmd;
1952
1953 BT_DBG("status %u", status);
1954
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001955 cmd = find_pairing(conn);
1956 if (!cmd)
1957 BT_DBG("Unable to find a pending command");
1958 else
Johan Hedberge2113262012-02-18 15:20:03 +02001959 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001960}
1961
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301962static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
1963{
1964 struct pending_cmd *cmd;
1965
1966 BT_DBG("status %u", status);
1967
1968 if (!status)
1969 return;
1970
1971 cmd = find_pairing(conn);
1972 if (!cmd)
1973 BT_DBG("Unable to find a pending command");
1974 else
1975 pairing_complete(cmd, mgmt_status(status));
1976}
1977
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001978static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001979 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001980{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001981 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001982 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001983 struct pending_cmd *cmd;
1984 u8 sec_level, auth_type;
1985 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001986 int err;
1987
1988 BT_DBG("");
1989
Szymon Jancf950a30e2013-01-18 12:48:07 +01001990 memset(&rp, 0, sizeof(rp));
1991 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1992 rp.addr.type = cp->addr.type;
1993
Johan Hedberg4ee71b22013-01-20 14:27:19 +02001994 if (!bdaddr_type_is_valid(cp->addr.type))
1995 return cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
1996 MGMT_STATUS_INVALID_PARAMS,
1997 &rp, sizeof(rp));
1998
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001999 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002000
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002001 if (!hdev_is_powered(hdev)) {
Szymon Jancf950a30e2013-01-18 12:48:07 +01002002 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
2003 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002004 goto unlock;
2005 }
2006
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002007 sec_level = BT_SECURITY_MEDIUM;
2008 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03002009 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03002010 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03002011 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002012
Andre Guedes591f47f2012-04-24 21:02:49 -03002013 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03002014 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
2015 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002016 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03002017 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
2018 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002019
Ville Tervo30e76272011-02-22 16:10:53 -03002020 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002021 int status;
2022
2023 if (PTR_ERR(conn) == -EBUSY)
2024 status = MGMT_STATUS_BUSY;
2025 else
2026 status = MGMT_STATUS_CONNECT_FAILED;
2027
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002028 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02002029 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002030 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002031 goto unlock;
2032 }
2033
2034 if (conn->connect_cfm_cb) {
2035 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002036 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002037 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03002038 goto unlock;
2039 }
2040
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002041 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002042 if (!cmd) {
2043 err = -ENOMEM;
2044 hci_conn_put(conn);
2045 goto unlock;
2046 }
2047
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002048 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03002049 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002050 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05302051 else
2052 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03002053
Johan Hedberge9a416b2011-02-19 12:05:56 -03002054 conn->security_cfm_cb = pairing_complete_cb;
2055 conn->disconn_cfm_cb = pairing_complete_cb;
2056 conn->io_capability = cp->io_cap;
2057 cmd->user_data = conn;
2058
2059 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002060 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03002061 pairing_complete(cmd, 0);
2062
2063 err = 0;
2064
2065unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002066 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002067 return err;
2068}
2069
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002070static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
2071 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02002072{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002073 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02002074 struct pending_cmd *cmd;
2075 struct hci_conn *conn;
2076 int err;
2077
2078 BT_DBG("");
2079
Johan Hedberg28424702012-02-02 04:02:29 +02002080 hci_dev_lock(hdev);
2081
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002082 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002083 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002084 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002085 goto unlock;
2086 }
2087
Johan Hedberg28424702012-02-02 04:02:29 +02002088 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
2089 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002090 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002091 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002092 goto unlock;
2093 }
2094
2095 conn = cmd->user_data;
2096
2097 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002098 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002099 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002100 goto unlock;
2101 }
2102
2103 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2104
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002105 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002106 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002107unlock:
2108 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002109 return err;
2110}
2111
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002112static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002113 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2114 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002115{
Johan Hedberga5c29682011-02-19 12:05:57 -03002116 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002117 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002118 int err;
2119
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002120 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002121
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002122 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002123 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002124 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002125 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002126 }
2127
Andre Guedes591f47f2012-04-24 21:02:49 -03002128 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002129 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2130 else
Brian Gix47c15e22011-11-16 13:53:14 -08002131 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002132
Johan Hedberg272d90d2012-02-09 15:26:12 +02002133 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002134 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002135 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002136 goto done;
2137 }
2138
Andre Guedes591f47f2012-04-24 21:02:49 -03002139 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002140 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002141 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002142
Brian Gix5fe57d92011-12-21 16:12:13 -08002143 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002144 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002145 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002146 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002147 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002148 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002149
Brian Gix47c15e22011-11-16 13:53:14 -08002150 goto done;
2151 }
2152
Brian Gix0df4c182011-11-16 13:53:13 -08002153 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002154 if (!cmd) {
2155 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002156 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002157 }
2158
Brian Gix0df4c182011-11-16 13:53:13 -08002159 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002160 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2161 struct hci_cp_user_passkey_reply cp;
2162
2163 bacpy(&cp.bdaddr, bdaddr);
2164 cp.passkey = passkey;
2165 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2166 } else
2167 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2168
Johan Hedberga664b5b2011-02-19 12:06:02 -03002169 if (err < 0)
2170 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002171
Brian Gix0df4c182011-11-16 13:53:13 -08002172done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002173 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002174 return err;
2175}
2176
Jaganath Kanakkasseryafeb0192012-07-09 16:11:51 +05302177static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
2178 void *data, u16 len)
2179{
2180 struct mgmt_cp_pin_code_neg_reply *cp = data;
2181
2182 BT_DBG("");
2183
2184 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
2185 MGMT_OP_PIN_CODE_NEG_REPLY,
2186 HCI_OP_PIN_CODE_NEG_REPLY, 0);
2187}
2188
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002189static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2190 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002191{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002192 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002193
2194 BT_DBG("");
2195
2196 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002197 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002198 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002200 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002201 MGMT_OP_USER_CONFIRM_REPLY,
2202 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002203}
2204
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002205static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002206 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002207{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002208 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002209
2210 BT_DBG("");
2211
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002212 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002213 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2214 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002215}
2216
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002217static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2218 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002219{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002220 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002221
2222 BT_DBG("");
2223
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002224 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002225 MGMT_OP_USER_PASSKEY_REPLY,
2226 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002227}
2228
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002229static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002230 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002231{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002232 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002233
2234 BT_DBG("");
2235
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002236 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002237 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2238 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002239}
2240
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002241static int update_name(struct hci_dev *hdev, const char *name)
2242{
2243 struct hci_cp_write_local_name cp;
2244
2245 memcpy(cp.name, name, sizeof(cp.name));
2246
2247 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2248}
2249
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002250static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002251 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002252{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002253 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002254 struct pending_cmd *cmd;
2255 int err;
2256
2257 BT_DBG("");
2258
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002259 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002260
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002261 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002262
Johan Hedbergb5235a62012-02-21 14:32:24 +02002263 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002264 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002265
2266 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002267 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002268 if (err < 0)
2269 goto failed;
2270
2271 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002272 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002273
Johan Hedbergb5235a62012-02-21 14:32:24 +02002274 goto failed;
2275 }
2276
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002277 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002278 if (!cmd) {
2279 err = -ENOMEM;
2280 goto failed;
2281 }
2282
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002283 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002284 if (err < 0)
2285 mgmt_pending_remove(cmd);
2286
2287failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002288 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002289 return err;
2290}
2291
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002292static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002293 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002294{
Szymon Jancc35938b2011-03-22 13:12:21 +01002295 struct pending_cmd *cmd;
2296 int err;
2297
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002298 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002299
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002300 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002301
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002302 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002303 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002304 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002305 goto unlock;
2306 }
2307
Andre Guedes9a1a1992012-07-24 15:03:48 -03002308 if (!lmp_ssp_capable(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002309 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002310 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002311 goto unlock;
2312 }
2313
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002314 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002315 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002316 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002317 goto unlock;
2318 }
2319
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002320 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002321 if (!cmd) {
2322 err = -ENOMEM;
2323 goto unlock;
2324 }
2325
2326 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2327 if (err < 0)
2328 mgmt_pending_remove(cmd);
2329
2330unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002331 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002332 return err;
2333}
2334
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002335static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002336 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002337{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002338 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002339 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002340 int err;
2341
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002342 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002343
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002344 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002345
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002346 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002347 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002348 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002349 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002350 else
Szymon Janca6785be2012-12-13 15:11:21 +01002351 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002352
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002353 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002354 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002355
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002356 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002357 return err;
2358}
2359
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002360static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002361 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002362{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002363 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002364 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002365 int err;
2366
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002367 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002368
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002369 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002370
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002371 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002372 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002373 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002374 else
Szymon Janca6785be2012-12-13 15:11:21 +01002375 status = MGMT_STATUS_SUCCESS;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002376
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002377 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002378 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002379
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002380 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002381 return err;
2382}
2383
Andre Guedes5e0452c2012-02-17 20:39:38 -03002384int mgmt_interleaved_discovery(struct hci_dev *hdev)
2385{
2386 int err;
2387
2388 BT_DBG("%s", hdev->name);
2389
2390 hci_dev_lock(hdev);
2391
2392 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2393 if (err < 0)
2394 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2395
2396 hci_dev_unlock(hdev);
2397
2398 return err;
2399}
2400
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002401static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002402 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002403{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002404 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002405 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002406 int err;
2407
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002408 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002409
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002410 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002411
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002412 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002413 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002414 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002415 goto failed;
2416 }
2417
Andre Guedes642be6c2012-03-21 00:03:37 -03002418 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2419 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2420 MGMT_STATUS_BUSY);
2421 goto failed;
2422 }
2423
Johan Hedbergff9ef572012-01-04 14:23:45 +02002424 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002425 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002426 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002427 goto failed;
2428 }
2429
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002430 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002431 if (!cmd) {
2432 err = -ENOMEM;
2433 goto failed;
2434 }
2435
Andre Guedes4aab14e2012-02-17 20:39:36 -03002436 hdev->discovery.type = cp->type;
2437
2438 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002439 case DISCOV_TYPE_BREDR:
Johan Hedberg04106752013-01-10 14:54:09 +02002440 if (!lmp_bredr_capable(hdev)) {
2441 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2442 MGMT_STATUS_NOT_SUPPORTED);
2443 mgmt_pending_remove(cmd);
2444 goto failed;
2445 }
2446
2447 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002448 break;
2449
2450 case DISCOV_TYPE_LE:
Johan Hedberg04106752013-01-10 14:54:09 +02002451 if (!lmp_host_le_capable(hdev)) {
2452 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2453 MGMT_STATUS_NOT_SUPPORTED);
2454 mgmt_pending_remove(cmd);
2455 goto failed;
2456 }
2457
2458 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2459 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002460 break;
2461
Andre Guedes5e0452c2012-02-17 20:39:38 -03002462 case DISCOV_TYPE_INTERLEAVED:
Johan Hedberg04106752013-01-10 14:54:09 +02002463 if (!lmp_host_le_capable(hdev) || !lmp_bredr_capable(hdev)) {
2464 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2465 MGMT_STATUS_NOT_SUPPORTED);
2466 mgmt_pending_remove(cmd);
2467 goto failed;
2468 }
2469
2470 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT, LE_SCAN_WIN,
2471 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes5e0452c2012-02-17 20:39:38 -03002472 break;
2473
Andre Guedesf39799f2012-02-17 20:39:35 -03002474 default:
Johan Hedberg04106752013-01-10 14:54:09 +02002475 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2476 MGMT_STATUS_INVALID_PARAMS);
2477 mgmt_pending_remove(cmd);
2478 goto failed;
Andre Guedesf39799f2012-02-17 20:39:35 -03002479 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002480
Johan Hedberg14a53662011-04-27 10:29:56 -04002481 if (err < 0)
2482 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002483 else
2484 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002485
2486failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002487 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002488 return err;
2489}
2490
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002491static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002492 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002493{
Johan Hedbergd9306502012-02-20 23:25:18 +02002494 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002495 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002496 struct hci_cp_remote_name_req_cancel cp;
2497 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002498 int err;
2499
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002500 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002501
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002502 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002503
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002504 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002505 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2507 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002508 goto unlock;
2509 }
2510
2511 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002512 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002513 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2514 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002515 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002516 }
2517
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002518 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002519 if (!cmd) {
2520 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002521 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002522 }
2523
Andre Guedese0d9727e2012-03-20 15:15:36 -03002524 switch (hdev->discovery.state) {
2525 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002526 if (test_bit(HCI_INQUIRY, &hdev->flags))
2527 err = hci_cancel_inquiry(hdev);
2528 else
2529 err = hci_cancel_le_scan(hdev);
2530
Andre Guedese0d9727e2012-03-20 15:15:36 -03002531 break;
2532
2533 case DISCOVERY_RESOLVING:
2534 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002535 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002536 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002537 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002538 err = cmd_complete(sk, hdev->id,
2539 MGMT_OP_STOP_DISCOVERY, 0,
2540 &mgmt_cp->type,
2541 sizeof(mgmt_cp->type));
2542 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2543 goto unlock;
2544 }
2545
2546 bacpy(&cp.bdaddr, &e->data.bdaddr);
2547 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2548 sizeof(cp), &cp);
2549
2550 break;
2551
2552 default:
2553 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2554 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002555 }
2556
Johan Hedberg14a53662011-04-27 10:29:56 -04002557 if (err < 0)
2558 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002559 else
2560 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002561
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002562unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002563 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002564 return err;
2565}
2566
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002567static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002568 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002569{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002570 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002571 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002572 int err;
2573
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002574 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002575
Johan Hedberg561aafb2012-01-04 13:31:59 +02002576 hci_dev_lock(hdev);
2577
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002578 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002579 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002580 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002581 goto failed;
2582 }
2583
Johan Hedberga198e7b2012-02-17 14:27:06 +02002584 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002585 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002586 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002587 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002588 goto failed;
2589 }
2590
2591 if (cp->name_known) {
2592 e->name_state = NAME_KNOWN;
2593 list_del(&e->list);
2594 } else {
2595 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002596 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002597 }
2598
Johan Hedberge3846622013-01-09 15:29:33 +02002599 err = cmd_complete(sk, hdev->id, MGMT_OP_CONFIRM_NAME, 0, &cp->addr,
2600 sizeof(cp->addr));
Johan Hedberg561aafb2012-01-04 13:31:59 +02002601
2602failed:
2603 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002604 return err;
2605}
2606
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002607static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002608 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002609{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002610 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002611 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002612 int err;
2613
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002614 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002615
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002616 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002617 return cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE,
2618 MGMT_STATUS_INVALID_PARAMS,
2619 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002620
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002621 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002622
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002623 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002624 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002625 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002626 else
Szymon Janca6785be2012-12-13 15:11:21 +01002627 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002628
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002629 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002630 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002632 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002633
2634 return err;
2635}
2636
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002637static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002638 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002639{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002640 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002641 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002642 int err;
2643
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002644 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002645
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002646 if (!bdaddr_type_is_valid(cp->addr.type))
Johan Hedberg5d0846d2013-01-20 14:27:22 +02002647 return cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE,
2648 MGMT_STATUS_INVALID_PARAMS,
2649 &cp->addr, sizeof(cp->addr));
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002650
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002651 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002652
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002653 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002654 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002655 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002656 else
Szymon Janca6785be2012-12-13 15:11:21 +01002657 status = MGMT_STATUS_SUCCESS;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002658
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002659 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002660 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002661
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002662 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002663
2664 return err;
2665}
2666
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002667static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2668 u16 len)
2669{
2670 struct mgmt_cp_set_device_id *cp = data;
2671 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002672 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002673
2674 BT_DBG("%s", hdev->name);
2675
Szymon Jancc72d4b82012-03-16 16:02:57 +01002676 source = __le16_to_cpu(cp->source);
2677
2678 if (source > 0x0002)
2679 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2680 MGMT_STATUS_INVALID_PARAMS);
2681
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002682 hci_dev_lock(hdev);
2683
Szymon Jancc72d4b82012-03-16 16:02:57 +01002684 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002685 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2686 hdev->devid_product = __le16_to_cpu(cp->product);
2687 hdev->devid_version = __le16_to_cpu(cp->version);
2688
2689 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2690
2691 update_eir(hdev);
2692
2693 hci_dev_unlock(hdev);
2694
2695 return err;
2696}
2697
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002698static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002699 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002700{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002701 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002702 struct hci_cp_write_page_scan_activity acp;
2703 u8 type;
2704 int err;
2705
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002706 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002707
Johan Hedberg33c525c2012-10-24 21:11:58 +03002708 if (!lmp_bredr_capable(hdev))
2709 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2710 MGMT_STATUS_NOT_SUPPORTED);
2711
Johan Hedberga7e80f22013-01-09 16:05:19 +02002712 if (cp->val != 0x00 && cp->val != 0x01)
2713 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
2714 MGMT_STATUS_INVALID_PARAMS);
2715
Johan Hedberg5400c042012-02-21 16:40:33 +02002716 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002717 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002718 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002719
2720 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002721 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002722 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002723
2724 hci_dev_lock(hdev);
2725
Johan Hedbergf7c68692011-12-15 00:47:36 +02002726 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002727 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002728
Johan Hedberg83ce9a062012-06-28 13:44:30 +03002729 /* 160 msec page scan interval */
2730 acp.interval = __constant_cpu_to_le16(0x0100);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002731 } else {
2732 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002733
2734 /* default 1.28 sec page scan */
2735 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002736 }
2737
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002738 /* default 11.25 msec page scan window */
2739 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002740
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002741 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2742 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002743 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002744 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002745 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002746 goto done;
2747 }
2748
2749 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2750 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002751 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002752 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002753 goto done;
2754 }
2755
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002756 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002757 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002758done:
2759 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002760 return err;
2761}
2762
Johan Hedberg3f706b72013-01-20 14:27:16 +02002763static bool ltk_is_valid(struct mgmt_ltk_info *key)
2764{
Johan Hedberg44b20d32013-01-20 14:27:17 +02002765 if (key->authenticated != 0x00 && key->authenticated != 0x01)
2766 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02002767 if (key->master != 0x00 && key->master != 0x01)
2768 return false;
Johan Hedberg4ee71b22013-01-20 14:27:19 +02002769 if (!bdaddr_type_is_le(key->addr.type))
2770 return false;
Johan Hedberg3f706b72013-01-20 14:27:16 +02002771 return true;
2772}
2773
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002774static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002775 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002776{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002777 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2778 u16 key_count, expected_len;
Johan Hedberg715a5bf2013-01-09 15:29:34 +02002779 int i, err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002780
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002781 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002782
2783 expected_len = sizeof(*cp) + key_count *
2784 sizeof(struct mgmt_ltk_info);
2785 if (expected_len != len) {
2786 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002787 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002788 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Johan Hedberge57e6192013-01-20 14:27:14 +02002789 MGMT_STATUS_INVALID_PARAMS);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002790 }
2791
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002792 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002793
Johan Hedberg54ad6d82013-01-20 14:27:15 +02002794 for (i = 0; i < key_count; i++) {
2795 struct mgmt_ltk_info *key = &cp->keys[i];
2796
Johan Hedberg3f706b72013-01-20 14:27:16 +02002797 if (!ltk_is_valid(key))
Johan Hedberg54ad6d82013-01-20 14:27:15 +02002798 return cmd_status(sk, hdev->id,
2799 MGMT_OP_LOAD_LONG_TERM_KEYS,
2800 MGMT_STATUS_INVALID_PARAMS);
2801 }
2802
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002803 hci_dev_lock(hdev);
2804
2805 hci_smp_ltks_clear(hdev);
2806
2807 for (i = 0; i < key_count; i++) {
2808 struct mgmt_ltk_info *key = &cp->keys[i];
2809 u8 type;
2810
2811 if (key->master)
2812 type = HCI_SMP_LTK;
2813 else
2814 type = HCI_SMP_LTK_SLAVE;
2815
Hemant Gupta4596fde2012-04-16 14:57:40 +05302816 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03002817 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002818 type, 0, key->authenticated, key->val,
2819 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002820 }
2821
Johan Hedberg715a5bf2013-01-09 15:29:34 +02002822 err = cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS, 0,
2823 NULL, 0);
2824
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002825 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002826
Johan Hedberg715a5bf2013-01-09 15:29:34 +02002827 return err;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002828}
2829
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002830static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002831 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2832 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002833 bool var_len;
2834 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002835} mgmt_handlers[] = {
2836 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002837 { read_version, false, MGMT_READ_VERSION_SIZE },
2838 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2839 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2840 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2841 { set_powered, false, MGMT_SETTING_SIZE },
2842 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2843 { set_connectable, false, MGMT_SETTING_SIZE },
2844 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2845 { set_pairable, false, MGMT_SETTING_SIZE },
2846 { set_link_security, false, MGMT_SETTING_SIZE },
2847 { set_ssp, false, MGMT_SETTING_SIZE },
2848 { set_hs, false, MGMT_SETTING_SIZE },
2849 { set_le, false, MGMT_SETTING_SIZE },
2850 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2851 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2852 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2853 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2854 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2855 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2856 { disconnect, false, MGMT_DISCONNECT_SIZE },
2857 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2858 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2859 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2860 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2861 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2862 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2863 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2864 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2865 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2866 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2867 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2868 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2869 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2870 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2871 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2872 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2873 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2874 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2875 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002876 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002877};
2878
2879
Johan Hedberg03811012010-12-08 00:21:06 +02002880int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2881{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002882 void *buf;
2883 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002884 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002885 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002886 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002887 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002888 int err;
2889
2890 BT_DBG("got %zu bytes", msglen);
2891
2892 if (msglen < sizeof(*hdr))
2893 return -EINVAL;
2894
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002895 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002896 if (!buf)
2897 return -ENOMEM;
2898
2899 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2900 err = -EFAULT;
2901 goto done;
2902 }
2903
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002904 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002905 opcode = __le16_to_cpu(hdr->opcode);
2906 index = __le16_to_cpu(hdr->index);
2907 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002908
2909 if (len != msglen - sizeof(*hdr)) {
2910 err = -EINVAL;
2911 goto done;
2912 }
2913
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002914 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002915 hdev = hci_dev_get(index);
2916 if (!hdev) {
2917 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002918 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002919 goto done;
2920 }
2921 }
2922
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002923 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002924 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002925 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002926 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002927 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002928 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002929 }
2930
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002931 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002932 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002933 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002934 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002935 goto done;
2936 }
2937
Johan Hedbergbe22b542012-03-01 22:24:41 +02002938 handler = &mgmt_handlers[opcode];
2939
2940 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002941 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02002942 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002943 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002944 goto done;
2945 }
2946
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002947 if (hdev)
2948 mgmt_init_hdev(sk, hdev);
2949
2950 cp = buf + sizeof(*hdr);
2951
Johan Hedbergbe22b542012-03-01 22:24:41 +02002952 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002953 if (err < 0)
2954 goto done;
2955
Johan Hedberg03811012010-12-08 00:21:06 +02002956 err = msglen;
2957
2958done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002959 if (hdev)
2960 hci_dev_put(hdev);
2961
Johan Hedberg03811012010-12-08 00:21:06 +02002962 kfree(buf);
2963 return err;
2964}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002965
Johan Hedbergb24752f2011-11-03 14:40:33 +02002966static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2967{
2968 u8 *status = data;
2969
2970 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2971 mgmt_pending_remove(cmd);
2972}
2973
Johan Hedberg744cf192011-11-08 20:40:14 +02002974int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002975{
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03002976 if (!mgmt_valid_hdev(hdev))
2977 return -ENOTSUPP;
2978
Johan Hedberg744cf192011-11-08 20:40:14 +02002979 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002980}
2981
Johan Hedberg744cf192011-11-08 20:40:14 +02002982int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002983{
Johan Hedberg5f159032012-03-02 03:13:19 +02002984 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002985
Andrei Emeltchenkobb4b2a92012-07-19 17:03:40 +03002986 if (!mgmt_valid_hdev(hdev))
2987 return -ENOTSUPP;
2988
Johan Hedberg744cf192011-11-08 20:40:14 +02002989 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002990
Johan Hedberg744cf192011-11-08 20:40:14 +02002991 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002992}
2993
Johan Hedberg73f22f62010-12-29 16:00:25 +02002994struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002995 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002996 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002997 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002998};
2999
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003000static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003001{
Johan Hedberg73f22f62010-12-29 16:00:25 +02003002 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003003
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003004 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003005
3006 list_del(&cmd->list);
3007
3008 if (match->sk == NULL) {
3009 match->sk = cmd->sk;
3010 sock_hold(match->sk);
3011 }
3012
3013 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02003014}
Johan Hedberg5add6af2010-12-16 10:00:37 +02003015
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003016static int set_bredr_scan(struct hci_dev *hdev)
3017{
3018 u8 scan = 0;
3019
3020 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3021 scan |= SCAN_PAGE;
3022 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3023 scan |= SCAN_INQUIRY;
3024
3025 if (!scan)
3026 return 0;
3027
3028 return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
3029}
3030
Johan Hedberg744cf192011-11-08 20:40:14 +02003031int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02003032{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003033 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003034 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003035
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003036 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
3037 return 0;
3038
Johan Hedberg69ab39e2011-12-15 00:47:35 +02003039 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02003040
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003041 if (powered) {
Johan Hedberg6b4b73e2012-10-25 00:09:52 +03003042 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
3043 !lmp_host_ssp_capable(hdev)) {
Andrzej Kaczmarek3d1cbdd2012-08-29 10:02:08 +02003044 u8 ssp = 1;
3045
3046 hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
3047 }
3048
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02003049 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
3050 struct hci_cp_write_le_host_supported cp;
3051
3052 cp.le = 1;
Gustavo Padovanffa88e02012-11-23 16:50:51 -02003053 cp.simul = lmp_le_br_capable(hdev);
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02003054
Johan Hedberg430a61b2012-10-25 00:09:53 +03003055 /* Check first if we already have the right
3056 * host state (host features set)
3057 */
Gustavo Padovanffa88e02012-11-23 16:50:51 -02003058 if (cp.le != lmp_host_le_capable(hdev) ||
3059 cp.simul != lmp_host_le_br_capable(hdev))
Johan Hedberg430a61b2012-10-25 00:09:53 +03003060 hci_send_cmd(hdev,
3061 HCI_OP_WRITE_LE_HOST_SUPPORTED,
3062 sizeof(cp), &cp);
Andrzej Kaczmarek562fcc22012-08-29 10:02:09 +02003063 }
3064
Johan Hedberg7f0ae642012-10-24 21:11:57 +03003065 if (lmp_bredr_capable(hdev)) {
3066 set_bredr_scan(hdev);
3067 update_class(hdev);
3068 update_name(hdev, hdev->dev_name);
3069 update_eir(hdev);
3070 }
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003071 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02003072 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedbergfe038882013-01-16 16:15:34 +02003073 u8 zero_cod[] = { 0, 0, 0 };
3074
Johan Hedberg744cf192011-11-08 20:40:14 +02003075 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergfe038882013-01-16 16:15:34 +02003076
3077 if (memcmp(hdev->dev_class, zero_cod, sizeof(zero_cod)) != 0)
3078 mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev,
3079 zero_cod, sizeof(zero_cod), NULL);
Johan Hedbergb24752f2011-11-03 14:40:33 +02003080 }
3081
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003082 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02003083
3084 if (match.sk)
3085 sock_put(match.sk);
3086
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003087 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02003088}
Johan Hedberg73f22f62010-12-29 16:00:25 +02003089
Johan Hedberg744cf192011-11-08 20:40:14 +02003090int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02003091{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003092 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003093 bool changed = false;
3094 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003095
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003096 if (discoverable) {
3097 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3098 changed = true;
3099 } else {
3100 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
3101 changed = true;
3102 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02003103
Johan Hedberged9b5f22012-02-21 20:47:06 +02003104 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003105 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003106
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003107 if (changed)
3108 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003109
Johan Hedberg73f22f62010-12-29 16:00:25 +02003110 if (match.sk)
3111 sock_put(match.sk);
3112
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003113 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02003114}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003115
Johan Hedberg744cf192011-11-08 20:40:14 +02003116int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003117{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003118 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003119 bool changed = false;
3120 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003121
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003122 if (connectable) {
3123 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3124 changed = true;
3125 } else {
3126 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3127 changed = true;
3128 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003129
Johan Hedberged9b5f22012-02-21 20:47:06 +02003130 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003131 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02003132
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003133 if (changed)
3134 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003135
3136 if (match.sk)
3137 sock_put(match.sk);
3138
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003139 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02003140}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003141
Johan Hedberg744cf192011-11-08 20:40:14 +02003142int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003143{
Johan Hedbergca69b792011-11-11 18:10:00 +02003144 u8 mgmt_err = mgmt_status(status);
3145
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003146 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003147 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003148 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003149
3150 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003151 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003152 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003153
3154 return 0;
3155}
3156
Cristian Chilipirea53168e52012-05-09 08:44:52 +03003157int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3158 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003159{
Johan Hedberg86742e12011-11-07 23:13:38 +02003160 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003161
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003162 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003163
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003164 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003165 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003166 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003167 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03003168 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003169 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003170
Johan Hedberg744cf192011-11-08 20:40:14 +02003171 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02003172}
Johan Hedbergf7520542011-01-20 12:34:39 +02003173
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003174int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3175{
3176 struct mgmt_ev_new_long_term_key ev;
3177
3178 memset(&ev, 0, sizeof(ev));
3179
3180 ev.store_hint = persistent;
3181 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003182 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003183 ev.key.authenticated = key->authenticated;
3184 ev.key.enc_size = key->enc_size;
3185 ev.key.ediv = key->ediv;
3186
3187 if (key->type == HCI_SMP_LTK)
3188 ev.key.master = 1;
3189
3190 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3191 memcpy(ev.key.val, key->val, sizeof(key->val));
3192
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003193 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3194 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003195}
3196
Johan Hedbergafc747a2012-01-15 18:11:07 +02003197int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003198 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3199 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003200{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003201 char buf[512];
3202 struct mgmt_ev_device_connected *ev = (void *) buf;
3203 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003204
Johan Hedbergb644ba32012-01-17 21:48:47 +02003205 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003206 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003207
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003208 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003209
Johan Hedbergb644ba32012-01-17 21:48:47 +02003210 if (name_len > 0)
3211 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003212 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003213
3214 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003215 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003216 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003217
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003218 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003219
3220 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003221 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003222}
3223
Johan Hedberg8962ee72011-01-20 12:40:27 +02003224static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3225{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003226 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003227 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003228 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003229
Johan Hedberg88c3df12012-02-09 14:27:38 +02003230 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3231 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003232
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003233 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003234 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003235
3236 *sk = cmd->sk;
3237 sock_hold(*sk);
3238
Johan Hedberga664b5b2011-02-19 12:06:02 -03003239 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003240}
3241
Johan Hedberg124f6e32012-02-09 13:50:12 +02003242static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003243{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003244 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003245 struct mgmt_cp_unpair_device *cp = cmd->param;
3246 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003247
3248 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003249 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3250 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003251
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003252 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3253
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003254 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003255
3256 mgmt_pending_remove(cmd);
3257}
3258
Johan Hedbergafc747a2012-01-15 18:11:07 +02003259int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003260 u8 link_type, u8 addr_type, u8 reason)
Johan Hedbergf7520542011-01-20 12:34:39 +02003261{
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003262 struct mgmt_ev_device_disconnected ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003263 struct sock *sk = NULL;
3264 int err;
3265
Johan Hedberg744cf192011-11-08 20:40:14 +02003266 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003267
Mikel Astizf0d6a0e2012-08-09 09:52:30 +02003268 bacpy(&ev.addr.bdaddr, bdaddr);
3269 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3270 ev.reason = reason;
Johan Hedbergf7520542011-01-20 12:34:39 +02003271
Johan Hedbergafc747a2012-01-15 18:11:07 +02003272 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003273 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003274
3275 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003276 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003277
Johan Hedberg124f6e32012-02-09 13:50:12 +02003278 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003279 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003280
Johan Hedberg8962ee72011-01-20 12:40:27 +02003281 return err;
3282}
3283
Johan Hedberg88c3df12012-02-09 14:27:38 +02003284int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003285 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003286{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003287 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003288 struct pending_cmd *cmd;
3289 int err;
3290
Jefferson Delfes36a75f12012-09-18 13:36:54 -04003291 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3292 hdev);
3293
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003294 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003295 if (!cmd)
3296 return -ENOENT;
3297
Johan Hedberg88c3df12012-02-09 14:27:38 +02003298 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003299 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003300
Johan Hedberg88c3df12012-02-09 14:27:38 +02003301 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003302 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003303
Johan Hedberga664b5b2011-02-19 12:06:02 -03003304 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003305
3306 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003307}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003308
Johan Hedberg48264f02011-11-09 13:58:58 +02003309int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003310 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003311{
3312 struct mgmt_ev_connect_failed ev;
3313
Johan Hedberg4c659c32011-11-07 23:13:39 +02003314 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003315 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003316 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003317
Johan Hedberg744cf192011-11-08 20:40:14 +02003318 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003319}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003320
Johan Hedberg744cf192011-11-08 20:40:14 +02003321int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003322{
3323 struct mgmt_ev_pin_code_request ev;
3324
Johan Hedbergd8457692012-02-17 14:24:57 +02003325 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003326 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003327 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003328
Johan Hedberg744cf192011-11-08 20:40:14 +02003329 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003330 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003331}
3332
Johan Hedberg744cf192011-11-08 20:40:14 +02003333int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003334 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003335{
3336 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003337 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003338 int err;
3339
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003340 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003341 if (!cmd)
3342 return -ENOENT;
3343
Johan Hedbergd8457692012-02-17 14:24:57 +02003344 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003345 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003346
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003347 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003348 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003349
Johan Hedberga664b5b2011-02-19 12:06:02 -03003350 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003351
3352 return err;
3353}
3354
Johan Hedberg744cf192011-11-08 20:40:14 +02003355int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003356 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003357{
3358 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003359 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003360 int err;
3361
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003362 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003363 if (!cmd)
3364 return -ENOENT;
3365
Johan Hedbergd8457692012-02-17 14:24:57 +02003366 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003367 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003368
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003369 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003370 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003371
Johan Hedberga664b5b2011-02-19 12:06:02 -03003372 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003373
3374 return err;
3375}
Johan Hedberga5c29682011-02-19 12:05:57 -03003376
Johan Hedberg744cf192011-11-08 20:40:14 +02003377int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003378 u8 link_type, u8 addr_type, __le32 value,
3379 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003380{
3381 struct mgmt_ev_user_confirm_request ev;
3382
Johan Hedberg744cf192011-11-08 20:40:14 +02003383 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003384
Johan Hedberg272d90d2012-02-09 15:26:12 +02003385 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003386 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003387 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003388 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003389
Johan Hedberg744cf192011-11-08 20:40:14 +02003390 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003391 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003392}
3393
Johan Hedberg272d90d2012-02-09 15:26:12 +02003394int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003395 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003396{
3397 struct mgmt_ev_user_passkey_request ev;
3398
3399 BT_DBG("%s", hdev->name);
3400
Johan Hedberg272d90d2012-02-09 15:26:12 +02003401 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003402 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003403
3404 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003405 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003406}
3407
Brian Gix0df4c182011-11-16 13:53:13 -08003408static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003409 u8 link_type, u8 addr_type, u8 status,
3410 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003411{
3412 struct pending_cmd *cmd;
3413 struct mgmt_rp_user_confirm_reply rp;
3414 int err;
3415
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003416 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003417 if (!cmd)
3418 return -ENOENT;
3419
Johan Hedberg272d90d2012-02-09 15:26:12 +02003420 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003421 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003422 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003423 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003424
Johan Hedberga664b5b2011-02-19 12:06:02 -03003425 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003426
3427 return err;
3428}
3429
Johan Hedberg744cf192011-11-08 20:40:14 +02003430int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003431 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003432{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003433 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003434 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003435}
3436
Johan Hedberg272d90d2012-02-09 15:26:12 +02003437int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003438 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003439{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003440 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003441 status,
3442 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003443}
Johan Hedberg2a611692011-02-19 12:06:00 -03003444
Brian Gix604086b2011-11-23 08:28:33 -08003445int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003446 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003447{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003448 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003449 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003450}
3451
Johan Hedberg272d90d2012-02-09 15:26:12 +02003452int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003453 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003454{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003455 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003456 status,
3457 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003458}
3459
Johan Hedberg92a25252012-09-06 18:39:26 +03003460int mgmt_user_passkey_notify(struct hci_dev *hdev, bdaddr_t *bdaddr,
3461 u8 link_type, u8 addr_type, u32 passkey,
3462 u8 entered)
3463{
3464 struct mgmt_ev_passkey_notify ev;
3465
3466 BT_DBG("%s", hdev->name);
3467
3468 bacpy(&ev.addr.bdaddr, bdaddr);
3469 ev.addr.type = link_to_bdaddr(link_type, addr_type);
3470 ev.passkey = __cpu_to_le32(passkey);
3471 ev.entered = entered;
3472
3473 return mgmt_event(MGMT_EV_PASSKEY_NOTIFY, hdev, &ev, sizeof(ev), NULL);
3474}
3475
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003476int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003477 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003478{
3479 struct mgmt_ev_auth_failed ev;
3480
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003481 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003482 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003483 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003484
Johan Hedberg744cf192011-11-08 20:40:14 +02003485 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003486}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003487
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003488int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3489{
3490 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003491 bool changed = false;
3492 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003493
3494 if (status) {
3495 u8 mgmt_err = mgmt_status(status);
3496 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003497 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003498 return 0;
3499 }
3500
Johan Hedberg47990ea2012-02-22 11:58:37 +02003501 if (test_bit(HCI_AUTH, &hdev->flags)) {
3502 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3503 changed = true;
3504 } else {
3505 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3506 changed = true;
3507 }
3508
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003509 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003510 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003511
Johan Hedberg47990ea2012-02-22 11:58:37 +02003512 if (changed)
3513 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003514
3515 if (match.sk)
3516 sock_put(match.sk);
3517
3518 return err;
3519}
3520
Johan Hedbergcacaf522012-02-21 00:52:42 +02003521static int clear_eir(struct hci_dev *hdev)
3522{
3523 struct hci_cp_write_eir cp;
3524
Johan Hedberg976eb202012-10-24 21:12:01 +03003525 if (!lmp_ext_inq_capable(hdev))
Johan Hedbergcacaf522012-02-21 00:52:42 +02003526 return 0;
3527
Johan Hedbergc80da272012-02-22 15:38:48 +02003528 memset(hdev->eir, 0, sizeof(hdev->eir));
3529
Johan Hedbergcacaf522012-02-21 00:52:42 +02003530 memset(&cp, 0, sizeof(cp));
3531
3532 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3533}
3534
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003535int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003536{
3537 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003538 bool changed = false;
3539 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003540
3541 if (status) {
3542 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003543
3544 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003545 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003546 err = new_settings(hdev, NULL);
3547
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003548 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3549 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003550
3551 return err;
3552 }
3553
3554 if (enable) {
3555 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3556 changed = true;
3557 } else {
3558 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3559 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003560 }
3561
3562 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3563
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003564 if (changed)
3565 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003566
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003567 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003568 sock_put(match.sk);
3569
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003570 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3571 update_eir(hdev);
3572 else
3573 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003574
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003575 return err;
3576}
3577
Johan Hedberg90e70452012-02-23 23:09:40 +02003578static void class_rsp(struct pending_cmd *cmd, void *data)
3579{
3580 struct cmd_lookup *match = data;
3581
3582 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003583 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003584
3585 list_del(&cmd->list);
3586
3587 if (match->sk == NULL) {
3588 match->sk = cmd->sk;
3589 sock_hold(match->sk);
3590 }
3591
3592 mgmt_pending_free(cmd);
3593}
3594
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003595int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003596 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003597{
Johan Hedberg90e70452012-02-23 23:09:40 +02003598 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3599 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003600
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003601 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3602
Johan Hedberg90e70452012-02-23 23:09:40 +02003603 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3604 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3605 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3606
3607 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003608 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3609 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003610
3611 if (match.sk)
3612 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003613
3614 return err;
3615}
3616
Johan Hedberg744cf192011-11-08 20:40:14 +02003617int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003618{
3619 struct pending_cmd *cmd;
3620 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003621 bool changed = false;
3622 int err = 0;
3623
3624 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3625 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3626 changed = true;
3627 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003628
3629 memset(&ev, 0, sizeof(ev));
3630 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003631 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003632
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003633 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003634 if (!cmd)
3635 goto send_event;
3636
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003637 /* Always assume that either the short or the complete name has
3638 * changed if there was a pending mgmt command */
3639 changed = true;
3640
Johan Hedbergb312b1612011-03-16 14:29:37 +02003641 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003642 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003643 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003644 goto failed;
3645 }
3646
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003647 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003648 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003649 if (err < 0)
3650 goto failed;
3651
3652send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003653 if (changed)
3654 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003655 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003656
Johan Hedberg1225a6b2012-10-25 00:09:54 +03003657 /* EIR is taken care of separately when powering on the
3658 * adapter so only update them here if this is a name change
3659 * unrelated to power on.
3660 */
3661 if (!test_bit(HCI_INIT, &hdev->flags))
3662 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003663
3664failed:
3665 if (cmd)
3666 mgmt_pending_remove(cmd);
3667 return err;
3668}
Szymon Jancc35938b2011-03-22 13:12:21 +01003669
Johan Hedberg744cf192011-11-08 20:40:14 +02003670int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003671 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003672{
3673 struct pending_cmd *cmd;
3674 int err;
3675
Johan Hedberg744cf192011-11-08 20:40:14 +02003676 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003677
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003678 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003679 if (!cmd)
3680 return -ENOENT;
3681
3682 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003683 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3684 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003685 } else {
3686 struct mgmt_rp_read_local_oob_data rp;
3687
3688 memcpy(rp.hash, hash, sizeof(rp.hash));
3689 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3690
Johan Hedberg744cf192011-11-08 20:40:14 +02003691 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003692 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3693 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003694 }
3695
3696 mgmt_pending_remove(cmd);
3697
3698 return err;
3699}
Johan Hedberge17acd42011-03-30 23:57:16 +03003700
Johan Hedberg06199cf2012-02-22 16:37:11 +02003701int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3702{
3703 struct cmd_lookup match = { NULL, hdev };
3704 bool changed = false;
3705 int err = 0;
3706
3707 if (status) {
3708 u8 mgmt_err = mgmt_status(status);
3709
3710 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003711 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003712 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003713
Szymon Jancd97dcb62012-03-16 16:02:56 +01003714 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3715 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003716
3717 return err;
3718 }
3719
3720 if (enable) {
3721 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3722 changed = true;
3723 } else {
3724 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3725 changed = true;
3726 }
3727
3728 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3729
3730 if (changed)
3731 err = new_settings(hdev, match.sk);
3732
3733 if (match.sk)
3734 sock_put(match.sk);
3735
3736 return err;
3737}
3738
Johan Hedberg48264f02011-11-09 13:58:58 +02003739int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003740 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3741 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003742{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003743 char buf[512];
3744 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003745 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003746
Johan Hedberg1dc06092012-01-15 21:01:23 +02003747 /* Leave 5 bytes for a potential CoD field */
3748 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003749 return -EINVAL;
3750
Johan Hedberg1dc06092012-01-15 21:01:23 +02003751 memset(buf, 0, sizeof(buf));
3752
Johan Hedberge319d2e2012-01-15 19:51:59 +02003753 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003754 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003755 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003756 if (cfm_name)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05303757 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003758 if (!ssp)
Syam Sidhardhan612dfce2012-10-29 22:37:36 +05303759 ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03003760
Johan Hedberg1dc06092012-01-15 21:01:23 +02003761 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003762 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003763
Johan Hedberg1dc06092012-01-15 21:01:23 +02003764 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3765 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003766 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003767
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003768 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003769 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003770
Johan Hedberge319d2e2012-01-15 19:51:59 +02003771 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003772}
Johan Hedberga88a9652011-03-30 13:18:12 +03003773
Johan Hedbergb644ba32012-01-17 21:48:47 +02003774int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003775 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003776{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003777 struct mgmt_ev_device_found *ev;
3778 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3779 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003780
Johan Hedbergb644ba32012-01-17 21:48:47 +02003781 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003782
Johan Hedbergb644ba32012-01-17 21:48:47 +02003783 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003784
Johan Hedbergb644ba32012-01-17 21:48:47 +02003785 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003786 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003787 ev->rssi = rssi;
3788
3789 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003790 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003791
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003792 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003793
Johan Hedberg053c7e02012-02-04 00:06:00 +02003794 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003795 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003796}
Johan Hedberg314b2382011-04-27 10:29:57 -04003797
Andre Guedes7a135102011-11-09 17:14:25 -03003798int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003799{
3800 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003801 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003802 int err;
3803
Andre Guedes203159d2012-02-13 15:41:01 -03003804 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3805
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003806 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003807 if (!cmd)
3808 return -ENOENT;
3809
Johan Hedbergf808e162012-02-19 12:52:07 +02003810 type = hdev->discovery.type;
3811
3812 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003813 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003814 mgmt_pending_remove(cmd);
3815
3816 return err;
3817}
3818
Andre Guedese6d465c2011-11-09 17:14:26 -03003819int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3820{
3821 struct pending_cmd *cmd;
3822 int err;
3823
3824 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3825 if (!cmd)
3826 return -ENOENT;
3827
Johan Hedbergd9306502012-02-20 23:25:18 +02003828 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003829 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003830 mgmt_pending_remove(cmd);
3831
3832 return err;
3833}
Johan Hedberg314b2382011-04-27 10:29:57 -04003834
Johan Hedberg744cf192011-11-08 20:40:14 +02003835int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003836{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003837 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003838 struct pending_cmd *cmd;
3839
Andre Guedes343fb142011-11-22 17:14:19 -03003840 BT_DBG("%s discovering %u", hdev->name, discovering);
3841
Johan Hedberg164a6e72011-11-01 17:06:44 +02003842 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003843 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003844 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003845 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003846
3847 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003848 u8 type = hdev->discovery.type;
3849
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003850 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3851 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003852 mgmt_pending_remove(cmd);
3853 }
3854
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003855 memset(&ev, 0, sizeof(ev));
3856 ev.type = hdev->discovery.type;
3857 ev.discovering = discovering;
3858
3859 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003860}
Antti Julku5e762442011-08-25 16:48:02 +03003861
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003862int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003863{
3864 struct pending_cmd *cmd;
3865 struct mgmt_ev_device_blocked ev;
3866
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003867 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003868
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003869 bacpy(&ev.addr.bdaddr, bdaddr);
3870 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003871
Johan Hedberg744cf192011-11-08 20:40:14 +02003872 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003873 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003874}
3875
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003876int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003877{
3878 struct pending_cmd *cmd;
3879 struct mgmt_ev_device_unblocked ev;
3880
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003881 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003882
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003883 bacpy(&ev.addr.bdaddr, bdaddr);
3884 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003885
Johan Hedberg744cf192011-11-08 20:40:14 +02003886 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003887 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003888}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003889
3890module_param(enable_hs, bool, 0644);
3891MODULE_PARM_DESC(enable_hs, "Enable High Speed support");