blob: 6311be775ff291fdda715cc936c11ce2a4859d7d [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
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300267 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b212012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b212012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100395 if (!test_bit(HCI_UP, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200396 return settings;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200397
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100398 if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
399 settings |= MGMT_SETTING_POWERED;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_CONNECTABLE;
403
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200404 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_DISCOVERABLE;
406
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200407 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_PAIRABLE;
409
410 if (!(hdev->features[4] & LMP_NO_BREDR))
411 settings |= MGMT_SETTING_BREDR;
412
Andre Guedes59e29402011-12-30 10:34:03 -0300413 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200415
416 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200418
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200419 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200421
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200422 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
423 settings |= MGMT_SETTING_HS;
424
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200425 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200426}
427
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300428#define PNP_INFO_SVCLASS_ID 0x1200
429
430static u8 bluetooth_base_uuid[] = {
431 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
432 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
433};
434
435static u16 get_uuid16(u8 *uuid128)
436{
437 u32 val;
438 int i;
439
440 for (i = 0; i < 12; i++) {
441 if (bluetooth_base_uuid[i] != uuid128[i])
442 return 0;
443 }
444
445 memcpy(&val, &uuid128[12], 4);
446
447 val = le32_to_cpu(val);
448 if (val > 0xffff)
449 return 0;
450
451 return (u16) val;
452}
453
454static void create_eir(struct hci_dev *hdev, u8 *data)
455{
456 u8 *ptr = data;
457 u16 eir_len = 0;
458 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
459 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200460 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300461 size_t name_len;
462
463 name_len = strlen(hdev->dev_name);
464
465 if (name_len > 0) {
466 /* EIR Data type */
467 if (name_len > 48) {
468 name_len = 48;
469 ptr[1] = EIR_NAME_SHORT;
470 } else
471 ptr[1] = EIR_NAME_COMPLETE;
472
473 /* EIR Data length */
474 ptr[0] = name_len + 1;
475
476 memcpy(ptr + 2, hdev->dev_name, name_len);
477
478 eir_len += (name_len + 2);
479 ptr += (name_len + 2);
480 }
481
482 memset(uuid16_list, 0, sizeof(uuid16_list));
483
484 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200485 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300486 u16 uuid16;
487
488 uuid16 = get_uuid16(uuid->uuid);
489 if (uuid16 == 0)
490 return;
491
492 if (uuid16 < 0x1100)
493 continue;
494
495 if (uuid16 == PNP_INFO_SVCLASS_ID)
496 continue;
497
498 /* Stop if not enough space to put next UUID */
499 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
500 truncated = 1;
501 break;
502 }
503
504 /* Check for duplicates */
505 for (i = 0; uuid16_list[i] != 0; i++)
506 if (uuid16_list[i] == uuid16)
507 break;
508
509 if (uuid16_list[i] == 0) {
510 uuid16_list[i] = uuid16;
511 eir_len += sizeof(u16);
512 }
513 }
514
515 if (uuid16_list[0] != 0) {
516 u8 *length = ptr;
517
518 /* EIR Data type */
519 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
520
521 ptr += 2;
522 eir_len += 2;
523
524 for (i = 0; uuid16_list[i] != 0; i++) {
525 *ptr++ = (uuid16_list[i] & 0x00ff);
526 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
527 }
528
529 /* EIR Data length */
530 *length = (i * sizeof(u16)) + 1;
531 }
532}
533
534static int update_eir(struct hci_dev *hdev)
535{
536 struct hci_cp_write_eir cp;
537
538 if (!(hdev->features[6] & LMP_EXT_INQ))
539 return 0;
540
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200541 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200544 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300545 return 0;
546
547 memset(&cp, 0, sizeof(cp));
548
549 create_eir(hdev, cp.data);
550
551 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
552 return 0;
553
554 memcpy(hdev->eir, cp.data, sizeof(cp.data));
555
556 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
557}
558
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559static u8 get_service_classes(struct hci_dev *hdev)
560{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 u8 val = 0;
563
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300564 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200566
567 return val;
568}
569
570static int update_class(struct hci_dev *hdev)
571{
572 u8 cod[3];
573
574 BT_DBG("%s", hdev->name);
575
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200576 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200577 return 0;
578
579 cod[0] = hdev->minor_class;
580 cod[1] = hdev->major_class;
581 cod[2] = get_service_classes(hdev);
582
583 if (memcmp(cod, hdev->dev_class, 3) == 0)
584 return 0;
585
586 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
587}
588
Johan Hedberg7d785252011-12-15 00:47:39 +0200589static void service_cache_off(struct work_struct *work)
590{
591 struct hci_dev *hdev = container_of(work, struct hci_dev,
592 service_cache.work);
593
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200594 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200595 return;
596
597 hci_dev_lock(hdev);
598
599 update_eir(hdev);
600 update_class(hdev);
601
602 hci_dev_unlock(hdev);
603}
604
605static void mgmt_init_hdev(struct hci_dev *hdev)
606{
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200607 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200608 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
609
Johan Hedberg0cbf4ed2012-02-21 17:25:22 +0200610 /* Non-mgmt controlled devices get this bit set
611 * implicitly so that pairing works for them, however
612 * for mgmt we require user-space to explicitly enable
613 * it
614 */
615 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
616 }
617
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200618 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200619 schedule_delayed_work(&hdev->service_cache,
620 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
621}
622
Johan Hedberg03811012010-12-08 00:21:06 +0200623static int read_controller_info(struct sock *sk, u16 index)
624{
625 struct mgmt_rp_read_info rp;
626 struct hci_dev *hdev;
627
628 BT_DBG("sock %p hci%u", sk, index);
629
630 hdev = hci_dev_get(index);
631 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200632 return cmd_status(sk, index, MGMT_OP_READ_INFO,
633 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200634
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300635 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200636
Johan Hedberg7d785252011-12-15 00:47:39 +0200637 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
638 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200639
640 memset(&rp, 0, sizeof(rp));
641
Johan Hedberg03811012010-12-08 00:21:06 +0200642 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200643
644 rp.version = hdev->hci_ver;
645
Johan Hedberg03811012010-12-08 00:21:06 +0200646 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200647
648 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
649 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
650
651 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200652
653 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
654
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300655 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200656 hci_dev_put(hdev);
657
Johan Hedbergaee9b212012-02-18 15:07:59 +0200658 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200659}
660
661static void mgmt_pending_free(struct pending_cmd *cmd)
662{
663 sock_put(cmd->sk);
664 kfree(cmd->param);
665 kfree(cmd);
666}
667
668static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
669 struct hci_dev *hdev,
670 void *data, u16 len)
671{
672 struct pending_cmd *cmd;
673
674 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
675 if (!cmd)
676 return NULL;
677
678 cmd->opcode = opcode;
679 cmd->index = hdev->id;
680
681 cmd->param = kmalloc(len, GFP_ATOMIC);
682 if (!cmd->param) {
683 kfree(cmd);
684 return NULL;
685 }
686
687 if (data)
688 memcpy(cmd->param, data, len);
689
690 cmd->sk = sk;
691 sock_hold(sk);
692
693 list_add(&cmd->list, &hdev->mgmt_pending);
694
695 return cmd;
696}
697
698static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
699 void (*cb)(struct pending_cmd *cmd, void *data),
700 void *data)
701{
702 struct list_head *p, *n;
703
704 list_for_each_safe(p, n, &hdev->mgmt_pending) {
705 struct pending_cmd *cmd;
706
707 cmd = list_entry(p, struct pending_cmd, list);
708
709 if (opcode > 0 && cmd->opcode != opcode)
710 continue;
711
712 cb(cmd, data);
713 }
714}
715
716static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
717{
718 struct pending_cmd *cmd;
719
720 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
721 if (cmd->opcode == opcode)
722 return cmd;
723 }
724
725 return NULL;
726}
727
728static void mgmt_pending_remove(struct pending_cmd *cmd)
729{
730 list_del(&cmd->list);
731 mgmt_pending_free(cmd);
732}
733
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200734static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200735{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200736 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200737
Johan Hedbergaee9b212012-02-18 15:07:59 +0200738 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
739 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200740}
741
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300742static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200743{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300744 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200745 struct hci_dev *hdev;
746 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200747 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200748
Johan Hedberg03811012010-12-08 00:21:06 +0200749 BT_DBG("request for hci%u", index);
750
751 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200752 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
753 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200754
755 hdev = hci_dev_get(index);
756 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200757 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
758 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200759
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300760 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200761
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100762 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
763 cancel_delayed_work(&hdev->power_off);
764
765 if (cp->val) {
766 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
767 mgmt_powered(hdev, 1);
768 goto failed;
769 }
770 }
771
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200772 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200773 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200774 goto failed;
775 }
776
777 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200778 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
779 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200780 goto failed;
781 }
782
783 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
784 if (!cmd) {
785 err = -ENOMEM;
786 goto failed;
787 }
788
789 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200790 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200791 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200792 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200793
794 err = 0;
795
796failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300797 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200798 hci_dev_put(hdev);
799 return err;
800}
801
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300802static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200803{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300804 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200805 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200806 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200807 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200808 u8 scan;
809 int err;
810
Johan Hedberg03811012010-12-08 00:21:06 +0200811 BT_DBG("request for hci%u", index);
812
813 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200814 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
815 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200816
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200817 hdev = hci_dev_get(index);
818 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200819 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
820 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200821
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200822 timeout = get_unaligned_le16(&cp->timeout);
823
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300824 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200825
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200826 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200827 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
828 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200829 goto failed;
830 }
831
832 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
833 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200834 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
835 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200836 goto failed;
837 }
838
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200839 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
840 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
841 MGMT_STATUS_REJECTED);
842 goto failed;
843 }
844
845 if (!hdev_is_powered(hdev)) {
846 if (cp->val)
847 set_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
848 else
849 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
850 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
851 goto failed;
852 }
853
854 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200855 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200856 goto failed;
857 }
858
859 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
860 if (!cmd) {
861 err = -ENOMEM;
862 goto failed;
863 }
864
865 scan = SCAN_PAGE;
866
867 if (cp->val)
868 scan |= SCAN_INQUIRY;
869 else
870 cancel_delayed_work(&hdev->discov_off);
871
872 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
873 if (err < 0)
874 mgmt_pending_remove(cmd);
875
Johan Hedberg03811012010-12-08 00:21:06 +0200876 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200877 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200878
879failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300880 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200881 hci_dev_put(hdev);
882
883 return err;
884}
885
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300886static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200887{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300888 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200889 struct hci_dev *hdev;
890 struct pending_cmd *cmd;
891 u8 scan;
892 int err;
893
Johan Hedberge41d8b42010-12-13 21:07:03 +0200894 BT_DBG("request for hci%u", index);
895
Johan Hedberg03811012010-12-08 00:21:06 +0200896 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200897 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
898 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200899
900 hdev = hci_dev_get(index);
901 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200902 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
903 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200904
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300905 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200906
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200907 if (!hdev_is_powered(hdev)) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200908 if (cp->val)
909 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
910 else {
911 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
912 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
913 }
914 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200915 goto failed;
916 }
917
918 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
919 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200920 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
921 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200922 goto failed;
923 }
924
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200925 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200926 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200927 goto failed;
928 }
929
930 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
931 if (!cmd) {
932 err = -ENOMEM;
933 goto failed;
934 }
935
936 if (cp->val)
937 scan = SCAN_PAGE;
938 else
939 scan = 0;
940
941 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
942 if (err < 0)
943 mgmt_pending_remove(cmd);
944
945failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300946 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200947 hci_dev_put(hdev);
948
949 return err;
950}
951
952static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
953 u16 data_len, struct sock *skip_sk)
954{
955 struct sk_buff *skb;
956 struct mgmt_hdr *hdr;
957
958 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
959 if (!skb)
960 return -ENOMEM;
961
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200962 hdr = (void *) skb_put(skb, sizeof(*hdr));
963 hdr->opcode = cpu_to_le16(event);
964 if (hdev)
965 hdr->index = cpu_to_le16(hdev->id);
966 else
967 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
968 hdr->len = cpu_to_le16(data_len);
969
970 if (data)
971 memcpy(skb_put(skb, data_len), data, data_len);
972
Marcel Holtmann470fe1b2012-02-20 14:50:30 +0100973 hci_send_to_control(skb, skip_sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200974 kfree_skb(skb);
975
976 return 0;
977}
978
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300979static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200980{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300981 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200982 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200983 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200984 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200985
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200986 BT_DBG("request for hci%u", index);
987
988 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200989 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
990 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200991
992 hdev = hci_dev_get(index);
993 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200994 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
995 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200996
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300997 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200998
999 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001000 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001001 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001002 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001003
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001004 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001005 if (err < 0)
1006 goto failed;
1007
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001008 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001009
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001010 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001011
1012failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001013 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001014 hci_dev_put(hdev);
1015
1016 return err;
1017}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001018
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001019static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1020{
1021 struct mgmt_mode *cp = data;
1022 struct pending_cmd *cmd;
1023 struct hci_dev *hdev;
1024 uint8_t val;
1025 int err;
1026
1027 BT_DBG("request for hci%u", index);
1028
1029 if (len != sizeof(*cp))
1030 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1031 MGMT_STATUS_INVALID_PARAMS);
1032
1033 hdev = hci_dev_get(index);
1034 if (!hdev)
1035 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1036 MGMT_STATUS_INVALID_PARAMS);
1037
1038 hci_dev_lock(hdev);
1039
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001040 if (!hdev_is_powered(hdev)) {
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001041 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1042 MGMT_STATUS_NOT_POWERED);
1043 goto failed;
1044 }
1045
1046 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1047 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1048 MGMT_STATUS_BUSY);
1049 goto failed;
1050 }
1051
1052 val = !!cp->val;
1053
1054 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1055 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1056 goto failed;
1057 }
1058
1059 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1060 if (!cmd) {
1061 err = -ENOMEM;
1062 goto failed;
1063 }
1064
1065 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1066 if (err < 0) {
1067 mgmt_pending_remove(cmd);
1068 goto failed;
1069 }
1070
1071failed:
1072 hci_dev_unlock(hdev);
1073 hci_dev_put(hdev);
1074
1075 return err;
1076}
1077
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001078static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1079{
1080 struct mgmt_mode *cp = data;
1081 struct pending_cmd *cmd;
1082 struct hci_dev *hdev;
1083 uint8_t val;
1084 int err;
1085
1086 BT_DBG("request for hci%u", index);
1087
1088 if (len != sizeof(*cp))
1089 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1090 MGMT_STATUS_INVALID_PARAMS);
1091
1092 hdev = hci_dev_get(index);
1093 if (!hdev)
1094 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1095 MGMT_STATUS_INVALID_PARAMS);
1096
1097 hci_dev_lock(hdev);
1098
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001099 if (!hdev_is_powered(hdev)) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001100 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1101 MGMT_STATUS_NOT_POWERED);
1102 goto failed;
1103 }
1104
Johan Hedberg1e163572012-02-20 23:53:46 +02001105 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1106 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1107 MGMT_STATUS_NOT_SUPPORTED);
1108 goto failed;
1109 }
1110
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001111 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1112 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1113 goto failed;
1114 }
1115
1116 val = !!cp->val;
1117
1118 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1119 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1120 goto failed;
1121 }
1122
1123 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1124 if (!cmd) {
1125 err = -ENOMEM;
1126 goto failed;
1127 }
1128
1129 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1130 if (err < 0) {
1131 mgmt_pending_remove(cmd);
1132 goto failed;
1133 }
1134
1135failed:
1136 hci_dev_unlock(hdev);
1137 hci_dev_put(hdev);
1138
1139 return err;
1140}
1141
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001142static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1143{
1144 struct mgmt_mode *cp = data;
1145 struct hci_dev *hdev;
1146 int err;
1147
1148 BT_DBG("request for hci%u", index);
1149
1150 if (len != sizeof(*cp))
1151 return cmd_status(sk, index, MGMT_OP_SET_HS,
1152 MGMT_STATUS_INVALID_PARAMS);
1153
1154 hdev = hci_dev_get(index);
1155 if (!hdev)
1156 return cmd_status(sk, index, MGMT_OP_SET_HS,
1157 MGMT_STATUS_INVALID_PARAMS);
1158
1159 if (!enable_hs) {
1160 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1161 MGMT_STATUS_NOT_SUPPORTED);
1162 goto failed;
1163 }
1164
1165 if (cp->val)
1166 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1167 else
1168 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1169
1170 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1171
1172failed:
1173 hci_dev_put(hdev);
1174 return err;
1175}
1176
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001177static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001178{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001179 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001180 struct hci_dev *hdev;
1181 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001182 int err;
1183
Szymon Janc4e51eae2011-02-25 19:05:48 +01001184 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001185
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001186 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001187 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1188 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001189
Szymon Janc4e51eae2011-02-25 19:05:48 +01001190 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001191 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001192 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1193 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001194
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001195 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001196
1197 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1198 if (!uuid) {
1199 err = -ENOMEM;
1200 goto failed;
1201 }
1202
1203 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001204 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001205
1206 list_add(&uuid->list, &hdev->uuids);
1207
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001208 err = update_class(hdev);
1209 if (err < 0)
1210 goto failed;
1211
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001212 err = update_eir(hdev);
1213 if (err < 0)
1214 goto failed;
1215
Johan Hedbergaee9b212012-02-18 15:07:59 +02001216 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001217
1218failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001219 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001220 hci_dev_put(hdev);
1221
1222 return err;
1223}
1224
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001225static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001226{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001227 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001228 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001229 struct hci_dev *hdev;
1230 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 +02001231 int err, found;
1232
Szymon Janc4e51eae2011-02-25 19:05:48 +01001233 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001234
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001235 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001236 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1237 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001238
Szymon Janc4e51eae2011-02-25 19:05:48 +01001239 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001240 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001241 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1242 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001243
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001244 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001245
1246 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1247 err = hci_uuids_clear(hdev);
1248 goto unlock;
1249 }
1250
1251 found = 0;
1252
1253 list_for_each_safe(p, n, &hdev->uuids) {
1254 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1255
1256 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1257 continue;
1258
1259 list_del(&match->list);
1260 found++;
1261 }
1262
1263 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001264 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1265 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001266 goto unlock;
1267 }
1268
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001269 err = update_class(hdev);
1270 if (err < 0)
1271 goto unlock;
1272
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001273 err = update_eir(hdev);
1274 if (err < 0)
1275 goto unlock;
1276
Johan Hedbergaee9b212012-02-18 15:07:59 +02001277 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001278
1279unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001280 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001281 hci_dev_put(hdev);
1282
1283 return err;
1284}
1285
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001286static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001287{
1288 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001289 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001290 int err;
1291
Szymon Janc4e51eae2011-02-25 19:05:48 +01001292 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001293
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001294 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001295 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1296 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001297
Szymon Janc4e51eae2011-02-25 19:05:48 +01001298 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001299 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001300 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1301 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001302
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001303 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001304
Johan Hedbergb5235a62012-02-21 14:32:24 +02001305 if (!hdev_is_powered(hdev)) {
1306 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1307 MGMT_STATUS_NOT_POWERED);
1308 goto unlock;
1309 }
1310
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001311 hdev->major_class = cp->major;
1312 hdev->minor_class = cp->minor;
1313
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001314 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001315 hci_dev_unlock(hdev);
1316 cancel_delayed_work_sync(&hdev->service_cache);
1317 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001318 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001319 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001320
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001321 err = update_class(hdev);
1322
1323 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001324 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1325 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001326
Johan Hedbergb5235a62012-02-21 14:32:24 +02001327unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001328 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001329 hci_dev_put(hdev);
1330
1331 return err;
1332}
1333
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001334static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001335{
1336 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001337 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001338 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001339 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001340
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001341 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001342 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1343 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001344
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001345 key_count = get_unaligned_le16(&cp->key_count);
1346
Johan Hedberg86742e12011-11-07 23:13:38 +02001347 expected_len = sizeof(*cp) + key_count *
1348 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001349 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001350 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001351 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001352 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1353 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001354 }
1355
Szymon Janc4e51eae2011-02-25 19:05:48 +01001356 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001357 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001358 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1359 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001360
Szymon Janc4e51eae2011-02-25 19:05:48 +01001361 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001362 key_count);
1363
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001364 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001365
1366 hci_link_keys_clear(hdev);
1367
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001368 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001369
1370 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001371 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001372 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001373 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001374
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001375 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001376 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001377
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001378 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1379 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001380 }
1381
Johan Hedbergaee9b212012-02-18 15:07:59 +02001382 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001383
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001384 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001385 hci_dev_put(hdev);
1386
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001387 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001388}
1389
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001390static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1391 u8 addr_type, struct sock *skip_sk)
1392{
1393 struct mgmt_ev_device_unpaired ev;
1394
1395 bacpy(&ev.addr.bdaddr, bdaddr);
1396 ev.addr.type = addr_type;
1397
1398 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1399 skip_sk);
1400}
1401
Johan Hedberg124f6e32012-02-09 13:50:12 +02001402static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001403{
1404 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001405 struct mgmt_cp_unpair_device *cp = data;
1406 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001407 struct hci_cp_disconnect dc;
1408 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001409 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001410 u8 status = 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001411 int err;
1412
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001413 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001414 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001415 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001416
Szymon Janc4e51eae2011-02-25 19:05:48 +01001417 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001418 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001419 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001420 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001421
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001422 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001423
Johan Hedberga8a1d192011-11-10 15:54:38 +02001424 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001425 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1426 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001427
Johan Hedberg124f6e32012-02-09 13:50:12 +02001428 if (cp->addr.type == MGMT_ADDR_BREDR)
1429 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1430 else
1431 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001432
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001433 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001434 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001435 goto unlock;
1436 }
1437
Johan Hedberga8a1d192011-11-10 15:54:38 +02001438 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001439 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1440 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001441 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001442 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001443 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001444
Johan Hedberg124f6e32012-02-09 13:50:12 +02001445 if (cp->addr.type == MGMT_ADDR_BREDR)
1446 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1447 &cp->addr.bdaddr);
1448 else
1449 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1450 &cp->addr.bdaddr);
1451
Johan Hedberga8a1d192011-11-10 15:54:38 +02001452 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001453 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1454 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001455 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001456 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001457 }
1458
Johan Hedberg124f6e32012-02-09 13:50:12 +02001459 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1460 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001461 if (!cmd) {
1462 err = -ENOMEM;
1463 goto unlock;
1464 }
1465
1466 put_unaligned_le16(conn->handle, &dc.handle);
1467 dc.reason = 0x13; /* Remote User Terminated Connection */
1468 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1469 if (err < 0)
1470 mgmt_pending_remove(cmd);
1471
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001472unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001473 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001474 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1475 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001476 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001477 hci_dev_put(hdev);
1478
1479 return err;
1480}
1481
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001482static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001483{
1484 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001485 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001486 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001487 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001488 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001489 int err;
1490
1491 BT_DBG("");
1492
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001493 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001494 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1495 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001496
Szymon Janc4e51eae2011-02-25 19:05:48 +01001497 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001498 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001499 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1500 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001501
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001502 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001503
1504 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001505 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1506 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001507 goto failed;
1508 }
1509
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001510 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001511 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1512 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001513 goto failed;
1514 }
1515
Johan Hedberg88c3df12012-02-09 14:27:38 +02001516 if (cp->addr.type == MGMT_ADDR_BREDR)
1517 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1518 else
1519 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001520
Johan Hedberg8962ee72011-01-20 12:40:27 +02001521 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001522 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1523 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001524 goto failed;
1525 }
1526
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001527 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001528 if (!cmd) {
1529 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001530 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001531 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001532
1533 put_unaligned_le16(conn->handle, &dc.handle);
1534 dc.reason = 0x13; /* Remote User Terminated Connection */
1535
1536 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1537 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001538 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001539
1540failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001541 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001542 hci_dev_put(hdev);
1543
1544 return err;
1545}
1546
Johan Hedberg48264f02011-11-09 13:58:58 +02001547static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001548{
1549 switch (link_type) {
1550 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001551 switch (addr_type) {
1552 case ADDR_LE_DEV_PUBLIC:
1553 return MGMT_ADDR_LE_PUBLIC;
1554 case ADDR_LE_DEV_RANDOM:
1555 return MGMT_ADDR_LE_RANDOM;
1556 default:
1557 return MGMT_ADDR_INVALID;
1558 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001559 case ACL_LINK:
1560 return MGMT_ADDR_BREDR;
1561 default:
1562 return MGMT_ADDR_INVALID;
1563 }
1564}
1565
Szymon Janc8ce62842011-03-01 16:55:32 +01001566static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001567{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001568 struct mgmt_rp_get_connections *rp;
1569 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001570 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001571 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001572 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001573 int i, err;
1574
1575 BT_DBG("");
1576
Szymon Janc4e51eae2011-02-25 19:05:48 +01001577 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001578 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001579 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1580 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001581
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001582 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001583
1584 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001585 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1586 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1587 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001588 }
1589
Johan Hedberg4c659c32011-11-07 23:13:39 +02001590 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001591 rp = kmalloc(rp_len, GFP_ATOMIC);
1592 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001593 err = -ENOMEM;
1594 goto unlock;
1595 }
1596
Johan Hedberg2784eb42011-01-21 13:56:35 +02001597 put_unaligned_le16(count, &rp->conn_count);
1598
Johan Hedberg2784eb42011-01-21 13:56:35 +02001599 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001600 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001601 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1602 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001603 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001604 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001605 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1606 continue;
1607 i++;
1608 }
1609
1610 /* Recalculate length in case of filtered SCO connections, etc */
1611 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001612
Johan Hedbergaee9b212012-02-18 15:07:59 +02001613 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001614
1615unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001616 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001617 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001618 hci_dev_put(hdev);
1619 return err;
1620}
1621
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001622static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1623 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1624{
1625 struct pending_cmd *cmd;
1626 int err;
1627
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001628 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001629 sizeof(*cp));
1630 if (!cmd)
1631 return -ENOMEM;
1632
Johan Hedbergd8457692012-02-17 14:24:57 +02001633 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1634 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001635 if (err < 0)
1636 mgmt_pending_remove(cmd);
1637
1638 return err;
1639}
1640
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001641static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001642{
1643 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001644 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001645 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001646 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001647 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001648 int err;
1649
1650 BT_DBG("");
1651
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001652 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001653 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1654 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001655
Szymon Janc4e51eae2011-02-25 19:05:48 +01001656 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001657 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001658 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1659 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001660
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001661 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001662
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001663 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001664 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1665 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001666 goto failed;
1667 }
1668
Johan Hedbergd8457692012-02-17 14:24:57 +02001669 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001670 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001671 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1672 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001673 goto failed;
1674 }
1675
1676 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001677 struct mgmt_cp_pin_code_neg_reply ncp;
1678
1679 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001680
1681 BT_ERR("PIN code is not 16 bytes long");
1682
1683 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1684 if (err >= 0)
1685 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001686 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001687
1688 goto failed;
1689 }
1690
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001691 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1692 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001693 if (!cmd) {
1694 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001695 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001696 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001697
Johan Hedbergd8457692012-02-17 14:24:57 +02001698 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001699 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001700 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001701
1702 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1703 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001704 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001705
1706failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001707 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001708 hci_dev_put(hdev);
1709
1710 return err;
1711}
1712
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001713static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001714{
1715 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001716 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001717 int err;
1718
1719 BT_DBG("");
1720
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001721 if (len != sizeof(*cp))
1722 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001723 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001724
Szymon Janc4e51eae2011-02-25 19:05:48 +01001725 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001726 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001727 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001728 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001729
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001730 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001731
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001732 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001733 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001734 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001735 goto failed;
1736 }
1737
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001738 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001739
1740failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001741 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001742 hci_dev_put(hdev);
1743
1744 return err;
1745}
1746
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001747static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001748{
1749 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001750 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001751
1752 BT_DBG("");
1753
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001754 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001755 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1756 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001757
Szymon Janc4e51eae2011-02-25 19:05:48 +01001758 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001759 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001760 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1761 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001762
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001763 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001764
1765 hdev->io_capability = cp->io_capability;
1766
1767 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001768 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001769
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001770 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001771 hci_dev_put(hdev);
1772
Johan Hedbergaee9b212012-02-18 15:07:59 +02001773 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001774}
1775
Johan Hedberge9a416b2011-02-19 12:05:56 -03001776static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1777{
1778 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001779 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001780
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001781 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001782 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1783 continue;
1784
Johan Hedberge9a416b2011-02-19 12:05:56 -03001785 if (cmd->user_data != conn)
1786 continue;
1787
1788 return cmd;
1789 }
1790
1791 return NULL;
1792}
1793
1794static void pairing_complete(struct pending_cmd *cmd, u8 status)
1795{
1796 struct mgmt_rp_pair_device rp;
1797 struct hci_conn *conn = cmd->user_data;
1798
Johan Hedbergba4e5642011-11-11 00:07:34 +02001799 bacpy(&rp.addr.bdaddr, &conn->dst);
1800 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001801
Johan Hedbergaee9b212012-02-18 15:07:59 +02001802 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1803 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001804
1805 /* So we don't get further callbacks for this connection */
1806 conn->connect_cfm_cb = NULL;
1807 conn->security_cfm_cb = NULL;
1808 conn->disconn_cfm_cb = NULL;
1809
1810 hci_conn_put(conn);
1811
Johan Hedberga664b5b2011-02-19 12:06:02 -03001812 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001813}
1814
1815static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1816{
1817 struct pending_cmd *cmd;
1818
1819 BT_DBG("status %u", status);
1820
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001821 cmd = find_pairing(conn);
1822 if (!cmd)
1823 BT_DBG("Unable to find a pending command");
1824 else
Johan Hedberge2113262012-02-18 15:20:03 +02001825 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001826}
1827
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001828static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001829{
1830 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001831 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001832 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001833 struct pending_cmd *cmd;
1834 u8 sec_level, auth_type;
1835 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001836 int err;
1837
1838 BT_DBG("");
1839
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001840 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001841 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1842 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001843
Szymon Janc4e51eae2011-02-25 19:05:48 +01001844 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001845 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001846 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1847 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001848
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001849 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001850
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001851 sec_level = BT_SECURITY_MEDIUM;
1852 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001853 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001854 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001855 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001856
Johan Hedbergba4e5642011-11-11 00:07:34 +02001857 if (cp->addr.type == MGMT_ADDR_BREDR)
1858 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001859 auth_type);
1860 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001861 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001862 auth_type);
1863
Johan Hedberg1425acb2011-11-11 00:07:35 +02001864 memset(&rp, 0, sizeof(rp));
1865 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1866 rp.addr.type = cp->addr.type;
1867
Ville Tervo30e76272011-02-22 16:10:53 -03001868 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001869 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1870 MGMT_STATUS_CONNECT_FAILED,
1871 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001872 goto unlock;
1873 }
1874
1875 if (conn->connect_cfm_cb) {
1876 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001877 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1878 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001879 goto unlock;
1880 }
1881
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001882 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001883 if (!cmd) {
1884 err = -ENOMEM;
1885 hci_conn_put(conn);
1886 goto unlock;
1887 }
1888
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001889 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001890 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001891 conn->connect_cfm_cb = pairing_complete_cb;
1892
Johan Hedberge9a416b2011-02-19 12:05:56 -03001893 conn->security_cfm_cb = pairing_complete_cb;
1894 conn->disconn_cfm_cb = pairing_complete_cb;
1895 conn->io_capability = cp->io_cap;
1896 cmd->user_data = conn;
1897
1898 if (conn->state == BT_CONNECTED &&
1899 hci_conn_security(conn, sec_level, auth_type))
1900 pairing_complete(cmd, 0);
1901
1902 err = 0;
1903
1904unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001905 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001906 hci_dev_put(hdev);
1907
1908 return err;
1909}
1910
Johan Hedberg28424702012-02-02 04:02:29 +02001911static int cancel_pair_device(struct sock *sk, u16 index,
1912 unsigned char *data, u16 len)
1913{
1914 struct mgmt_addr_info *addr = (void *) data;
1915 struct hci_dev *hdev;
1916 struct pending_cmd *cmd;
1917 struct hci_conn *conn;
1918 int err;
1919
1920 BT_DBG("");
1921
1922 if (len != sizeof(*addr))
1923 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1924 MGMT_STATUS_INVALID_PARAMS);
1925
1926 hdev = hci_dev_get(index);
1927 if (!hdev)
1928 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1929 MGMT_STATUS_INVALID_PARAMS);
1930
1931 hci_dev_lock(hdev);
1932
1933 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1934 if (!cmd) {
1935 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1936 MGMT_STATUS_INVALID_PARAMS);
1937 goto unlock;
1938 }
1939
1940 conn = cmd->user_data;
1941
1942 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1943 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1944 MGMT_STATUS_INVALID_PARAMS);
1945 goto unlock;
1946 }
1947
1948 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1949
Johan Hedbergaee9b212012-02-18 15:07:59 +02001950 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001951 sizeof(*addr));
1952unlock:
1953 hci_dev_unlock(hdev);
1954 hci_dev_put(hdev);
1955
1956 return err;
1957}
1958
Brian Gix0df4c182011-11-16 13:53:13 -08001959static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001960 u8 type, u16 mgmt_op, u16 hci_op,
1961 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001962{
Johan Hedberga5c29682011-02-19 12:05:57 -03001963 struct pending_cmd *cmd;
1964 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001965 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001966 int err;
1967
Szymon Janc4e51eae2011-02-25 19:05:48 +01001968 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001969 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001970 return cmd_status(sk, index, mgmt_op,
1971 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001972
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001973 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001974
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001975 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001976 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1977 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001978 }
1979
Johan Hedberg272d90d2012-02-09 15:26:12 +02001980 if (type == MGMT_ADDR_BREDR)
1981 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1982 else
Brian Gix47c15e22011-11-16 13:53:14 -08001983 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001984
Johan Hedberg272d90d2012-02-09 15:26:12 +02001985 if (!conn) {
1986 err = cmd_status(sk, index, mgmt_op,
1987 MGMT_STATUS_NOT_CONNECTED);
1988 goto done;
1989 }
1990
1991 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001992 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001993 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001994
Brian Gix5fe57d92011-12-21 16:12:13 -08001995 if (!err)
1996 err = cmd_status(sk, index, mgmt_op,
1997 MGMT_STATUS_SUCCESS);
1998 else
1999 err = cmd_status(sk, index, mgmt_op,
2000 MGMT_STATUS_FAILED);
2001
Brian Gix47c15e22011-11-16 13:53:14 -08002002 goto done;
2003 }
2004
Brian Gix0df4c182011-11-16 13:53:13 -08002005 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002006 if (!cmd) {
2007 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002008 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002009 }
2010
Brian Gix0df4c182011-11-16 13:53:13 -08002011 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002012 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2013 struct hci_cp_user_passkey_reply cp;
2014
2015 bacpy(&cp.bdaddr, bdaddr);
2016 cp.passkey = passkey;
2017 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2018 } else
2019 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2020
Johan Hedberga664b5b2011-02-19 12:06:02 -03002021 if (err < 0)
2022 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002023
Brian Gix0df4c182011-11-16 13:53:13 -08002024done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002025 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002026 hci_dev_put(hdev);
2027
2028 return err;
2029}
2030
Brian Gix0df4c182011-11-16 13:53:13 -08002031static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2032{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002033 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002034
2035 BT_DBG("");
2036
2037 if (len != sizeof(*cp))
2038 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2039 MGMT_STATUS_INVALID_PARAMS);
2040
Johan Hedberg272d90d2012-02-09 15:26:12 +02002041 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2042 MGMT_OP_USER_CONFIRM_REPLY,
2043 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002044}
2045
2046static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2047 u16 len)
2048{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002049 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002050
2051 BT_DBG("");
2052
2053 if (len != sizeof(*cp))
2054 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2055 MGMT_STATUS_INVALID_PARAMS);
2056
Johan Hedberg272d90d2012-02-09 15:26:12 +02002057 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2058 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2059 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002060}
2061
Brian Gix604086b2011-11-23 08:28:33 -08002062static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2063{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002064 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002065
2066 BT_DBG("");
2067
2068 if (len != sizeof(*cp))
2069 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2070 EINVAL);
2071
Johan Hedberg272d90d2012-02-09 15:26:12 +02002072 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2073 MGMT_OP_USER_PASSKEY_REPLY,
2074 HCI_OP_USER_PASSKEY_REPLY,
2075 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002076}
2077
2078static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2079 u16 len)
2080{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002081 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002082
2083 BT_DBG("");
2084
2085 if (len != sizeof(*cp))
2086 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2087 EINVAL);
2088
Johan Hedberg272d90d2012-02-09 15:26:12 +02002089 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2090 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2091 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002092}
2093
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002094static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002095 u16 len)
2096{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002097 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002098 struct hci_cp_write_local_name hci_cp;
2099 struct hci_dev *hdev;
2100 struct pending_cmd *cmd;
2101 int err;
2102
2103 BT_DBG("");
2104
2105 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002106 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2107 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002108
2109 hdev = hci_dev_get(index);
2110 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002111 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2112 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002113
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002114 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002115
Johan Hedbergb5235a62012-02-21 14:32:24 +02002116 if (!hdev_is_powered(hdev)) {
2117 err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2118 MGMT_STATUS_NOT_POWERED);
2119 goto failed;
2120 }
2121
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002122 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2123 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002124 if (!cmd) {
2125 err = -ENOMEM;
2126 goto failed;
2127 }
2128
2129 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2130 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2131 &hci_cp);
2132 if (err < 0)
2133 mgmt_pending_remove(cmd);
2134
2135failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002136 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002137 hci_dev_put(hdev);
2138
2139 return err;
2140}
2141
Szymon Jancc35938b2011-03-22 13:12:21 +01002142static int read_local_oob_data(struct sock *sk, u16 index)
2143{
2144 struct hci_dev *hdev;
2145 struct pending_cmd *cmd;
2146 int err;
2147
2148 BT_DBG("hci%u", index);
2149
2150 hdev = hci_dev_get(index);
2151 if (!hdev)
2152 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002153 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002154
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002155 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002156
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002157 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002158 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002159 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002160 goto unlock;
2161 }
2162
2163 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2164 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002165 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002166 goto unlock;
2167 }
2168
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002169 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002170 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2171 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002172 goto unlock;
2173 }
2174
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002175 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002176 if (!cmd) {
2177 err = -ENOMEM;
2178 goto unlock;
2179 }
2180
2181 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2182 if (err < 0)
2183 mgmt_pending_remove(cmd);
2184
2185unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002186 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002187 hci_dev_put(hdev);
2188
2189 return err;
2190}
2191
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002192static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2193 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002194{
2195 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002196 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002197 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002198 int err;
2199
2200 BT_DBG("hci%u ", index);
2201
2202 if (len != sizeof(*cp))
2203 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002204 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002205
2206 hdev = hci_dev_get(index);
2207 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002208 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2209 MGMT_STATUS_INVALID_PARAMS,
2210 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002211
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002212 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002213
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002214 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002215 cp->randomizer);
2216 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002217 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002218 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002219 status = 0;
2220
2221 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2222 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002223
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002224 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002225 hci_dev_put(hdev);
2226
2227 return err;
2228}
2229
2230static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002231 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002232{
2233 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002234 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002235 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002236 int err;
2237
2238 BT_DBG("hci%u ", index);
2239
2240 if (len != sizeof(*cp))
2241 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002242 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002243
2244 hdev = hci_dev_get(index);
2245 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002246 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2247 MGMT_STATUS_INVALID_PARAMS,
2248 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002249
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002250 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002251
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002252 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002253 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002254 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002255 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002256 status = 0;
2257
2258 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2259 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002260
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002261 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002262 hci_dev_put(hdev);
2263
2264 return err;
2265}
2266
Andre Guedes5e0452c2012-02-17 20:39:38 -03002267static int discovery(struct hci_dev *hdev)
2268{
2269 int err;
2270
2271 if (lmp_host_le_capable(hdev)) {
2272 if (lmp_bredr_capable(hdev)) {
2273 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2274 LE_SCAN_INT, LE_SCAN_WIN,
2275 LE_SCAN_TIMEOUT_BREDR_LE);
2276 } else {
2277 hdev->discovery.type = DISCOV_TYPE_LE;
2278 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2279 LE_SCAN_INT, LE_SCAN_WIN,
2280 LE_SCAN_TIMEOUT_LE_ONLY);
2281 }
2282 } else {
2283 hdev->discovery.type = DISCOV_TYPE_BREDR;
2284 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2285 }
2286
2287 return err;
2288}
2289
2290int mgmt_interleaved_discovery(struct hci_dev *hdev)
2291{
2292 int err;
2293
2294 BT_DBG("%s", hdev->name);
2295
2296 hci_dev_lock(hdev);
2297
2298 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2299 if (err < 0)
2300 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2301
2302 hci_dev_unlock(hdev);
2303
2304 return err;
2305}
2306
Johan Hedberg450dfda2011-11-12 11:58:22 +02002307static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002308 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002309{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002310 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002311 struct pending_cmd *cmd;
2312 struct hci_dev *hdev;
2313 int err;
2314
2315 BT_DBG("hci%u", index);
2316
Johan Hedberg450dfda2011-11-12 11:58:22 +02002317 if (len != sizeof(*cp))
2318 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2319 MGMT_STATUS_INVALID_PARAMS);
2320
Johan Hedberg14a53662011-04-27 10:29:56 -04002321 hdev = hci_dev_get(index);
2322 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002323 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2324 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002325
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002326 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002327
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002328 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002329 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2330 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002331 goto failed;
2332 }
2333
Johan Hedbergff9ef572012-01-04 14:23:45 +02002334 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2335 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2336 MGMT_STATUS_BUSY);
2337 goto failed;
2338 }
2339
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002340 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002341 if (!cmd) {
2342 err = -ENOMEM;
2343 goto failed;
2344 }
2345
Andre Guedes4aab14e2012-02-17 20:39:36 -03002346 hdev->discovery.type = cp->type;
2347
2348 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002349 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002350 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002351 break;
2352
2353 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002354 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2355 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002356 break;
2357
Andre Guedes5e0452c2012-02-17 20:39:38 -03002358 case DISCOV_TYPE_INTERLEAVED:
2359 err = discovery(hdev);
2360 break;
2361
Andre Guedesf39799f2012-02-17 20:39:35 -03002362 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002363 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002364 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002365
Johan Hedberg14a53662011-04-27 10:29:56 -04002366 if (err < 0)
2367 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002368 else
2369 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002370
2371failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002372 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002373 hci_dev_put(hdev);
2374
2375 return err;
2376}
2377
Johan Hedbergd9306502012-02-20 23:25:18 +02002378static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002379{
Johan Hedbergd9306502012-02-20 23:25:18 +02002380 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002381 struct hci_dev *hdev;
2382 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002383 struct hci_cp_remote_name_req_cancel cp;
2384 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002385 int err;
2386
2387 BT_DBG("hci%u", index);
2388
Johan Hedbergd9306502012-02-20 23:25:18 +02002389 if (len != sizeof(*mgmt_cp))
2390 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2391 MGMT_STATUS_INVALID_PARAMS);
2392
Johan Hedberg14a53662011-04-27 10:29:56 -04002393 hdev = hci_dev_get(index);
2394 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002395 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2396 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002397
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002398 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002399
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002400 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002401 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2402 MGMT_STATUS_REJECTED,
2403 &mgmt_cp->type, sizeof(mgmt_cp->type));
2404 goto unlock;
2405 }
2406
2407 if (hdev->discovery.type != mgmt_cp->type) {
2408 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2409 MGMT_STATUS_INVALID_PARAMS,
2410 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002411 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002412 }
2413
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002414 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002415 if (!cmd) {
2416 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002417 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002418 }
2419
Andre Guedes343f9352012-02-17 20:39:37 -03002420 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002421 err = hci_cancel_inquiry(hdev);
2422 if (err < 0)
2423 mgmt_pending_remove(cmd);
2424 else
2425 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2426 goto unlock;
2427 }
2428
2429 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2430 if (!e) {
2431 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002432 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002433 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002434 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2435 goto unlock;
2436 }
2437
2438 bacpy(&cp.bdaddr, &e->data.bdaddr);
2439 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2440 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002441 if (err < 0)
2442 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002443 else
2444 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002445
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002446unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002447 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002448 hci_dev_put(hdev);
2449
2450 return err;
2451}
2452
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002453static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002454{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002455 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002456 struct inquiry_entry *e;
2457 struct hci_dev *hdev;
2458 int err;
2459
2460 BT_DBG("hci%u", index);
2461
2462 if (len != sizeof(*cp))
2463 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2464 MGMT_STATUS_INVALID_PARAMS);
2465
2466 hdev = hci_dev_get(index);
2467 if (!hdev)
2468 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2469 MGMT_STATUS_INVALID_PARAMS);
2470
2471 hci_dev_lock(hdev);
2472
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002473 if (!hci_discovery_active(hdev)) {
2474 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2475 MGMT_STATUS_FAILED);
2476 goto failed;
2477 }
2478
Johan Hedberga198e7b2012-02-17 14:27:06 +02002479 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002480 if (!e) {
2481 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2482 MGMT_STATUS_INVALID_PARAMS);
2483 goto failed;
2484 }
2485
2486 if (cp->name_known) {
2487 e->name_state = NAME_KNOWN;
2488 list_del(&e->list);
2489 } else {
2490 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002491 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002492 }
2493
2494 err = 0;
2495
2496failed:
2497 hci_dev_unlock(hdev);
2498
2499 return err;
2500}
2501
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002502static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002503{
2504 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002505 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002506 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002507 int err;
2508
2509 BT_DBG("hci%u", index);
2510
Antti Julku7fbec222011-06-15 12:01:15 +03002511 if (len != sizeof(*cp))
2512 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002513 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002514
2515 hdev = hci_dev_get(index);
2516 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002517 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2518 MGMT_STATUS_INVALID_PARAMS,
2519 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002520
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002521 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002522
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002523 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002524 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002525 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002526 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002527 status = 0;
2528
2529 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2530 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002531
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002532 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002533 hci_dev_put(hdev);
2534
2535 return err;
2536}
2537
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002538static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002539{
2540 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002541 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002542 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002543 int err;
2544
2545 BT_DBG("hci%u", index);
2546
Antti Julku7fbec222011-06-15 12:01:15 +03002547 if (len != sizeof(*cp))
2548 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002549 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002550
2551 hdev = hci_dev_get(index);
2552 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002553 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2554 MGMT_STATUS_INVALID_PARAMS,
2555 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002556
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002557 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002558
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002559 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002560 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002561 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002562 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002563 status = 0;
2564
2565 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2566 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002567
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002568 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002569 hci_dev_put(hdev);
2570
2571 return err;
2572}
2573
Antti Julkuf6422ec2011-06-22 13:11:56 +03002574static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002575 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002576{
2577 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002578 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002579 struct hci_cp_write_page_scan_activity acp;
2580 u8 type;
2581 int err;
2582
2583 BT_DBG("hci%u", index);
2584
2585 if (len != sizeof(*cp))
2586 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002587 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002588
2589 hdev = hci_dev_get(index);
2590 if (!hdev)
2591 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002592 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002593 if (!hdev_is_powered(hdev))
2594 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2595 MGMT_STATUS_NOT_POWERED);
2596
2597 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2598 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2599 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002600
2601 hci_dev_lock(hdev);
2602
Johan Hedbergf7c68692011-12-15 00:47:36 +02002603 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002604 type = PAGE_SCAN_TYPE_INTERLACED;
2605 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2606 } else {
2607 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2608 acp.interval = 0x0800; /* default 1.28 sec page scan */
2609 }
2610
2611 acp.window = 0x0012; /* default 11.25 msec page scan window */
2612
2613 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2614 sizeof(acp), &acp);
2615 if (err < 0) {
2616 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002617 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002618 goto done;
2619 }
2620
2621 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2622 if (err < 0) {
2623 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002624 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002625 goto done;
2626 }
2627
Johan Hedbergaee9b212012-02-18 15:07:59 +02002628 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2629 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002630done:
2631 hci_dev_unlock(hdev);
2632 hci_dev_put(hdev);
2633
2634 return err;
2635}
2636
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002637static int load_long_term_keys(struct sock *sk, u16 index,
2638 void *cp_data, u16 len)
2639{
2640 struct hci_dev *hdev;
2641 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2642 u16 key_count, expected_len;
2643 int i;
2644
2645 if (len < sizeof(*cp))
2646 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2647 EINVAL);
2648
2649 key_count = get_unaligned_le16(&cp->key_count);
2650
2651 expected_len = sizeof(*cp) + key_count *
2652 sizeof(struct mgmt_ltk_info);
2653 if (expected_len != len) {
2654 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2655 len, expected_len);
2656 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2657 EINVAL);
2658 }
2659
2660 hdev = hci_dev_get(index);
2661 if (!hdev)
2662 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2663 ENODEV);
2664
2665 BT_DBG("hci%u key_count %u", index, key_count);
2666
2667 hci_dev_lock(hdev);
2668
2669 hci_smp_ltks_clear(hdev);
2670
2671 for (i = 0; i < key_count; i++) {
2672 struct mgmt_ltk_info *key = &cp->keys[i];
2673 u8 type;
2674
2675 if (key->master)
2676 type = HCI_SMP_LTK;
2677 else
2678 type = HCI_SMP_LTK_SLAVE;
2679
2680 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2681 type, 0, key->authenticated, key->val,
2682 key->enc_size, key->ediv, key->rand);
2683 }
2684
2685 hci_dev_unlock(hdev);
2686 hci_dev_put(hdev);
2687
2688 return 0;
2689}
2690
Johan Hedberg03811012010-12-08 00:21:06 +02002691int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2692{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002693 void *buf;
2694 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002695 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002696 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002697 int err;
2698
2699 BT_DBG("got %zu bytes", msglen);
2700
2701 if (msglen < sizeof(*hdr))
2702 return -EINVAL;
2703
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002704 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002705 if (!buf)
2706 return -ENOMEM;
2707
2708 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2709 err = -EFAULT;
2710 goto done;
2711 }
2712
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002713 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002714 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002715 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002716 len = get_unaligned_le16(&hdr->len);
2717
2718 if (len != msglen - sizeof(*hdr)) {
2719 err = -EINVAL;
2720 goto done;
2721 }
2722
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002723 cp = buf + sizeof(*hdr);
2724
Johan Hedberg03811012010-12-08 00:21:06 +02002725 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002726 case MGMT_OP_READ_VERSION:
2727 err = read_version(sk);
2728 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002729 case MGMT_OP_READ_COMMANDS:
2730 err = read_commands(sk);
2731 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002732 case MGMT_OP_READ_INDEX_LIST:
2733 err = read_index_list(sk);
2734 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002735 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002736 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002737 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002738 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002739 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002740 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002741 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002742 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002743 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002744 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002745 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002746 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002747 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002748 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002749 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002750 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002751 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002752 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002753 case MGMT_OP_SET_LINK_SECURITY:
2754 err = set_link_security(sk, index, cp, len);
2755 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002756 case MGMT_OP_SET_SSP:
2757 err = set_ssp(sk, index, cp, len);
2758 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002759 case MGMT_OP_SET_HS:
2760 err = set_hs(sk, index, cp, len);
2761 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002762 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002763 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002764 break;
2765 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002766 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002767 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002768 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002769 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002770 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002771 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002772 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002773 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002774 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002775 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002776 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002777 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002778 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002779 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002780 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002781 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002782 break;
2783 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002784 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002785 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002786 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002787 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002788 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002789 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002790 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002791 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002792 case MGMT_OP_CANCEL_PAIR_DEVICE:
2793 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2794 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002795 case MGMT_OP_UNPAIR_DEVICE:
2796 err = unpair_device(sk, index, cp, len);
2797 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002798 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002799 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002800 break;
2801 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002802 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002803 break;
Brian Gix604086b2011-11-23 08:28:33 -08002804 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002805 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002806 break;
2807 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002808 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002809 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002810 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002811 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002812 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002813 case MGMT_OP_READ_LOCAL_OOB_DATA:
2814 err = read_local_oob_data(sk, index);
2815 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002816 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002817 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002818 break;
2819 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002820 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002821 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002822 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002823 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002824 break;
2825 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002826 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002827 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002828 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002829 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002830 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002831 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002832 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002833 break;
2834 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002835 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002836 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002837 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2838 err = load_long_term_keys(sk, index, cp, len);
2839 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002840 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002841 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002842 err = cmd_status(sk, index, opcode,
2843 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002844 break;
2845 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002846
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002847 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002848 goto done;
2849
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002850 err = msglen;
2851
2852done:
2853 kfree(buf);
2854 return err;
2855}
2856
Johan Hedbergb24752f2011-11-03 14:40:33 +02002857static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2858{
2859 u8 *status = data;
2860
2861 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2862 mgmt_pending_remove(cmd);
2863}
2864
Johan Hedberg744cf192011-11-08 20:40:14 +02002865int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002866{
Johan Hedberg744cf192011-11-08 20:40:14 +02002867 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002868}
2869
Johan Hedberg744cf192011-11-08 20:40:14 +02002870int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002871{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002872 u8 status = ENODEV;
2873
Johan Hedberg744cf192011-11-08 20:40:14 +02002874 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002875
Johan Hedberg744cf192011-11-08 20:40:14 +02002876 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002877}
2878
2879struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002880 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002881 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002882};
2883
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002884static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002885{
Johan Hedberg03811012010-12-08 00:21:06 +02002886 struct cmd_lookup *match = data;
2887
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002888 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002889
2890 list_del(&cmd->list);
2891
2892 if (match->sk == NULL) {
2893 match->sk = cmd->sk;
2894 sock_hold(match->sk);
2895 }
2896
2897 mgmt_pending_free(cmd);
2898}
2899
Johan Hedberg744cf192011-11-08 20:40:14 +02002900int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002901{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002902 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002903 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002904 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002905
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002906 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2907 return 0;
2908
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002909 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002910
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002911 if (powered) {
2912 u8 scan = 0;
2913
2914 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2915 scan |= SCAN_PAGE;
2916 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2917 scan |= SCAN_INQUIRY;
2918
2919 if (scan)
2920 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2921 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02002922 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002923 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002924 }
2925
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002926 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002927
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002928 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002929 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002930
2931 if (match.sk)
2932 sock_put(match.sk);
2933
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002934 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002935}
2936
Johan Hedberg744cf192011-11-08 20:40:14 +02002937int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002938{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002939 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002940 bool changed = false;
2941 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002942
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002943 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002944
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002945 if (discoverable) {
2946 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2947 changed = true;
2948 } else {
2949 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2950 changed = true;
2951 }
Johan Hedberg03811012010-12-08 00:21:06 +02002952
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002953 if (changed) {
2954 __le32 ev = cpu_to_le32(get_current_settings(hdev));
2955 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002956 match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002957 }
2958
Johan Hedberg03811012010-12-08 00:21:06 +02002959 if (match.sk)
2960 sock_put(match.sk);
2961
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002962 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002963}
2964
Johan Hedberg744cf192011-11-08 20:40:14 +02002965int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002966{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002967 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002968 bool changed = false;
2969 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002970
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002971 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2972 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002973
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002974 if (connectable) {
2975 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2976 changed = true;
2977 } else {
2978 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2979 changed = true;
2980 }
Johan Hedberg03811012010-12-08 00:21:06 +02002981
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002982 if (changed) {
2983 __le32 ev = cpu_to_le32(get_current_settings(hdev));
2984 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2985 match.sk);
2986 }
Johan Hedberg03811012010-12-08 00:21:06 +02002987
2988 if (match.sk)
2989 sock_put(match.sk);
2990
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002991 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002992}
2993
Johan Hedberg744cf192011-11-08 20:40:14 +02002994int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002995{
Johan Hedbergca69b792011-11-11 18:10:00 +02002996 u8 mgmt_err = mgmt_status(status);
2997
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002998 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002999 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003000 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003001
3002 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003003 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003004 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003005
3006 return 0;
3007}
3008
Johan Hedberg744cf192011-11-08 20:40:14 +02003009int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3010 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003011{
Johan Hedberg86742e12011-11-07 23:13:38 +02003012 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003013
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003014 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003015
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003016 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003017 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3018 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003019 ev.key.type = key->type;
3020 memcpy(ev.key.val, key->val, 16);
3021 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003022
Johan Hedberg744cf192011-11-08 20:40:14 +02003023 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003024}
Johan Hedbergf7520542011-01-20 12:34:39 +02003025
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003026int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3027{
3028 struct mgmt_ev_new_long_term_key ev;
3029
3030 memset(&ev, 0, sizeof(ev));
3031
3032 ev.store_hint = persistent;
3033 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3034 ev.key.addr.type = key->bdaddr_type;
3035 ev.key.authenticated = key->authenticated;
3036 ev.key.enc_size = key->enc_size;
3037 ev.key.ediv = key->ediv;
3038
3039 if (key->type == HCI_SMP_LTK)
3040 ev.key.master = 1;
3041
3042 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3043 memcpy(ev.key.val, key->val, sizeof(key->val));
3044
3045 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3046 &ev, sizeof(ev), NULL);
3047}
3048
Johan Hedbergafc747a2012-01-15 18:11:07 +02003049int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003050 u8 addr_type, u8 *name, u8 name_len,
3051 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003052{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003053 char buf[512];
3054 struct mgmt_ev_device_connected *ev = (void *) buf;
3055 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003056
Johan Hedbergb644ba32012-01-17 21:48:47 +02003057 bacpy(&ev->addr.bdaddr, bdaddr);
3058 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003059
Johan Hedbergb644ba32012-01-17 21:48:47 +02003060 if (name_len > 0)
3061 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3062 name, name_len);
3063
3064 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3065 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3066 EIR_CLASS_OF_DEV, dev_class, 3);
3067
3068 put_unaligned_le16(eir_len, &ev->eir_len);
3069
3070 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3071 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003072}
3073
Johan Hedberg8962ee72011-01-20 12:40:27 +02003074static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3075{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003076 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003077 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003078 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003079
Johan Hedberg88c3df12012-02-09 14:27:38 +02003080 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3081 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003082
Johan Hedbergaee9b212012-02-18 15:07:59 +02003083 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3084 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003085
3086 *sk = cmd->sk;
3087 sock_hold(*sk);
3088
Johan Hedberga664b5b2011-02-19 12:06:02 -03003089 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003090}
3091
Johan Hedberg124f6e32012-02-09 13:50:12 +02003092static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003093{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003094 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003095 struct mgmt_cp_unpair_device *cp = cmd->param;
3096 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003097
3098 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003099 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3100 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003101
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003102 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3103
Johan Hedbergaee9b212012-02-18 15:07:59 +02003104 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003105
3106 mgmt_pending_remove(cmd);
3107}
3108
Johan Hedbergafc747a2012-01-15 18:11:07 +02003109int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3110 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003111{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003112 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003113 struct sock *sk = NULL;
3114 int err;
3115
Johan Hedberg744cf192011-11-08 20:40:14 +02003116 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003117
Johan Hedbergf7520542011-01-20 12:34:39 +02003118 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003119 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003120
Johan Hedbergafc747a2012-01-15 18:11:07 +02003121 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3122 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003123
3124 if (sk)
3125 sock_put(sk);
3126
Johan Hedberg124f6e32012-02-09 13:50:12 +02003127 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003128 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003129
Johan Hedberg8962ee72011-01-20 12:40:27 +02003130 return err;
3131}
3132
Johan Hedberg88c3df12012-02-09 14:27:38 +02003133int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3134 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003135{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003136 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003137 struct pending_cmd *cmd;
3138 int err;
3139
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003140 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003141 if (!cmd)
3142 return -ENOENT;
3143
Johan Hedberg88c3df12012-02-09 14:27:38 +02003144 bacpy(&rp.addr.bdaddr, bdaddr);
3145 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003146
Johan Hedberg88c3df12012-02-09 14:27:38 +02003147 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003148 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003149
Johan Hedberga664b5b2011-02-19 12:06:02 -03003150 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003151
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003152 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3153 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003154 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003155}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003156
Johan Hedberg48264f02011-11-09 13:58:58 +02003157int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3158 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003159{
3160 struct mgmt_ev_connect_failed ev;
3161
Johan Hedberg4c659c32011-11-07 23:13:39 +02003162 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003163 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003164 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003165
Johan Hedberg744cf192011-11-08 20:40:14 +02003166 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003167}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003168
Johan Hedberg744cf192011-11-08 20:40:14 +02003169int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003170{
3171 struct mgmt_ev_pin_code_request ev;
3172
Johan Hedbergd8457692012-02-17 14:24:57 +02003173 bacpy(&ev.addr.bdaddr, bdaddr);
3174 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003175 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003176
Johan Hedberg744cf192011-11-08 20:40:14 +02003177 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003178 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003179}
3180
Johan Hedberg744cf192011-11-08 20:40:14 +02003181int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3182 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003183{
3184 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003185 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003186 int err;
3187
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003188 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003189 if (!cmd)
3190 return -ENOENT;
3191
Johan Hedbergd8457692012-02-17 14:24:57 +02003192 bacpy(&rp.addr.bdaddr, bdaddr);
3193 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003194
Johan Hedbergaee9b212012-02-18 15:07:59 +02003195 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3196 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003197
Johan Hedberga664b5b2011-02-19 12:06:02 -03003198 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003199
3200 return err;
3201}
3202
Johan Hedberg744cf192011-11-08 20:40:14 +02003203int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3204 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003205{
3206 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003207 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003208 int err;
3209
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003210 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003211 if (!cmd)
3212 return -ENOENT;
3213
Johan Hedbergd8457692012-02-17 14:24:57 +02003214 bacpy(&rp.addr.bdaddr, bdaddr);
3215 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003216
Johan Hedbergaee9b212012-02-18 15:07:59 +02003217 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3218 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003219
Johan Hedberga664b5b2011-02-19 12:06:02 -03003220 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003221
3222 return err;
3223}
Johan Hedberga5c29682011-02-19 12:05:57 -03003224
Johan Hedberg744cf192011-11-08 20:40:14 +02003225int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003226 u8 link_type, u8 addr_type, __le32 value,
3227 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003228{
3229 struct mgmt_ev_user_confirm_request ev;
3230
Johan Hedberg744cf192011-11-08 20:40:14 +02003231 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003232
Johan Hedberg272d90d2012-02-09 15:26:12 +02003233 bacpy(&ev.addr.bdaddr, bdaddr);
3234 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003235 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003236 put_unaligned_le32(value, &ev.value);
3237
Johan Hedberg744cf192011-11-08 20:40:14 +02003238 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003239 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003240}
3241
Johan Hedberg272d90d2012-02-09 15:26:12 +02003242int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3243 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003244{
3245 struct mgmt_ev_user_passkey_request ev;
3246
3247 BT_DBG("%s", hdev->name);
3248
Johan Hedberg272d90d2012-02-09 15:26:12 +02003249 bacpy(&ev.addr.bdaddr, bdaddr);
3250 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003251
3252 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3253 NULL);
3254}
3255
Brian Gix0df4c182011-11-16 13:53:13 -08003256static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003257 u8 link_type, u8 addr_type, u8 status,
3258 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003259{
3260 struct pending_cmd *cmd;
3261 struct mgmt_rp_user_confirm_reply rp;
3262 int err;
3263
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003264 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003265 if (!cmd)
3266 return -ENOENT;
3267
Johan Hedberg272d90d2012-02-09 15:26:12 +02003268 bacpy(&rp.addr.bdaddr, bdaddr);
3269 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003270 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3271 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003272
Johan Hedberga664b5b2011-02-19 12:06:02 -03003273 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003274
3275 return err;
3276}
3277
Johan Hedberg744cf192011-11-08 20:40:14 +02003278int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003279 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003280{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003281 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3282 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003283}
3284
Johan Hedberg272d90d2012-02-09 15:26:12 +02003285int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3286 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003287{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003288 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3289 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003290}
Johan Hedberg2a611692011-02-19 12:06:00 -03003291
Brian Gix604086b2011-11-23 08:28:33 -08003292int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003293 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003294{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003295 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3296 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003297}
3298
Johan Hedberg272d90d2012-02-09 15:26:12 +02003299int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3300 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003301{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003302 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3303 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003304}
3305
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003306int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3307 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003308{
3309 struct mgmt_ev_auth_failed ev;
3310
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003311 bacpy(&ev.addr.bdaddr, bdaddr);
3312 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003313 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003314
Johan Hedberg744cf192011-11-08 20:40:14 +02003315 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003316}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003317
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003318int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3319{
3320 struct cmd_lookup match = { NULL, hdev };
3321 __le32 ev;
3322 int err;
3323
3324 if (status) {
3325 u8 mgmt_err = mgmt_status(status);
3326 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3327 cmd_status_rsp, &mgmt_err);
3328 return 0;
3329 }
3330
3331 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3332 &match);
3333
3334 ev = cpu_to_le32(get_current_settings(hdev));
3335 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3336
3337 if (match.sk)
3338 sock_put(match.sk);
3339
3340 return err;
3341}
3342
Johan Hedbergcacaf522012-02-21 00:52:42 +02003343static int clear_eir(struct hci_dev *hdev)
3344{
3345 struct hci_cp_write_eir cp;
3346
3347 if (!(hdev->features[6] & LMP_EXT_INQ))
3348 return 0;
3349
3350 memset(&cp, 0, sizeof(cp));
3351
3352 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3353}
3354
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003355int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3356{
3357 struct cmd_lookup match = { NULL, hdev };
3358 __le32 ev;
3359 int err;
3360
3361 if (status) {
3362 u8 mgmt_err = mgmt_status(status);
3363 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3364 cmd_status_rsp, &mgmt_err);
3365 return 0;
3366 }
3367
3368 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3369
3370 ev = cpu_to_le32(get_current_settings(hdev));
3371 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3372
Johan Hedbergcacaf522012-02-21 00:52:42 +02003373 if (match.sk) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003374 sock_put(match.sk);
3375
Johan Hedbergcacaf522012-02-21 00:52:42 +02003376 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3377 update_eir(hdev);
3378 else
3379 clear_eir(hdev);
3380 }
3381
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003382 return err;
3383}
3384
Johan Hedberg744cf192011-11-08 20:40:14 +02003385int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003386{
3387 struct pending_cmd *cmd;
3388 struct mgmt_cp_set_local_name ev;
3389 int err;
3390
3391 memset(&ev, 0, sizeof(ev));
3392 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3393
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003394 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003395 if (!cmd)
3396 goto send_event;
3397
3398 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003399 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003400 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003401 goto failed;
3402 }
3403
Johan Hedberg744cf192011-11-08 20:40:14 +02003404 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003405
Johan Hedbergaee9b212012-02-18 15:07:59 +02003406 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003407 sizeof(ev));
3408 if (err < 0)
3409 goto failed;
3410
3411send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003412 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003413 cmd ? cmd->sk : NULL);
3414
3415failed:
3416 if (cmd)
3417 mgmt_pending_remove(cmd);
3418 return err;
3419}
Szymon Jancc35938b2011-03-22 13:12:21 +01003420
Johan Hedberg744cf192011-11-08 20:40:14 +02003421int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3422 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003423{
3424 struct pending_cmd *cmd;
3425 int err;
3426
Johan Hedberg744cf192011-11-08 20:40:14 +02003427 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003428
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003429 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003430 if (!cmd)
3431 return -ENOENT;
3432
3433 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003434 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003435 MGMT_OP_READ_LOCAL_OOB_DATA,
3436 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003437 } else {
3438 struct mgmt_rp_read_local_oob_data rp;
3439
3440 memcpy(rp.hash, hash, sizeof(rp.hash));
3441 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3442
Johan Hedberg744cf192011-11-08 20:40:14 +02003443 err = cmd_complete(cmd->sk, hdev->id,
3444 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003445 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003446 }
3447
3448 mgmt_pending_remove(cmd);
3449
3450 return err;
3451}
Johan Hedberge17acd42011-03-30 23:57:16 +03003452
Johan Hedberg48264f02011-11-09 13:58:58 +02003453int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003454 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003455 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003456{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003457 char buf[512];
3458 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003459 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003460
Johan Hedberg1dc06092012-01-15 21:01:23 +02003461 /* Leave 5 bytes for a potential CoD field */
3462 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003463 return -EINVAL;
3464
Johan Hedberg1dc06092012-01-15 21:01:23 +02003465 memset(buf, 0, sizeof(buf));
3466
Johan Hedberge319d2e2012-01-15 19:51:59 +02003467 bacpy(&ev->addr.bdaddr, bdaddr);
3468 ev->addr.type = link_to_mgmt(link_type, addr_type);
3469 ev->rssi = rssi;
3470 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003471
Johan Hedberg1dc06092012-01-15 21:01:23 +02003472 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003473 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003474
Johan Hedberg1dc06092012-01-15 21:01:23 +02003475 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3476 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3477 dev_class, 3);
3478
3479 put_unaligned_le16(eir_len, &ev->eir_len);
3480
3481 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003482
Johan Hedberge319d2e2012-01-15 19:51:59 +02003483 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003484}
Johan Hedberga88a9652011-03-30 13:18:12 +03003485
Johan Hedbergb644ba32012-01-17 21:48:47 +02003486int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3487 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003488{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003489 struct mgmt_ev_device_found *ev;
3490 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3491 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003492
Johan Hedbergb644ba32012-01-17 21:48:47 +02003493 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003494
Johan Hedbergb644ba32012-01-17 21:48:47 +02003495 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003496
Johan Hedbergb644ba32012-01-17 21:48:47 +02003497 bacpy(&ev->addr.bdaddr, bdaddr);
3498 ev->addr.type = link_to_mgmt(link_type, addr_type);
3499 ev->rssi = rssi;
3500
3501 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3502 name_len);
3503
3504 put_unaligned_le16(eir_len, &ev->eir_len);
3505
Johan Hedberg053c7e02012-02-04 00:06:00 +02003506 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3507 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003508}
Johan Hedberg314b2382011-04-27 10:29:57 -04003509
Andre Guedes7a135102011-11-09 17:14:25 -03003510int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003511{
3512 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003513 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003514 int err;
3515
Andre Guedes203159d2012-02-13 15:41:01 -03003516 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3517
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003518 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003519 if (!cmd)
3520 return -ENOENT;
3521
Johan Hedbergf808e162012-02-19 12:52:07 +02003522 type = hdev->discovery.type;
3523
3524 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3525 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003526 mgmt_pending_remove(cmd);
3527
3528 return err;
3529}
3530
Andre Guedese6d465c2011-11-09 17:14:26 -03003531int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3532{
3533 struct pending_cmd *cmd;
3534 int err;
3535
3536 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3537 if (!cmd)
3538 return -ENOENT;
3539
Johan Hedbergd9306502012-02-20 23:25:18 +02003540 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3541 &hdev->discovery.type,
3542 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003543 mgmt_pending_remove(cmd);
3544
3545 return err;
3546}
Johan Hedberg314b2382011-04-27 10:29:57 -04003547
Johan Hedberg744cf192011-11-08 20:40:14 +02003548int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003549{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003550 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003551 struct pending_cmd *cmd;
3552
Andre Guedes343fb142011-11-22 17:14:19 -03003553 BT_DBG("%s discovering %u", hdev->name, discovering);
3554
Johan Hedberg164a6e72011-11-01 17:06:44 +02003555 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003556 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003557 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003558 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003559
3560 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003561 u8 type = hdev->discovery.type;
3562
Johan Hedbergd9306502012-02-20 23:25:18 +02003563 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003564 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003565 mgmt_pending_remove(cmd);
3566 }
3567
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003568 memset(&ev, 0, sizeof(ev));
3569 ev.type = hdev->discovery.type;
3570 ev.discovering = discovering;
3571
3572 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003573}
Antti Julku5e762442011-08-25 16:48:02 +03003574
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003575int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003576{
3577 struct pending_cmd *cmd;
3578 struct mgmt_ev_device_blocked ev;
3579
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003580 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003581
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003582 bacpy(&ev.addr.bdaddr, bdaddr);
3583 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003584
Johan Hedberg744cf192011-11-08 20:40:14 +02003585 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3586 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003587}
3588
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003589int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003590{
3591 struct pending_cmd *cmd;
3592 struct mgmt_ev_device_unblocked ev;
3593
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003594 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003595
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003596 bacpy(&ev.addr.bdaddr, bdaddr);
3597 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003598
Johan Hedberg744cf192011-11-08 20:40:14 +02003599 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3600 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003601}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003602
3603module_param(enable_hs, bool, 0644);
3604MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3605
3606module_param(enable_le, bool, 0644);
3607MODULE_PARM_DESC(enable_le, "Enable Low Energy support");