blob: edf84c3e6a2bcb9e1815356e45ebc184b61ae4ad [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 Hedbergeec8d2b2010-12-16 10:17:38 +0200121struct pending_cmd {
122 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200123 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100125 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200126 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300127 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200128};
129
Johan Hedbergca69b792011-11-11 18:10:00 +0200130/* HCI to MGMT error code conversion table */
131static u8 mgmt_status_table[] = {
132 MGMT_STATUS_SUCCESS,
133 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
134 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
135 MGMT_STATUS_FAILED, /* Hardware Failure */
136 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
137 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
138 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
139 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
140 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
141 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
142 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
143 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
144 MGMT_STATUS_BUSY, /* Command Disallowed */
145 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
146 MGMT_STATUS_REJECTED, /* Rejected Security */
147 MGMT_STATUS_REJECTED, /* Rejected Personal */
148 MGMT_STATUS_TIMEOUT, /* Host Timeout */
149 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
150 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
151 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
152 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
153 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
154 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
155 MGMT_STATUS_BUSY, /* Repeated Attempts */
156 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
157 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
158 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
159 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
160 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
161 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
162 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
163 MGMT_STATUS_FAILED, /* Unspecified Error */
164 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
165 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
166 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
167 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
168 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
169 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
170 MGMT_STATUS_FAILED, /* Unit Link Key Used */
171 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
172 MGMT_STATUS_TIMEOUT, /* Instant Passed */
173 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
174 MGMT_STATUS_FAILED, /* Transaction Collision */
175 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
176 MGMT_STATUS_REJECTED, /* QoS Rejected */
177 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
178 MGMT_STATUS_REJECTED, /* Insufficient Security */
179 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
180 MGMT_STATUS_BUSY, /* Role Switch Pending */
181 MGMT_STATUS_FAILED, /* Slot Violation */
182 MGMT_STATUS_FAILED, /* Role Switch Failed */
183 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
184 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
185 MGMT_STATUS_BUSY, /* Host Busy Pairing */
186 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
187 MGMT_STATUS_BUSY, /* Controller Busy */
188 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
189 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
190 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
191 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
192 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
193};
194
195static u8 mgmt_status(u8 hci_status)
196{
197 if (hci_status < ARRAY_SIZE(mgmt_status_table))
198 return mgmt_status_table[hci_status];
199
200 return MGMT_STATUS_FAILED;
201}
202
Szymon Janc4e51eae2011-02-25 19:05:48 +0100203static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200204{
205 struct sk_buff *skb;
206 struct mgmt_hdr *hdr;
207 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300208 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200209
Szymon Janc34eb5252011-02-28 14:10:08 +0100210 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200211
212 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
213 if (!skb)
214 return -ENOMEM;
215
216 hdr = (void *) skb_put(skb, sizeof(*hdr));
217
218 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100219 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200220 hdr->len = cpu_to_le16(sizeof(*ev));
221
222 ev = (void *) skb_put(skb, sizeof(*ev));
223 ev->status = status;
224 put_unaligned_le16(cmd, &ev->opcode);
225
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300226 err = sock_queue_rcv_skb(sk, skb);
227 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200228 kfree_skb(skb);
229
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300230 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200231}
232
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200233static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
234 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200235{
236 struct sk_buff *skb;
237 struct mgmt_hdr *hdr;
238 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300239 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200240
241 BT_DBG("sock %p", sk);
242
Johan Hedberga38528f2011-01-22 06:46:43 +0200243 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200244 if (!skb)
245 return -ENOMEM;
246
247 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200248
Johan Hedberg02d98122010-12-13 21:07:04 +0200249 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100250 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200251 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200252
Johan Hedberga38528f2011-01-22 06:46:43 +0200253 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
254 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200255 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100256
257 if (rp)
258 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200259
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300260 err = sock_queue_rcv_skb(sk, skb);
261 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200262 kfree_skb(skb);
263
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300264 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200265}
266
Johan Hedberga38528f2011-01-22 06:46:43 +0200267static int read_version(struct sock *sk)
268{
269 struct mgmt_rp_read_version rp;
270
271 BT_DBG("sock %p", sk);
272
273 rp.version = MGMT_VERSION;
274 put_unaligned_le16(MGMT_REVISION, &rp.revision);
275
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200276 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100277 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200278}
279
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200280static int read_commands(struct sock *sk)
281{
282 struct mgmt_rp_read_commands *rp;
283 u16 num_commands = ARRAY_SIZE(mgmt_commands);
284 u16 num_events = ARRAY_SIZE(mgmt_events);
285 u16 *opcode;
286 size_t rp_size;
287 int i, err;
288
289 BT_DBG("sock %p", sk);
290
291 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
292
293 rp = kmalloc(rp_size, GFP_KERNEL);
294 if (!rp)
295 return -ENOMEM;
296
297 put_unaligned_le16(num_commands, &rp->num_commands);
298 put_unaligned_le16(num_events, &rp->num_events);
299
300 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
301 put_unaligned_le16(mgmt_commands[i], opcode);
302
303 for (i = 0; i < num_events; i++, opcode++)
304 put_unaligned_le16(mgmt_events[i], opcode);
305
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200306 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200307 rp_size);
308 kfree(rp);
309
310 return err;
311}
312
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313static int read_index_list(struct sock *sk)
314{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315 struct mgmt_rp_read_index_list *rp;
316 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200317 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200318 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200319 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200320 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200321
322 BT_DBG("sock %p", sk);
323
324 read_lock(&hci_dev_list_lock);
325
326 count = 0;
327 list_for_each(p, &hci_dev_list) {
328 count++;
329 }
330
Johan Hedberga38528f2011-01-22 06:46:43 +0200331 rp_len = sizeof(*rp) + (2 * count);
332 rp = kmalloc(rp_len, GFP_ATOMIC);
333 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100334 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200335 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100336 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200337
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 put_unaligned_le16(count, &rp->num_controllers);
339
340 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200341 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200342 if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200343 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200344
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 Hedbergaee9b2182012-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
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200395 if (test_bit(HCI_UP, &hdev->flags))
396 settings |= MGMT_SETTING_POWERED;
397 else
398 return settings;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200399
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200400 if (test_bit(HCI_PSCAN, &hdev->flags))
401 settings |= MGMT_SETTING_CONNECTABLE;
402
403 if (test_bit(HCI_ISCAN, &hdev->flags))
404 settings |= MGMT_SETTING_DISCOVERABLE;
405
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200406 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200407 settings |= MGMT_SETTING_PAIRABLE;
408
409 if (!(hdev->features[4] & LMP_NO_BREDR))
410 settings |= MGMT_SETTING_BREDR;
411
Andre Guedes59e29402011-12-30 10:34:03 -0300412 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200414
415 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200417
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200418 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200419 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200420
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200421 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
422 settings |= MGMT_SETTING_HS;
423
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200424 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200425}
426
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300427#define PNP_INFO_SVCLASS_ID 0x1200
428
429static u8 bluetooth_base_uuid[] = {
430 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
431 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
432};
433
434static u16 get_uuid16(u8 *uuid128)
435{
436 u32 val;
437 int i;
438
439 for (i = 0; i < 12; i++) {
440 if (bluetooth_base_uuid[i] != uuid128[i])
441 return 0;
442 }
443
444 memcpy(&val, &uuid128[12], 4);
445
446 val = le32_to_cpu(val);
447 if (val > 0xffff)
448 return 0;
449
450 return (u16) val;
451}
452
453static void create_eir(struct hci_dev *hdev, u8 *data)
454{
455 u8 *ptr = data;
456 u16 eir_len = 0;
457 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
458 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200459 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300460 size_t name_len;
461
462 name_len = strlen(hdev->dev_name);
463
464 if (name_len > 0) {
465 /* EIR Data type */
466 if (name_len > 48) {
467 name_len = 48;
468 ptr[1] = EIR_NAME_SHORT;
469 } else
470 ptr[1] = EIR_NAME_COMPLETE;
471
472 /* EIR Data length */
473 ptr[0] = name_len + 1;
474
475 memcpy(ptr + 2, hdev->dev_name, name_len);
476
477 eir_len += (name_len + 2);
478 ptr += (name_len + 2);
479 }
480
481 memset(uuid16_list, 0, sizeof(uuid16_list));
482
483 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200484 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300485 u16 uuid16;
486
487 uuid16 = get_uuid16(uuid->uuid);
488 if (uuid16 == 0)
489 return;
490
491 if (uuid16 < 0x1100)
492 continue;
493
494 if (uuid16 == PNP_INFO_SVCLASS_ID)
495 continue;
496
497 /* Stop if not enough space to put next UUID */
498 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
499 truncated = 1;
500 break;
501 }
502
503 /* Check for duplicates */
504 for (i = 0; uuid16_list[i] != 0; i++)
505 if (uuid16_list[i] == uuid16)
506 break;
507
508 if (uuid16_list[i] == 0) {
509 uuid16_list[i] = uuid16;
510 eir_len += sizeof(u16);
511 }
512 }
513
514 if (uuid16_list[0] != 0) {
515 u8 *length = ptr;
516
517 /* EIR Data type */
518 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
519
520 ptr += 2;
521 eir_len += 2;
522
523 for (i = 0; uuid16_list[i] != 0; i++) {
524 *ptr++ = (uuid16_list[i] & 0x00ff);
525 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
526 }
527
528 /* EIR Data length */
529 *length = (i * sizeof(u16)) + 1;
530 }
531}
532
533static int update_eir(struct hci_dev *hdev)
534{
535 struct hci_cp_write_eir cp;
536
537 if (!(hdev->features[6] & LMP_EXT_INQ))
538 return 0;
539
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200540 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300541 return 0;
542
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200543 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300544 return 0;
545
546 memset(&cp, 0, sizeof(cp));
547
548 create_eir(hdev, cp.data);
549
550 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
551 return 0;
552
553 memcpy(hdev->eir, cp.data, sizeof(cp.data));
554
555 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
556}
557
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200558static u8 get_service_classes(struct hci_dev *hdev)
559{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300560 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200561 u8 val = 0;
562
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300563 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200564 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565
566 return val;
567}
568
569static int update_class(struct hci_dev *hdev)
570{
571 u8 cod[3];
572
573 BT_DBG("%s", hdev->name);
574
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200575 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200576 return 0;
577
578 cod[0] = hdev->minor_class;
579 cod[1] = hdev->major_class;
580 cod[2] = get_service_classes(hdev);
581
582 if (memcmp(cod, hdev->dev_class, 3) == 0)
583 return 0;
584
585 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
586}
587
Johan Hedberg7d785252011-12-15 00:47:39 +0200588static void service_cache_off(struct work_struct *work)
589{
590 struct hci_dev *hdev = container_of(work, struct hci_dev,
591 service_cache.work);
592
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200593 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200594 return;
595
596 hci_dev_lock(hdev);
597
598 update_eir(hdev);
599 update_class(hdev);
600
601 hci_dev_unlock(hdev);
602}
603
604static void mgmt_init_hdev(struct hci_dev *hdev)
605{
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200606 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200607 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
608
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200609 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200610 schedule_delayed_work(&hdev->service_cache,
611 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
612}
613
Johan Hedberg03811012010-12-08 00:21:06 +0200614static int read_controller_info(struct sock *sk, u16 index)
615{
616 struct mgmt_rp_read_info rp;
617 struct hci_dev *hdev;
618
619 BT_DBG("sock %p hci%u", sk, index);
620
621 hdev = hci_dev_get(index);
622 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200623 return cmd_status(sk, index, MGMT_OP_READ_INFO,
624 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200625
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200626 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
Johan Hedberg03811012010-12-08 00:21:06 +0200627 cancel_delayed_work_sync(&hdev->power_off);
628
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300629 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200630
Johan Hedberg7d785252011-12-15 00:47:39 +0200631 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
632 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
634 memset(&rp, 0, sizeof(rp));
635
Johan Hedberg03811012010-12-08 00:21:06 +0200636 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200637
638 rp.version = hdev->hci_ver;
639
Johan Hedberg03811012010-12-08 00:21:06 +0200640 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200641
642 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
643 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
644
645 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200646
647 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
648
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300649 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200650 hci_dev_put(hdev);
651
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200652 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200653}
654
655static void mgmt_pending_free(struct pending_cmd *cmd)
656{
657 sock_put(cmd->sk);
658 kfree(cmd->param);
659 kfree(cmd);
660}
661
662static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
663 struct hci_dev *hdev,
664 void *data, u16 len)
665{
666 struct pending_cmd *cmd;
667
668 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
669 if (!cmd)
670 return NULL;
671
672 cmd->opcode = opcode;
673 cmd->index = hdev->id;
674
675 cmd->param = kmalloc(len, GFP_ATOMIC);
676 if (!cmd->param) {
677 kfree(cmd);
678 return NULL;
679 }
680
681 if (data)
682 memcpy(cmd->param, data, len);
683
684 cmd->sk = sk;
685 sock_hold(sk);
686
687 list_add(&cmd->list, &hdev->mgmt_pending);
688
689 return cmd;
690}
691
692static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
693 void (*cb)(struct pending_cmd *cmd, void *data),
694 void *data)
695{
696 struct list_head *p, *n;
697
698 list_for_each_safe(p, n, &hdev->mgmt_pending) {
699 struct pending_cmd *cmd;
700
701 cmd = list_entry(p, struct pending_cmd, list);
702
703 if (opcode > 0 && cmd->opcode != opcode)
704 continue;
705
706 cb(cmd, data);
707 }
708}
709
710static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
711{
712 struct pending_cmd *cmd;
713
714 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
715 if (cmd->opcode == opcode)
716 return cmd;
717 }
718
719 return NULL;
720}
721
722static void mgmt_pending_remove(struct pending_cmd *cmd)
723{
724 list_del(&cmd->list);
725 mgmt_pending_free(cmd);
726}
727
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200728static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200729{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200730 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200731
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200732 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
733 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200734}
735
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300736static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200737{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300738 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200739 struct hci_dev *hdev;
740 struct pending_cmd *cmd;
741 int err, up;
742
Johan Hedberg03811012010-12-08 00:21:06 +0200743 BT_DBG("request for hci%u", index);
744
745 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200746 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
747 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200748
749 hdev = hci_dev_get(index);
750 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200751 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
752 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200753
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300754 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200755
756 up = test_bit(HCI_UP, &hdev->flags);
757 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200758 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200759 goto failed;
760 }
761
762 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200763 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
764 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200765 goto failed;
766 }
767
768 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
769 if (!cmd) {
770 err = -ENOMEM;
771 goto failed;
772 }
773
774 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200775 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200776 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200777 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200778
779 err = 0;
780
781failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300782 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200783 hci_dev_put(hdev);
784 return err;
785}
786
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300787static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200788{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300789 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200790 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200791 struct pending_cmd *cmd;
792 u8 scan;
793 int err;
794
Johan Hedberg03811012010-12-08 00:21:06 +0200795 BT_DBG("request for hci%u", index);
796
797 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200798 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
799 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200800
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200801 hdev = hci_dev_get(index);
802 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200803 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
804 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200805
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300806 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200807
808 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200809 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
810 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200811 goto failed;
812 }
813
814 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
815 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200816 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
817 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200818 goto failed;
819 }
820
821 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
822 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200823 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200824 goto failed;
825 }
826
827 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
828 if (!cmd) {
829 err = -ENOMEM;
830 goto failed;
831 }
832
833 scan = SCAN_PAGE;
834
835 if (cp->val)
836 scan |= SCAN_INQUIRY;
837 else
838 cancel_delayed_work(&hdev->discov_off);
839
840 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
841 if (err < 0)
842 mgmt_pending_remove(cmd);
843
Johan Hedberg03811012010-12-08 00:21:06 +0200844 if (cp->val)
845 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
846
Johan Hedberge41d8b42010-12-13 21:07:03 +0200847failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300848 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200849 hci_dev_put(hdev);
850
851 return err;
852}
853
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300854static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200855{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300856 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200857 struct hci_dev *hdev;
858 struct pending_cmd *cmd;
859 u8 scan;
860 int err;
861
Johan Hedberge41d8b42010-12-13 21:07:03 +0200862 BT_DBG("request for hci%u", index);
863
Johan Hedberg03811012010-12-08 00:21:06 +0200864 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200865 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
866 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200867
868 hdev = hci_dev_get(index);
869 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200870 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
871 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200872
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300873 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200874
875 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200876 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
877 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200878 goto failed;
879 }
880
881 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
882 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200883 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
884 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200885 goto failed;
886 }
887
888 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200889 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200890 goto failed;
891 }
892
893 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
894 if (!cmd) {
895 err = -ENOMEM;
896 goto failed;
897 }
898
899 if (cp->val)
900 scan = SCAN_PAGE;
901 else
902 scan = 0;
903
904 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
905 if (err < 0)
906 mgmt_pending_remove(cmd);
907
908failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300909 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200910 hci_dev_put(hdev);
911
912 return err;
913}
914
915static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
916 u16 data_len, struct sock *skip_sk)
917{
918 struct sk_buff *skb;
919 struct mgmt_hdr *hdr;
920
921 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
922 if (!skb)
923 return -ENOMEM;
924
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200925 hdr = (void *) skb_put(skb, sizeof(*hdr));
926 hdr->opcode = cpu_to_le16(event);
927 if (hdev)
928 hdr->index = cpu_to_le16(hdev->id);
929 else
930 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
931 hdr->len = cpu_to_le16(data_len);
932
933 if (data)
934 memcpy(skb_put(skb, data_len), data, data_len);
935
Marcel Holtmann470fe1b2012-02-20 14:50:30 +0100936 hci_send_to_control(skb, skip_sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200937 kfree_skb(skb);
938
939 return 0;
940}
941
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300942static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200943{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300944 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200945 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200946 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200947 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200948
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200949 BT_DBG("request for hci%u", index);
950
951 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200952 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
953 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200954
955 hdev = hci_dev_get(index);
956 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200957 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
958 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200959
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300960 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200961
962 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200963 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200964 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200965 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200966
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200967 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200968 if (err < 0)
969 goto failed;
970
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200971 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200972
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200973 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200974
975failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300976 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200977 hci_dev_put(hdev);
978
979 return err;
980}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200981
Johan Hedberg33ef95e2012-02-16 23:56:27 +0200982static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
983{
984 struct mgmt_mode *cp = data;
985 struct pending_cmd *cmd;
986 struct hci_dev *hdev;
987 uint8_t val;
988 int err;
989
990 BT_DBG("request for hci%u", index);
991
992 if (len != sizeof(*cp))
993 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
994 MGMT_STATUS_INVALID_PARAMS);
995
996 hdev = hci_dev_get(index);
997 if (!hdev)
998 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
999 MGMT_STATUS_INVALID_PARAMS);
1000
1001 hci_dev_lock(hdev);
1002
1003 if (!test_bit(HCI_UP, &hdev->flags)) {
1004 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1005 MGMT_STATUS_NOT_POWERED);
1006 goto failed;
1007 }
1008
1009 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1010 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1011 MGMT_STATUS_BUSY);
1012 goto failed;
1013 }
1014
1015 val = !!cp->val;
1016
1017 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1018 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1019 goto failed;
1020 }
1021
1022 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1023 if (!cmd) {
1024 err = -ENOMEM;
1025 goto failed;
1026 }
1027
1028 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1029 if (err < 0) {
1030 mgmt_pending_remove(cmd);
1031 goto failed;
1032 }
1033
1034failed:
1035 hci_dev_unlock(hdev);
1036 hci_dev_put(hdev);
1037
1038 return err;
1039}
1040
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001041static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1042{
1043 struct mgmt_mode *cp = data;
1044 struct pending_cmd *cmd;
1045 struct hci_dev *hdev;
1046 uint8_t val;
1047 int err;
1048
1049 BT_DBG("request for hci%u", index);
1050
1051 if (len != sizeof(*cp))
1052 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1053 MGMT_STATUS_INVALID_PARAMS);
1054
1055 hdev = hci_dev_get(index);
1056 if (!hdev)
1057 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1058 MGMT_STATUS_INVALID_PARAMS);
1059
1060 hci_dev_lock(hdev);
1061
1062 if (!test_bit(HCI_UP, &hdev->flags)) {
1063 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1064 MGMT_STATUS_NOT_POWERED);
1065 goto failed;
1066 }
1067
1068 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1069 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1070 goto failed;
1071 }
1072
1073 val = !!cp->val;
1074
1075 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1076 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1077 goto failed;
1078 }
1079
1080 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1081 if (!cmd) {
1082 err = -ENOMEM;
1083 goto failed;
1084 }
1085
1086 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1087 if (err < 0) {
1088 mgmt_pending_remove(cmd);
1089 goto failed;
1090 }
1091
1092failed:
1093 hci_dev_unlock(hdev);
1094 hci_dev_put(hdev);
1095
1096 return err;
1097}
1098
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001099static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1100{
1101 struct mgmt_mode *cp = data;
1102 struct hci_dev *hdev;
1103 int err;
1104
1105 BT_DBG("request for hci%u", index);
1106
1107 if (len != sizeof(*cp))
1108 return cmd_status(sk, index, MGMT_OP_SET_HS,
1109 MGMT_STATUS_INVALID_PARAMS);
1110
1111 hdev = hci_dev_get(index);
1112 if (!hdev)
1113 return cmd_status(sk, index, MGMT_OP_SET_HS,
1114 MGMT_STATUS_INVALID_PARAMS);
1115
1116 if (!enable_hs) {
1117 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1118 MGMT_STATUS_NOT_SUPPORTED);
1119 goto failed;
1120 }
1121
1122 if (cp->val)
1123 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1124 else
1125 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1126
1127 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1128
1129failed:
1130 hci_dev_put(hdev);
1131 return err;
1132}
1133
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001134static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001135{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001136 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001137 struct hci_dev *hdev;
1138 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001139 int err;
1140
Szymon Janc4e51eae2011-02-25 19:05:48 +01001141 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001142
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001143 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001144 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1145 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001146
Szymon Janc4e51eae2011-02-25 19:05:48 +01001147 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001148 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001149 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1150 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001151
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001152 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001153
1154 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1155 if (!uuid) {
1156 err = -ENOMEM;
1157 goto failed;
1158 }
1159
1160 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001161 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001162
1163 list_add(&uuid->list, &hdev->uuids);
1164
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001165 err = update_class(hdev);
1166 if (err < 0)
1167 goto failed;
1168
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001169 err = update_eir(hdev);
1170 if (err < 0)
1171 goto failed;
1172
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001173 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001174
1175failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001176 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001177 hci_dev_put(hdev);
1178
1179 return err;
1180}
1181
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001182static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001183{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001184 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001185 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001186 struct hci_dev *hdev;
1187 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 +02001188 int err, found;
1189
Szymon Janc4e51eae2011-02-25 19:05:48 +01001190 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001191
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001192 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001193 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1194 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001195
Szymon Janc4e51eae2011-02-25 19:05:48 +01001196 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001197 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001198 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1199 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001200
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001201 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001202
1203 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1204 err = hci_uuids_clear(hdev);
1205 goto unlock;
1206 }
1207
1208 found = 0;
1209
1210 list_for_each_safe(p, n, &hdev->uuids) {
1211 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1212
1213 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1214 continue;
1215
1216 list_del(&match->list);
1217 found++;
1218 }
1219
1220 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001221 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1222 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001223 goto unlock;
1224 }
1225
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001226 err = update_class(hdev);
1227 if (err < 0)
1228 goto unlock;
1229
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001230 err = update_eir(hdev);
1231 if (err < 0)
1232 goto unlock;
1233
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001234 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001235
1236unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001237 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001238 hci_dev_put(hdev);
1239
1240 return err;
1241}
1242
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001243static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001244{
1245 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001246 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001247 int err;
1248
Szymon Janc4e51eae2011-02-25 19:05:48 +01001249 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001250
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001251 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001252 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1253 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001254
Szymon Janc4e51eae2011-02-25 19:05:48 +01001255 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001256 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001257 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1258 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001259
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001260 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001261
1262 hdev->major_class = cp->major;
1263 hdev->minor_class = cp->minor;
1264
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001265 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001266 hci_dev_unlock(hdev);
1267 cancel_delayed_work_sync(&hdev->service_cache);
1268 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001269 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001270 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001271
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001272 err = update_class(hdev);
1273
1274 if (err == 0)
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001275 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1276 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001277
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001278 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001279 hci_dev_put(hdev);
1280
1281 return err;
1282}
1283
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001284static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001285{
1286 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001287 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001288 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001289 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001290
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001291 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001292 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1293 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001294
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001295 key_count = get_unaligned_le16(&cp->key_count);
1296
Johan Hedberg86742e12011-11-07 23:13:38 +02001297 expected_len = sizeof(*cp) + key_count *
1298 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001299 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001300 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001301 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001302 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1303 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001304 }
1305
Szymon Janc4e51eae2011-02-25 19:05:48 +01001306 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001307 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001308 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1309 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001310
Szymon Janc4e51eae2011-02-25 19:05:48 +01001311 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001312 key_count);
1313
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001314 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001315
1316 hci_link_keys_clear(hdev);
1317
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001318 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001319
1320 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001321 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001322 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001323 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001324
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001325 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001326 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001327
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001328 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1329 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001330 }
1331
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001332 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001333
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001334 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001335 hci_dev_put(hdev);
1336
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001337 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001338}
1339
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001340static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1341 u8 addr_type, struct sock *skip_sk)
1342{
1343 struct mgmt_ev_device_unpaired ev;
1344
1345 bacpy(&ev.addr.bdaddr, bdaddr);
1346 ev.addr.type = addr_type;
1347
1348 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1349 skip_sk);
1350}
1351
Johan Hedberg124f6e32012-02-09 13:50:12 +02001352static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001353{
1354 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001355 struct mgmt_cp_unpair_device *cp = data;
1356 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001357 struct hci_cp_disconnect dc;
1358 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001359 struct hci_conn *conn;
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001360 u8 status = 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001361 int err;
1362
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001363 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001364 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001365 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001366
Szymon Janc4e51eae2011-02-25 19:05:48 +01001367 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001368 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001369 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001370 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001371
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001372 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001373
Johan Hedberga8a1d192011-11-10 15:54:38 +02001374 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001375 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1376 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001377
Johan Hedberg124f6e32012-02-09 13:50:12 +02001378 if (cp->addr.type == MGMT_ADDR_BREDR)
1379 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1380 else
1381 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001382
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001383 if (err < 0) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001384 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001385 goto unlock;
1386 }
1387
Johan Hedberga8a1d192011-11-10 15:54:38 +02001388 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001389 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1390 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001391 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001392 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001393 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001394
Johan Hedberg124f6e32012-02-09 13:50:12 +02001395 if (cp->addr.type == MGMT_ADDR_BREDR)
1396 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1397 &cp->addr.bdaddr);
1398 else
1399 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1400 &cp->addr.bdaddr);
1401
Johan Hedberga8a1d192011-11-10 15:54:38 +02001402 if (!conn) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001403 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1404 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001405 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001406 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001407 }
1408
Johan Hedberg124f6e32012-02-09 13:50:12 +02001409 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1410 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001411 if (!cmd) {
1412 err = -ENOMEM;
1413 goto unlock;
1414 }
1415
1416 put_unaligned_le16(conn->handle, &dc.handle);
1417 dc.reason = 0x13; /* Remote User Terminated Connection */
1418 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1419 if (err < 0)
1420 mgmt_pending_remove(cmd);
1421
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001422unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001423 if (err < 0)
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001424 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1425 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001426 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001427 hci_dev_put(hdev);
1428
1429 return err;
1430}
1431
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001432static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001433{
1434 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001435 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001436 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001437 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001438 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001439 int err;
1440
1441 BT_DBG("");
1442
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001443 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001444 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1445 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001446
Szymon Janc4e51eae2011-02-25 19:05:48 +01001447 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001448 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001449 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1450 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001451
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001452 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001453
1454 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001455 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1456 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001457 goto failed;
1458 }
1459
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001460 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001461 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1462 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001463 goto failed;
1464 }
1465
Johan Hedberg88c3df12012-02-09 14:27:38 +02001466 if (cp->addr.type == MGMT_ADDR_BREDR)
1467 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1468 else
1469 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001470
Johan Hedberg8962ee72011-01-20 12:40:27 +02001471 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001472 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1473 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001474 goto failed;
1475 }
1476
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001477 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001478 if (!cmd) {
1479 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001480 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001481 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001482
1483 put_unaligned_le16(conn->handle, &dc.handle);
1484 dc.reason = 0x13; /* Remote User Terminated Connection */
1485
1486 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1487 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001488 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001489
1490failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001491 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001492 hci_dev_put(hdev);
1493
1494 return err;
1495}
1496
Johan Hedberg48264f02011-11-09 13:58:58 +02001497static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001498{
1499 switch (link_type) {
1500 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001501 switch (addr_type) {
1502 case ADDR_LE_DEV_PUBLIC:
1503 return MGMT_ADDR_LE_PUBLIC;
1504 case ADDR_LE_DEV_RANDOM:
1505 return MGMT_ADDR_LE_RANDOM;
1506 default:
1507 return MGMT_ADDR_INVALID;
1508 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001509 case ACL_LINK:
1510 return MGMT_ADDR_BREDR;
1511 default:
1512 return MGMT_ADDR_INVALID;
1513 }
1514}
1515
Szymon Janc8ce62842011-03-01 16:55:32 +01001516static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001517{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001518 struct mgmt_rp_get_connections *rp;
1519 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001520 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001521 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001522 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001523 int i, err;
1524
1525 BT_DBG("");
1526
Szymon Janc4e51eae2011-02-25 19:05:48 +01001527 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001528 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001529 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1530 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001531
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001532 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001533
1534 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001535 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1536 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1537 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001538 }
1539
Johan Hedberg4c659c32011-11-07 23:13:39 +02001540 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001541 rp = kmalloc(rp_len, GFP_ATOMIC);
1542 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001543 err = -ENOMEM;
1544 goto unlock;
1545 }
1546
Johan Hedberg2784eb42011-01-21 13:56:35 +02001547 put_unaligned_le16(count, &rp->conn_count);
1548
Johan Hedberg2784eb42011-01-21 13:56:35 +02001549 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001550 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001551 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1552 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001553 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001554 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001555 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1556 continue;
1557 i++;
1558 }
1559
1560 /* Recalculate length in case of filtered SCO connections, etc */
1561 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001562
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001563 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001564
1565unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001566 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001567 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001568 hci_dev_put(hdev);
1569 return err;
1570}
1571
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001572static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1573 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1574{
1575 struct pending_cmd *cmd;
1576 int err;
1577
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001578 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001579 sizeof(*cp));
1580 if (!cmd)
1581 return -ENOMEM;
1582
Johan Hedbergd8457692012-02-17 14:24:57 +02001583 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1584 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001585 if (err < 0)
1586 mgmt_pending_remove(cmd);
1587
1588 return err;
1589}
1590
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001591static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001592{
1593 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001594 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001595 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001596 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001597 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001598 int err;
1599
1600 BT_DBG("");
1601
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001602 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001603 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1604 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001605
Szymon Janc4e51eae2011-02-25 19:05:48 +01001606 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001607 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001608 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1609 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001610
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001611 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001612
1613 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001614 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1615 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001616 goto failed;
1617 }
1618
Johan Hedbergd8457692012-02-17 14:24:57 +02001619 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001620 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001621 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1622 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001623 goto failed;
1624 }
1625
1626 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001627 struct mgmt_cp_pin_code_neg_reply ncp;
1628
1629 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001630
1631 BT_ERR("PIN code is not 16 bytes long");
1632
1633 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1634 if (err >= 0)
1635 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001636 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001637
1638 goto failed;
1639 }
1640
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001641 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1642 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001643 if (!cmd) {
1644 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001645 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001646 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001647
Johan Hedbergd8457692012-02-17 14:24:57 +02001648 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001649 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001650 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001651
1652 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1653 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001654 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001655
1656failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001657 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001658 hci_dev_put(hdev);
1659
1660 return err;
1661}
1662
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001663static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001664{
1665 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001666 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001667 int err;
1668
1669 BT_DBG("");
1670
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001671 if (len != sizeof(*cp))
1672 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001673 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001674
Szymon Janc4e51eae2011-02-25 19:05:48 +01001675 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001676 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001677 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001678 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001679
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001680 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001681
1682 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001683 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001684 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001685 goto failed;
1686 }
1687
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001688 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001689
1690failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001691 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001692 hci_dev_put(hdev);
1693
1694 return err;
1695}
1696
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001697static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001698{
1699 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001700 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001701
1702 BT_DBG("");
1703
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001704 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001705 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1706 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001707
Szymon Janc4e51eae2011-02-25 19:05:48 +01001708 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001709 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001710 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1711 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001712
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001713 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001714
1715 hdev->io_capability = cp->io_capability;
1716
1717 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001718 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001719
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001720 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001721 hci_dev_put(hdev);
1722
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001723 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001724}
1725
Johan Hedberge9a416b2011-02-19 12:05:56 -03001726static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1727{
1728 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001729 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001730
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001731 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001732 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1733 continue;
1734
Johan Hedberge9a416b2011-02-19 12:05:56 -03001735 if (cmd->user_data != conn)
1736 continue;
1737
1738 return cmd;
1739 }
1740
1741 return NULL;
1742}
1743
1744static void pairing_complete(struct pending_cmd *cmd, u8 status)
1745{
1746 struct mgmt_rp_pair_device rp;
1747 struct hci_conn *conn = cmd->user_data;
1748
Johan Hedbergba4e5642011-11-11 00:07:34 +02001749 bacpy(&rp.addr.bdaddr, &conn->dst);
1750 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001751
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001752 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1753 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001754
1755 /* So we don't get further callbacks for this connection */
1756 conn->connect_cfm_cb = NULL;
1757 conn->security_cfm_cb = NULL;
1758 conn->disconn_cfm_cb = NULL;
1759
1760 hci_conn_put(conn);
1761
Johan Hedberga664b5b2011-02-19 12:06:02 -03001762 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001763}
1764
1765static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1766{
1767 struct pending_cmd *cmd;
1768
1769 BT_DBG("status %u", status);
1770
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001771 cmd = find_pairing(conn);
1772 if (!cmd)
1773 BT_DBG("Unable to find a pending command");
1774 else
Johan Hedberge2113262012-02-18 15:20:03 +02001775 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001776}
1777
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001778static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001779{
1780 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001781 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001782 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001783 struct pending_cmd *cmd;
1784 u8 sec_level, auth_type;
1785 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001786 int err;
1787
1788 BT_DBG("");
1789
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001790 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001791 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1792 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001793
Szymon Janc4e51eae2011-02-25 19:05:48 +01001794 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001795 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001796 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1797 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001798
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001799 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001800
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001801 sec_level = BT_SECURITY_MEDIUM;
1802 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001803 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001804 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001805 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001806
Johan Hedbergba4e5642011-11-11 00:07:34 +02001807 if (cp->addr.type == MGMT_ADDR_BREDR)
1808 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001809 auth_type);
1810 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001811 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001812 auth_type);
1813
Johan Hedberg1425acb2011-11-11 00:07:35 +02001814 memset(&rp, 0, sizeof(rp));
1815 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1816 rp.addr.type = cp->addr.type;
1817
Ville Tervo30e76272011-02-22 16:10:53 -03001818 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001819 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1820 MGMT_STATUS_CONNECT_FAILED,
1821 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001822 goto unlock;
1823 }
1824
1825 if (conn->connect_cfm_cb) {
1826 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001827 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1828 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001829 goto unlock;
1830 }
1831
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001832 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001833 if (!cmd) {
1834 err = -ENOMEM;
1835 hci_conn_put(conn);
1836 goto unlock;
1837 }
1838
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001839 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001840 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001841 conn->connect_cfm_cb = pairing_complete_cb;
1842
Johan Hedberge9a416b2011-02-19 12:05:56 -03001843 conn->security_cfm_cb = pairing_complete_cb;
1844 conn->disconn_cfm_cb = pairing_complete_cb;
1845 conn->io_capability = cp->io_cap;
1846 cmd->user_data = conn;
1847
1848 if (conn->state == BT_CONNECTED &&
1849 hci_conn_security(conn, sec_level, auth_type))
1850 pairing_complete(cmd, 0);
1851
1852 err = 0;
1853
1854unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001855 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001856 hci_dev_put(hdev);
1857
1858 return err;
1859}
1860
Johan Hedberg28424702012-02-02 04:02:29 +02001861static int cancel_pair_device(struct sock *sk, u16 index,
1862 unsigned char *data, u16 len)
1863{
1864 struct mgmt_addr_info *addr = (void *) data;
1865 struct hci_dev *hdev;
1866 struct pending_cmd *cmd;
1867 struct hci_conn *conn;
1868 int err;
1869
1870 BT_DBG("");
1871
1872 if (len != sizeof(*addr))
1873 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1874 MGMT_STATUS_INVALID_PARAMS);
1875
1876 hdev = hci_dev_get(index);
1877 if (!hdev)
1878 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1879 MGMT_STATUS_INVALID_PARAMS);
1880
1881 hci_dev_lock(hdev);
1882
1883 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1884 if (!cmd) {
1885 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1886 MGMT_STATUS_INVALID_PARAMS);
1887 goto unlock;
1888 }
1889
1890 conn = cmd->user_data;
1891
1892 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1893 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1894 MGMT_STATUS_INVALID_PARAMS);
1895 goto unlock;
1896 }
1897
1898 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1899
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001900 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001901 sizeof(*addr));
1902unlock:
1903 hci_dev_unlock(hdev);
1904 hci_dev_put(hdev);
1905
1906 return err;
1907}
1908
Brian Gix0df4c182011-11-16 13:53:13 -08001909static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001910 u8 type, u16 mgmt_op, u16 hci_op,
1911 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001912{
Johan Hedberga5c29682011-02-19 12:05:57 -03001913 struct pending_cmd *cmd;
1914 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001915 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001916 int err;
1917
Szymon Janc4e51eae2011-02-25 19:05:48 +01001918 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001919 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001920 return cmd_status(sk, index, mgmt_op,
1921 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001922
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001923 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001924
Johan Hedberga5c29682011-02-19 12:05:57 -03001925 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001926 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1927 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001928 }
1929
Johan Hedberg272d90d2012-02-09 15:26:12 +02001930 if (type == MGMT_ADDR_BREDR)
1931 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1932 else
Brian Gix47c15e22011-11-16 13:53:14 -08001933 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001934
Johan Hedberg272d90d2012-02-09 15:26:12 +02001935 if (!conn) {
1936 err = cmd_status(sk, index, mgmt_op,
1937 MGMT_STATUS_NOT_CONNECTED);
1938 goto done;
1939 }
1940
1941 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001942 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001943 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001944
Brian Gix5fe57d92011-12-21 16:12:13 -08001945 if (!err)
1946 err = cmd_status(sk, index, mgmt_op,
1947 MGMT_STATUS_SUCCESS);
1948 else
1949 err = cmd_status(sk, index, mgmt_op,
1950 MGMT_STATUS_FAILED);
1951
Brian Gix47c15e22011-11-16 13:53:14 -08001952 goto done;
1953 }
1954
Brian Gix0df4c182011-11-16 13:53:13 -08001955 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001956 if (!cmd) {
1957 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001958 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001959 }
1960
Brian Gix0df4c182011-11-16 13:53:13 -08001961 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001962 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1963 struct hci_cp_user_passkey_reply cp;
1964
1965 bacpy(&cp.bdaddr, bdaddr);
1966 cp.passkey = passkey;
1967 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1968 } else
1969 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1970
Johan Hedberga664b5b2011-02-19 12:06:02 -03001971 if (err < 0)
1972 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001973
Brian Gix0df4c182011-11-16 13:53:13 -08001974done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001975 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001976 hci_dev_put(hdev);
1977
1978 return err;
1979}
1980
Brian Gix0df4c182011-11-16 13:53:13 -08001981static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1982{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001983 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001984
1985 BT_DBG("");
1986
1987 if (len != sizeof(*cp))
1988 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1989 MGMT_STATUS_INVALID_PARAMS);
1990
Johan Hedberg272d90d2012-02-09 15:26:12 +02001991 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1992 MGMT_OP_USER_CONFIRM_REPLY,
1993 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001994}
1995
1996static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1997 u16 len)
1998{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001999 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002000
2001 BT_DBG("");
2002
2003 if (len != sizeof(*cp))
2004 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2005 MGMT_STATUS_INVALID_PARAMS);
2006
Johan Hedberg272d90d2012-02-09 15:26:12 +02002007 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2008 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2009 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002010}
2011
Brian Gix604086b2011-11-23 08:28:33 -08002012static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2013{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002014 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002015
2016 BT_DBG("");
2017
2018 if (len != sizeof(*cp))
2019 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2020 EINVAL);
2021
Johan Hedberg272d90d2012-02-09 15:26:12 +02002022 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2023 MGMT_OP_USER_PASSKEY_REPLY,
2024 HCI_OP_USER_PASSKEY_REPLY,
2025 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002026}
2027
2028static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2029 u16 len)
2030{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002031 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002032
2033 BT_DBG("");
2034
2035 if (len != sizeof(*cp))
2036 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2037 EINVAL);
2038
Johan Hedberg272d90d2012-02-09 15:26:12 +02002039 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2040 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2041 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002042}
2043
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002044static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002045 u16 len)
2046{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002047 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002048 struct hci_cp_write_local_name hci_cp;
2049 struct hci_dev *hdev;
2050 struct pending_cmd *cmd;
2051 int err;
2052
2053 BT_DBG("");
2054
2055 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002056 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2057 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002058
2059 hdev = hci_dev_get(index);
2060 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002061 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2062 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002063
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002064 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002065
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002066 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2067 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002068 if (!cmd) {
2069 err = -ENOMEM;
2070 goto failed;
2071 }
2072
2073 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2074 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2075 &hci_cp);
2076 if (err < 0)
2077 mgmt_pending_remove(cmd);
2078
2079failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002080 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002081 hci_dev_put(hdev);
2082
2083 return err;
2084}
2085
Szymon Jancc35938b2011-03-22 13:12:21 +01002086static int read_local_oob_data(struct sock *sk, u16 index)
2087{
2088 struct hci_dev *hdev;
2089 struct pending_cmd *cmd;
2090 int err;
2091
2092 BT_DBG("hci%u", index);
2093
2094 hdev = hci_dev_get(index);
2095 if (!hdev)
2096 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002097 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002098
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002099 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002100
2101 if (!test_bit(HCI_UP, &hdev->flags)) {
2102 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002103 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002104 goto unlock;
2105 }
2106
2107 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2108 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002109 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002110 goto unlock;
2111 }
2112
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002113 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002114 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2115 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002116 goto unlock;
2117 }
2118
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002119 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002120 if (!cmd) {
2121 err = -ENOMEM;
2122 goto unlock;
2123 }
2124
2125 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2126 if (err < 0)
2127 mgmt_pending_remove(cmd);
2128
2129unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002130 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002131 hci_dev_put(hdev);
2132
2133 return err;
2134}
2135
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002136static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2137 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002138{
2139 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002140 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002141 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002142 int err;
2143
2144 BT_DBG("hci%u ", index);
2145
2146 if (len != sizeof(*cp))
2147 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002148 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002149
2150 hdev = hci_dev_get(index);
2151 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002152 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2153 MGMT_STATUS_INVALID_PARAMS,
2154 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002155
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002156 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002157
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002158 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002159 cp->randomizer);
2160 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002161 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002162 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002163 status = 0;
2164
2165 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2166 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002167
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002168 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002169 hci_dev_put(hdev);
2170
2171 return err;
2172}
2173
2174static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002175 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002176{
2177 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002178 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002179 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002180 int err;
2181
2182 BT_DBG("hci%u ", index);
2183
2184 if (len != sizeof(*cp))
2185 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002186 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002187
2188 hdev = hci_dev_get(index);
2189 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002190 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2191 MGMT_STATUS_INVALID_PARAMS,
2192 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002193
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002194 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002195
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002196 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002197 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002198 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002199 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002200 status = 0;
2201
2202 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2203 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002204
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002205 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002206 hci_dev_put(hdev);
2207
2208 return err;
2209}
2210
Andre Guedes5e0452c2012-02-17 20:39:38 -03002211static int discovery(struct hci_dev *hdev)
2212{
2213 int err;
2214
2215 if (lmp_host_le_capable(hdev)) {
2216 if (lmp_bredr_capable(hdev)) {
2217 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2218 LE_SCAN_INT, LE_SCAN_WIN,
2219 LE_SCAN_TIMEOUT_BREDR_LE);
2220 } else {
2221 hdev->discovery.type = DISCOV_TYPE_LE;
2222 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2223 LE_SCAN_INT, LE_SCAN_WIN,
2224 LE_SCAN_TIMEOUT_LE_ONLY);
2225 }
2226 } else {
2227 hdev->discovery.type = DISCOV_TYPE_BREDR;
2228 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2229 }
2230
2231 return err;
2232}
2233
2234int mgmt_interleaved_discovery(struct hci_dev *hdev)
2235{
2236 int err;
2237
2238 BT_DBG("%s", hdev->name);
2239
2240 hci_dev_lock(hdev);
2241
2242 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2243 if (err < 0)
2244 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2245
2246 hci_dev_unlock(hdev);
2247
2248 return err;
2249}
2250
Johan Hedberg450dfda2011-11-12 11:58:22 +02002251static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002252 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002253{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002254 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002255 struct pending_cmd *cmd;
2256 struct hci_dev *hdev;
2257 int err;
2258
2259 BT_DBG("hci%u", index);
2260
Johan Hedberg450dfda2011-11-12 11:58:22 +02002261 if (len != sizeof(*cp))
2262 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2263 MGMT_STATUS_INVALID_PARAMS);
2264
Johan Hedberg14a53662011-04-27 10:29:56 -04002265 hdev = hci_dev_get(index);
2266 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002267 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2268 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002269
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002270 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002271
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002272 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002273 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2274 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002275 goto failed;
2276 }
2277
Johan Hedbergff9ef572012-01-04 14:23:45 +02002278 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2279 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2280 MGMT_STATUS_BUSY);
2281 goto failed;
2282 }
2283
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002284 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002285 if (!cmd) {
2286 err = -ENOMEM;
2287 goto failed;
2288 }
2289
Andre Guedes4aab14e2012-02-17 20:39:36 -03002290 hdev->discovery.type = cp->type;
2291
2292 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002293 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002294 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002295 break;
2296
2297 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002298 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2299 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002300 break;
2301
Andre Guedes5e0452c2012-02-17 20:39:38 -03002302 case DISCOV_TYPE_INTERLEAVED:
2303 err = discovery(hdev);
2304 break;
2305
Andre Guedesf39799f2012-02-17 20:39:35 -03002306 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002307 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002308 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002309
Johan Hedberg14a53662011-04-27 10:29:56 -04002310 if (err < 0)
2311 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002312 else
2313 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002314
2315failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002316 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002317 hci_dev_put(hdev);
2318
2319 return err;
2320}
2321
Johan Hedbergd9306502012-02-20 23:25:18 +02002322static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002323{
Johan Hedbergd9306502012-02-20 23:25:18 +02002324 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002325 struct hci_dev *hdev;
2326 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002327 struct hci_cp_remote_name_req_cancel cp;
2328 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002329 int err;
2330
2331 BT_DBG("hci%u", index);
2332
Johan Hedbergd9306502012-02-20 23:25:18 +02002333 if (len != sizeof(*mgmt_cp))
2334 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2335 MGMT_STATUS_INVALID_PARAMS);
2336
Johan Hedberg14a53662011-04-27 10:29:56 -04002337 hdev = hci_dev_get(index);
2338 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002339 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2340 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002341
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002342 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002343
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002344 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002345 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2346 MGMT_STATUS_REJECTED,
2347 &mgmt_cp->type, sizeof(mgmt_cp->type));
2348 goto unlock;
2349 }
2350
2351 if (hdev->discovery.type != mgmt_cp->type) {
2352 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2353 MGMT_STATUS_INVALID_PARAMS,
2354 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002355 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002356 }
2357
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002358 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002359 if (!cmd) {
2360 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002361 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002362 }
2363
Andre Guedes343f9352012-02-17 20:39:37 -03002364 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002365 err = hci_cancel_inquiry(hdev);
2366 if (err < 0)
2367 mgmt_pending_remove(cmd);
2368 else
2369 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2370 goto unlock;
2371 }
2372
2373 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2374 if (!e) {
2375 mgmt_pending_remove(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002376 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002377 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002378 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2379 goto unlock;
2380 }
2381
2382 bacpy(&cp.bdaddr, &e->data.bdaddr);
2383 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2384 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002385 if (err < 0)
2386 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002387 else
2388 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002389
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002390unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002391 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002392 hci_dev_put(hdev);
2393
2394 return err;
2395}
2396
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002397static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002398{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002399 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002400 struct inquiry_entry *e;
2401 struct hci_dev *hdev;
2402 int err;
2403
2404 BT_DBG("hci%u", index);
2405
2406 if (len != sizeof(*cp))
2407 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2408 MGMT_STATUS_INVALID_PARAMS);
2409
2410 hdev = hci_dev_get(index);
2411 if (!hdev)
2412 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2413 MGMT_STATUS_INVALID_PARAMS);
2414
2415 hci_dev_lock(hdev);
2416
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002417 if (!hci_discovery_active(hdev)) {
2418 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2419 MGMT_STATUS_FAILED);
2420 goto failed;
2421 }
2422
Johan Hedberga198e7b2012-02-17 14:27:06 +02002423 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002424 if (!e) {
2425 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2426 MGMT_STATUS_INVALID_PARAMS);
2427 goto failed;
2428 }
2429
2430 if (cp->name_known) {
2431 e->name_state = NAME_KNOWN;
2432 list_del(&e->list);
2433 } else {
2434 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002435 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002436 }
2437
2438 err = 0;
2439
2440failed:
2441 hci_dev_unlock(hdev);
2442
2443 return err;
2444}
2445
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002446static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002447{
2448 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002449 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002450 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002451 int err;
2452
2453 BT_DBG("hci%u", index);
2454
Antti Julku7fbec222011-06-15 12:01:15 +03002455 if (len != sizeof(*cp))
2456 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002457 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002458
2459 hdev = hci_dev_get(index);
2460 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002461 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2462 MGMT_STATUS_INVALID_PARAMS,
2463 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002464
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002465 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002466
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002467 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002468 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002469 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002470 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002471 status = 0;
2472
2473 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2474 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002475
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002476 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002477 hci_dev_put(hdev);
2478
2479 return err;
2480}
2481
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002482static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002483{
2484 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002485 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002486 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002487 int err;
2488
2489 BT_DBG("hci%u", index);
2490
Antti Julku7fbec222011-06-15 12:01:15 +03002491 if (len != sizeof(*cp))
2492 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002493 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002494
2495 hdev = hci_dev_get(index);
2496 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002497 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2498 MGMT_STATUS_INVALID_PARAMS,
2499 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002500
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002501 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002502
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002503 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002504 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002505 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002506 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002507 status = 0;
2508
2509 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2510 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002511
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002512 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002513 hci_dev_put(hdev);
2514
2515 return err;
2516}
2517
Antti Julkuf6422ec2011-06-22 13:11:56 +03002518static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002519 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002520{
2521 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002522 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002523 struct hci_cp_write_page_scan_activity acp;
2524 u8 type;
2525 int err;
2526
2527 BT_DBG("hci%u", index);
2528
2529 if (len != sizeof(*cp))
2530 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002531 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002532
2533 hdev = hci_dev_get(index);
2534 if (!hdev)
2535 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002536 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002537
2538 hci_dev_lock(hdev);
2539
Johan Hedbergf7c68692011-12-15 00:47:36 +02002540 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002541 type = PAGE_SCAN_TYPE_INTERLACED;
2542 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2543 } else {
2544 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2545 acp.interval = 0x0800; /* default 1.28 sec page scan */
2546 }
2547
2548 acp.window = 0x0012; /* default 11.25 msec page scan window */
2549
2550 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2551 sizeof(acp), &acp);
2552 if (err < 0) {
2553 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002554 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002555 goto done;
2556 }
2557
2558 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2559 if (err < 0) {
2560 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002561 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002562 goto done;
2563 }
2564
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002565 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2566 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002567done:
2568 hci_dev_unlock(hdev);
2569 hci_dev_put(hdev);
2570
2571 return err;
2572}
2573
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002574static int load_long_term_keys(struct sock *sk, u16 index,
2575 void *cp_data, u16 len)
2576{
2577 struct hci_dev *hdev;
2578 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2579 u16 key_count, expected_len;
2580 int i;
2581
2582 if (len < sizeof(*cp))
2583 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2584 EINVAL);
2585
2586 key_count = get_unaligned_le16(&cp->key_count);
2587
2588 expected_len = sizeof(*cp) + key_count *
2589 sizeof(struct mgmt_ltk_info);
2590 if (expected_len != len) {
2591 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2592 len, expected_len);
2593 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2594 EINVAL);
2595 }
2596
2597 hdev = hci_dev_get(index);
2598 if (!hdev)
2599 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2600 ENODEV);
2601
2602 BT_DBG("hci%u key_count %u", index, key_count);
2603
2604 hci_dev_lock(hdev);
2605
2606 hci_smp_ltks_clear(hdev);
2607
2608 for (i = 0; i < key_count; i++) {
2609 struct mgmt_ltk_info *key = &cp->keys[i];
2610 u8 type;
2611
2612 if (key->master)
2613 type = HCI_SMP_LTK;
2614 else
2615 type = HCI_SMP_LTK_SLAVE;
2616
2617 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2618 type, 0, key->authenticated, key->val,
2619 key->enc_size, key->ediv, key->rand);
2620 }
2621
2622 hci_dev_unlock(hdev);
2623 hci_dev_put(hdev);
2624
2625 return 0;
2626}
2627
Johan Hedberg03811012010-12-08 00:21:06 +02002628int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2629{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002630 void *buf;
2631 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002632 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002633 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002634 int err;
2635
2636 BT_DBG("got %zu bytes", msglen);
2637
2638 if (msglen < sizeof(*hdr))
2639 return -EINVAL;
2640
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002641 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002642 if (!buf)
2643 return -ENOMEM;
2644
2645 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2646 err = -EFAULT;
2647 goto done;
2648 }
2649
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002650 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002651 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002652 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002653 len = get_unaligned_le16(&hdr->len);
2654
2655 if (len != msglen - sizeof(*hdr)) {
2656 err = -EINVAL;
2657 goto done;
2658 }
2659
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002660 cp = buf + sizeof(*hdr);
2661
Johan Hedberg03811012010-12-08 00:21:06 +02002662 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002663 case MGMT_OP_READ_VERSION:
2664 err = read_version(sk);
2665 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002666 case MGMT_OP_READ_COMMANDS:
2667 err = read_commands(sk);
2668 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002669 case MGMT_OP_READ_INDEX_LIST:
2670 err = read_index_list(sk);
2671 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002672 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002673 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002674 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002675 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002676 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002677 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002678 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002679 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002680 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002681 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002682 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002683 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002684 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002685 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002686 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002687 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002688 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002689 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002690 case MGMT_OP_SET_LINK_SECURITY:
2691 err = set_link_security(sk, index, cp, len);
2692 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002693 case MGMT_OP_SET_SSP:
2694 err = set_ssp(sk, index, cp, len);
2695 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002696 case MGMT_OP_SET_HS:
2697 err = set_hs(sk, index, cp, len);
2698 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002699 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002700 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002701 break;
2702 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002703 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002704 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002705 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002706 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002707 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002708 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002709 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002710 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002711 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002712 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002713 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002714 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002715 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002716 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002717 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002718 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002719 break;
2720 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002721 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002722 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002723 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002724 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002725 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002726 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002727 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002728 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002729 case MGMT_OP_CANCEL_PAIR_DEVICE:
2730 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2731 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002732 case MGMT_OP_UNPAIR_DEVICE:
2733 err = unpair_device(sk, index, cp, len);
2734 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002735 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002736 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002737 break;
2738 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002739 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002740 break;
Brian Gix604086b2011-11-23 08:28:33 -08002741 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002742 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002743 break;
2744 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002745 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002746 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002747 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002748 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002749 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002750 case MGMT_OP_READ_LOCAL_OOB_DATA:
2751 err = read_local_oob_data(sk, index);
2752 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002753 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002754 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002755 break;
2756 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002757 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002758 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002759 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002760 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002761 break;
2762 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002763 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002764 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002765 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002766 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002767 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002768 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002769 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002770 break;
2771 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002772 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002773 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002774 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2775 err = load_long_term_keys(sk, index, cp, len);
2776 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002777 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002778 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002779 err = cmd_status(sk, index, opcode,
2780 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002781 break;
2782 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002783
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002784 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002785 goto done;
2786
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002787 err = msglen;
2788
2789done:
2790 kfree(buf);
2791 return err;
2792}
2793
Johan Hedbergb24752f2011-11-03 14:40:33 +02002794static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2795{
2796 u8 *status = data;
2797
2798 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2799 mgmt_pending_remove(cmd);
2800}
2801
Johan Hedberg744cf192011-11-08 20:40:14 +02002802int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002803{
Johan Hedberg744cf192011-11-08 20:40:14 +02002804 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002805}
2806
Johan Hedberg744cf192011-11-08 20:40:14 +02002807int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002808{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002809 u8 status = ENODEV;
2810
Johan Hedberg744cf192011-11-08 20:40:14 +02002811 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002812
Johan Hedberg744cf192011-11-08 20:40:14 +02002813 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002814}
2815
2816struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002817 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002818 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002819};
2820
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002821static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002822{
Johan Hedberg03811012010-12-08 00:21:06 +02002823 struct cmd_lookup *match = data;
2824
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002825 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002826
2827 list_del(&cmd->list);
2828
2829 if (match->sk == NULL) {
2830 match->sk = cmd->sk;
2831 sock_hold(match->sk);
2832 }
2833
2834 mgmt_pending_free(cmd);
2835}
2836
Johan Hedberg744cf192011-11-08 20:40:14 +02002837int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002838{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002839 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002840 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002841 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002842
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002843 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002844
Johan Hedbergb24752f2011-11-03 14:40:33 +02002845 if (!powered) {
2846 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002847 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002848 }
2849
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002850 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002851
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002852 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002853 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002854
2855 if (match.sk)
2856 sock_put(match.sk);
2857
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002858 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002859}
2860
Johan Hedberg744cf192011-11-08 20:40:14 +02002861int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002862{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002863 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002864 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002865 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002866
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002867 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002868
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002869 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002870
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002871 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002872 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002873 if (match.sk)
2874 sock_put(match.sk);
2875
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002876 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002877}
2878
Johan Hedberg744cf192011-11-08 20:40:14 +02002879int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002880{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002881 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002882 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002883 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002884
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002885 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2886 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002887
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002888 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002889
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002890 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002891
2892 if (match.sk)
2893 sock_put(match.sk);
2894
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002895 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002896}
2897
Johan Hedberg744cf192011-11-08 20:40:14 +02002898int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002899{
Johan Hedbergca69b792011-11-11 18:10:00 +02002900 u8 mgmt_err = mgmt_status(status);
2901
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002902 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002903 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002904 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002905
2906 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002907 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002908 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002909
2910 return 0;
2911}
2912
Johan Hedberg744cf192011-11-08 20:40:14 +02002913int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2914 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002915{
Johan Hedberg86742e12011-11-07 23:13:38 +02002916 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002917
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002918 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002919
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002920 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002921 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2922 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002923 ev.key.type = key->type;
2924 memcpy(ev.key.val, key->val, 16);
2925 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002926
Johan Hedberg744cf192011-11-08 20:40:14 +02002927 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002928}
Johan Hedbergf7520542011-01-20 12:34:39 +02002929
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002930int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2931{
2932 struct mgmt_ev_new_long_term_key ev;
2933
2934 memset(&ev, 0, sizeof(ev));
2935
2936 ev.store_hint = persistent;
2937 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2938 ev.key.addr.type = key->bdaddr_type;
2939 ev.key.authenticated = key->authenticated;
2940 ev.key.enc_size = key->enc_size;
2941 ev.key.ediv = key->ediv;
2942
2943 if (key->type == HCI_SMP_LTK)
2944 ev.key.master = 1;
2945
2946 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2947 memcpy(ev.key.val, key->val, sizeof(key->val));
2948
2949 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2950 &ev, sizeof(ev), NULL);
2951}
2952
Johan Hedbergafc747a2012-01-15 18:11:07 +02002953int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002954 u8 addr_type, u8 *name, u8 name_len,
2955 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002956{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002957 char buf[512];
2958 struct mgmt_ev_device_connected *ev = (void *) buf;
2959 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002960
Johan Hedbergb644ba32012-01-17 21:48:47 +02002961 bacpy(&ev->addr.bdaddr, bdaddr);
2962 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002963
Johan Hedbergb644ba32012-01-17 21:48:47 +02002964 if (name_len > 0)
2965 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2966 name, name_len);
2967
2968 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2969 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2970 EIR_CLASS_OF_DEV, dev_class, 3);
2971
2972 put_unaligned_le16(eir_len, &ev->eir_len);
2973
2974 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2975 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002976}
2977
Johan Hedberg8962ee72011-01-20 12:40:27 +02002978static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2979{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002980 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002981 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002982 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002983
Johan Hedberg88c3df12012-02-09 14:27:38 +02002984 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2985 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002986
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002987 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
2988 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002989
2990 *sk = cmd->sk;
2991 sock_hold(*sk);
2992
Johan Hedberga664b5b2011-02-19 12:06:02 -03002993 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002994}
2995
Johan Hedberg124f6e32012-02-09 13:50:12 +02002996static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002997{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002998 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002999 struct mgmt_cp_unpair_device *cp = cmd->param;
3000 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003001
3002 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003003 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3004 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003005
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003006 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3007
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003008 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003009
3010 mgmt_pending_remove(cmd);
3011}
3012
Johan Hedbergafc747a2012-01-15 18:11:07 +02003013int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3014 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003015{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003016 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003017 struct sock *sk = NULL;
3018 int err;
3019
Johan Hedberg744cf192011-11-08 20:40:14 +02003020 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003021
Johan Hedbergf7520542011-01-20 12:34:39 +02003022 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003023 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003024
Johan Hedbergafc747a2012-01-15 18:11:07 +02003025 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3026 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003027
3028 if (sk)
3029 sock_put(sk);
3030
Johan Hedberg124f6e32012-02-09 13:50:12 +02003031 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003032 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003033
Johan Hedberg8962ee72011-01-20 12:40:27 +02003034 return err;
3035}
3036
Johan Hedberg88c3df12012-02-09 14:27:38 +02003037int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3038 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003039{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003040 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003041 struct pending_cmd *cmd;
3042 int err;
3043
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003044 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003045 if (!cmd)
3046 return -ENOENT;
3047
Johan Hedberg88c3df12012-02-09 14:27:38 +02003048 bacpy(&rp.addr.bdaddr, bdaddr);
3049 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003050
Johan Hedberg88c3df12012-02-09 14:27:38 +02003051 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003052 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003053
Johan Hedberga664b5b2011-02-19 12:06:02 -03003054 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003055
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003056 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3057 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003058 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003059}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003060
Johan Hedberg48264f02011-11-09 13:58:58 +02003061int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3062 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003063{
3064 struct mgmt_ev_connect_failed ev;
3065
Johan Hedberg4c659c32011-11-07 23:13:39 +02003066 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003067 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003068 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003069
Johan Hedberg744cf192011-11-08 20:40:14 +02003070 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003071}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003072
Johan Hedberg744cf192011-11-08 20:40:14 +02003073int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003074{
3075 struct mgmt_ev_pin_code_request ev;
3076
Johan Hedbergd8457692012-02-17 14:24:57 +02003077 bacpy(&ev.addr.bdaddr, bdaddr);
3078 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003079 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003080
Johan Hedberg744cf192011-11-08 20:40:14 +02003081 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003082 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003083}
3084
Johan Hedberg744cf192011-11-08 20:40:14 +02003085int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3086 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003087{
3088 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003089 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003090 int err;
3091
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003092 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003093 if (!cmd)
3094 return -ENOENT;
3095
Johan Hedbergd8457692012-02-17 14:24:57 +02003096 bacpy(&rp.addr.bdaddr, bdaddr);
3097 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003098
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003099 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3100 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003101
Johan Hedberga664b5b2011-02-19 12:06:02 -03003102 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003103
3104 return err;
3105}
3106
Johan Hedberg744cf192011-11-08 20:40:14 +02003107int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3108 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003109{
3110 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003111 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003112 int err;
3113
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003114 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003115 if (!cmd)
3116 return -ENOENT;
3117
Johan Hedbergd8457692012-02-17 14:24:57 +02003118 bacpy(&rp.addr.bdaddr, bdaddr);
3119 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003120
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003121 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3122 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003123
Johan Hedberga664b5b2011-02-19 12:06:02 -03003124 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003125
3126 return err;
3127}
Johan Hedberga5c29682011-02-19 12:05:57 -03003128
Johan Hedberg744cf192011-11-08 20:40:14 +02003129int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003130 u8 link_type, u8 addr_type, __le32 value,
3131 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003132{
3133 struct mgmt_ev_user_confirm_request ev;
3134
Johan Hedberg744cf192011-11-08 20:40:14 +02003135 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003136
Johan Hedberg272d90d2012-02-09 15:26:12 +02003137 bacpy(&ev.addr.bdaddr, bdaddr);
3138 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003139 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003140 put_unaligned_le32(value, &ev.value);
3141
Johan Hedberg744cf192011-11-08 20:40:14 +02003142 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003143 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003144}
3145
Johan Hedberg272d90d2012-02-09 15:26:12 +02003146int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3147 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003148{
3149 struct mgmt_ev_user_passkey_request ev;
3150
3151 BT_DBG("%s", hdev->name);
3152
Johan Hedberg272d90d2012-02-09 15:26:12 +02003153 bacpy(&ev.addr.bdaddr, bdaddr);
3154 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003155
3156 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3157 NULL);
3158}
3159
Brian Gix0df4c182011-11-16 13:53:13 -08003160static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003161 u8 link_type, u8 addr_type, u8 status,
3162 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003163{
3164 struct pending_cmd *cmd;
3165 struct mgmt_rp_user_confirm_reply rp;
3166 int err;
3167
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003168 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003169 if (!cmd)
3170 return -ENOENT;
3171
Johan Hedberg272d90d2012-02-09 15:26:12 +02003172 bacpy(&rp.addr.bdaddr, bdaddr);
3173 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003174 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3175 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003176
Johan Hedberga664b5b2011-02-19 12:06:02 -03003177 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003178
3179 return err;
3180}
3181
Johan Hedberg744cf192011-11-08 20:40:14 +02003182int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003183 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003184{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003185 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3186 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003187}
3188
Johan Hedberg272d90d2012-02-09 15:26:12 +02003189int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3190 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003191{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003192 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3193 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003194}
Johan Hedberg2a611692011-02-19 12:06:00 -03003195
Brian Gix604086b2011-11-23 08:28:33 -08003196int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003197 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003198{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003199 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3200 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003201}
3202
Johan Hedberg272d90d2012-02-09 15:26:12 +02003203int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3204 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003205{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003206 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3207 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003208}
3209
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003210int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3211 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003212{
3213 struct mgmt_ev_auth_failed ev;
3214
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003215 bacpy(&ev.addr.bdaddr, bdaddr);
3216 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003217 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003218
Johan Hedberg744cf192011-11-08 20:40:14 +02003219 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003220}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003221
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003222int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3223{
3224 struct cmd_lookup match = { NULL, hdev };
3225 __le32 ev;
3226 int err;
3227
3228 if (status) {
3229 u8 mgmt_err = mgmt_status(status);
3230 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3231 cmd_status_rsp, &mgmt_err);
3232 return 0;
3233 }
3234
3235 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3236 &match);
3237
3238 ev = cpu_to_le32(get_current_settings(hdev));
3239 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3240
3241 if (match.sk)
3242 sock_put(match.sk);
3243
3244 return err;
3245}
3246
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003247int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3248{
3249 struct cmd_lookup match = { NULL, hdev };
3250 __le32 ev;
3251 int err;
3252
3253 if (status) {
3254 u8 mgmt_err = mgmt_status(status);
3255 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3256 cmd_status_rsp, &mgmt_err);
3257 return 0;
3258 }
3259
3260 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3261
3262 ev = cpu_to_le32(get_current_settings(hdev));
3263 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3264
3265 if (match.sk)
3266 sock_put(match.sk);
3267
3268 return err;
3269}
3270
Johan Hedberg744cf192011-11-08 20:40:14 +02003271int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003272{
3273 struct pending_cmd *cmd;
3274 struct mgmt_cp_set_local_name ev;
3275 int err;
3276
3277 memset(&ev, 0, sizeof(ev));
3278 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3279
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003280 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003281 if (!cmd)
3282 goto send_event;
3283
3284 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003285 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003286 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003287 goto failed;
3288 }
3289
Johan Hedberg744cf192011-11-08 20:40:14 +02003290 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003291
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003292 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003293 sizeof(ev));
3294 if (err < 0)
3295 goto failed;
3296
3297send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003298 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003299 cmd ? cmd->sk : NULL);
3300
3301failed:
3302 if (cmd)
3303 mgmt_pending_remove(cmd);
3304 return err;
3305}
Szymon Jancc35938b2011-03-22 13:12:21 +01003306
Johan Hedberg744cf192011-11-08 20:40:14 +02003307int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3308 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003309{
3310 struct pending_cmd *cmd;
3311 int err;
3312
Johan Hedberg744cf192011-11-08 20:40:14 +02003313 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003314
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003315 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003316 if (!cmd)
3317 return -ENOENT;
3318
3319 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003320 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003321 MGMT_OP_READ_LOCAL_OOB_DATA,
3322 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003323 } else {
3324 struct mgmt_rp_read_local_oob_data rp;
3325
3326 memcpy(rp.hash, hash, sizeof(rp.hash));
3327 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3328
Johan Hedberg744cf192011-11-08 20:40:14 +02003329 err = cmd_complete(cmd->sk, hdev->id,
3330 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003331 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003332 }
3333
3334 mgmt_pending_remove(cmd);
3335
3336 return err;
3337}
Johan Hedberge17acd42011-03-30 23:57:16 +03003338
Johan Hedberg48264f02011-11-09 13:58:58 +02003339int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003340 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003341 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003342{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003343 char buf[512];
3344 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003345 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003346
Johan Hedberg1dc06092012-01-15 21:01:23 +02003347 /* Leave 5 bytes for a potential CoD field */
3348 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003349 return -EINVAL;
3350
Johan Hedberg1dc06092012-01-15 21:01:23 +02003351 memset(buf, 0, sizeof(buf));
3352
Johan Hedberge319d2e2012-01-15 19:51:59 +02003353 bacpy(&ev->addr.bdaddr, bdaddr);
3354 ev->addr.type = link_to_mgmt(link_type, addr_type);
3355 ev->rssi = rssi;
3356 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003357
Johan Hedberg1dc06092012-01-15 21:01:23 +02003358 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003359 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003360
Johan Hedberg1dc06092012-01-15 21:01:23 +02003361 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3362 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3363 dev_class, 3);
3364
3365 put_unaligned_le16(eir_len, &ev->eir_len);
3366
3367 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003368
Johan Hedberge319d2e2012-01-15 19:51:59 +02003369 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003370}
Johan Hedberga88a9652011-03-30 13:18:12 +03003371
Johan Hedbergb644ba32012-01-17 21:48:47 +02003372int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3373 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003374{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003375 struct mgmt_ev_device_found *ev;
3376 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3377 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003378
Johan Hedbergb644ba32012-01-17 21:48:47 +02003379 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003380
Johan Hedbergb644ba32012-01-17 21:48:47 +02003381 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003382
Johan Hedbergb644ba32012-01-17 21:48:47 +02003383 bacpy(&ev->addr.bdaddr, bdaddr);
3384 ev->addr.type = link_to_mgmt(link_type, addr_type);
3385 ev->rssi = rssi;
3386
3387 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3388 name_len);
3389
3390 put_unaligned_le16(eir_len, &ev->eir_len);
3391
Johan Hedberg053c7e02012-02-04 00:06:00 +02003392 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3393 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003394}
Johan Hedberg314b2382011-04-27 10:29:57 -04003395
Andre Guedes7a135102011-11-09 17:14:25 -03003396int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003397{
3398 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003399 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003400 int err;
3401
Andre Guedes203159d2012-02-13 15:41:01 -03003402 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3403
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003404 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003405 if (!cmd)
3406 return -ENOENT;
3407
Johan Hedbergf808e162012-02-19 12:52:07 +02003408 type = hdev->discovery.type;
3409
3410 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3411 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003412 mgmt_pending_remove(cmd);
3413
3414 return err;
3415}
3416
Andre Guedese6d465c2011-11-09 17:14:26 -03003417int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3418{
3419 struct pending_cmd *cmd;
3420 int err;
3421
3422 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3423 if (!cmd)
3424 return -ENOENT;
3425
Johan Hedbergd9306502012-02-20 23:25:18 +02003426 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3427 &hdev->discovery.type,
3428 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003429 mgmt_pending_remove(cmd);
3430
3431 return err;
3432}
Johan Hedberg314b2382011-04-27 10:29:57 -04003433
Johan Hedberg744cf192011-11-08 20:40:14 +02003434int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003435{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003436 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003437 struct pending_cmd *cmd;
3438
Andre Guedes343fb142011-11-22 17:14:19 -03003439 BT_DBG("%s discovering %u", hdev->name, discovering);
3440
Johan Hedberg164a6e72011-11-01 17:06:44 +02003441 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003442 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003443 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003444 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003445
3446 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003447 u8 type = hdev->discovery.type;
3448
Johan Hedbergd9306502012-02-20 23:25:18 +02003449 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003450 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003451 mgmt_pending_remove(cmd);
3452 }
3453
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003454 memset(&ev, 0, sizeof(ev));
3455 ev.type = hdev->discovery.type;
3456 ev.discovering = discovering;
3457
3458 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003459}
Antti Julku5e762442011-08-25 16:48:02 +03003460
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003461int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003462{
3463 struct pending_cmd *cmd;
3464 struct mgmt_ev_device_blocked ev;
3465
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003466 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003467
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003468 bacpy(&ev.addr.bdaddr, bdaddr);
3469 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003470
Johan Hedberg744cf192011-11-08 20:40:14 +02003471 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3472 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003473}
3474
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003475int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003476{
3477 struct pending_cmd *cmd;
3478 struct mgmt_ev_device_unblocked ev;
3479
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003480 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003481
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003482 bacpy(&ev.addr.bdaddr, bdaddr);
3483 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003484
Johan Hedberg744cf192011-11-08 20:40:14 +02003485 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3486 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003487}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003488
3489module_param(enable_hs, bool, 0644);
3490MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3491
3492module_param(enable_le, bool, 0644);
3493MODULE_PARM_DESC(enable_le, "Enable Low Energy support");