blob: a5a2a6844aeae43950e9682e70231d189971095b [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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200228 kfree_skb(skb);
229
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300230 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200231}
232
Johan Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200417
Johan Hedberg84bde9d6c2012-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 Hedbergf7b64e692010-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 Hedberg84bde9d6c2012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200805
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300806 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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
Johan Hedberg1e163572012-02-20 23:53:46 +02001068 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1069 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1070 MGMT_STATUS_NOT_SUPPORTED);
1071 goto failed;
1072 }
1073
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001074 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1075 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1076 goto failed;
1077 }
1078
1079 val = !!cp->val;
1080
1081 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1082 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1083 goto failed;
1084 }
1085
1086 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1087 if (!cmd) {
1088 err = -ENOMEM;
1089 goto failed;
1090 }
1091
1092 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1093 if (err < 0) {
1094 mgmt_pending_remove(cmd);
1095 goto failed;
1096 }
1097
1098failed:
1099 hci_dev_unlock(hdev);
1100 hci_dev_put(hdev);
1101
1102 return err;
1103}
1104
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001105static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1106{
1107 struct mgmt_mode *cp = data;
1108 struct hci_dev *hdev;
1109 int err;
1110
1111 BT_DBG("request for hci%u", index);
1112
1113 if (len != sizeof(*cp))
1114 return cmd_status(sk, index, MGMT_OP_SET_HS,
1115 MGMT_STATUS_INVALID_PARAMS);
1116
1117 hdev = hci_dev_get(index);
1118 if (!hdev)
1119 return cmd_status(sk, index, MGMT_OP_SET_HS,
1120 MGMT_STATUS_INVALID_PARAMS);
1121
1122 if (!enable_hs) {
1123 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1124 MGMT_STATUS_NOT_SUPPORTED);
1125 goto failed;
1126 }
1127
1128 if (cp->val)
1129 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1130 else
1131 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1132
1133 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1134
1135failed:
1136 hci_dev_put(hdev);
1137 return err;
1138}
1139
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001140static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001141{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001142 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001143 struct hci_dev *hdev;
1144 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001145 int err;
1146
Szymon Janc4e51eae2011-02-25 19:05:48 +01001147 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001148
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001149 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001150 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1151 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001152
Szymon Janc4e51eae2011-02-25 19:05:48 +01001153 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001154 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001155 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1156 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001157
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001158 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001159
1160 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1161 if (!uuid) {
1162 err = -ENOMEM;
1163 goto failed;
1164 }
1165
1166 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001167 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001168
1169 list_add(&uuid->list, &hdev->uuids);
1170
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001171 err = update_class(hdev);
1172 if (err < 0)
1173 goto failed;
1174
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001175 err = update_eir(hdev);
1176 if (err < 0)
1177 goto failed;
1178
Johan Hedbergaee9b212012-02-18 15:07:59 +02001179 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001180
1181failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001182 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001183 hci_dev_put(hdev);
1184
1185 return err;
1186}
1187
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001188static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001189{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001190 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001191 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001192 struct hci_dev *hdev;
1193 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 +02001194 int err, found;
1195
Szymon Janc4e51eae2011-02-25 19:05:48 +01001196 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001197
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001198 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001199 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1200 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001201
Szymon Janc4e51eae2011-02-25 19:05:48 +01001202 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001203 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001204 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1205 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001206
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001207 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001208
1209 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1210 err = hci_uuids_clear(hdev);
1211 goto unlock;
1212 }
1213
1214 found = 0;
1215
1216 list_for_each_safe(p, n, &hdev->uuids) {
1217 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1218
1219 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1220 continue;
1221
1222 list_del(&match->list);
1223 found++;
1224 }
1225
1226 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001227 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1228 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001229 goto unlock;
1230 }
1231
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001232 err = update_class(hdev);
1233 if (err < 0)
1234 goto unlock;
1235
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001236 err = update_eir(hdev);
1237 if (err < 0)
1238 goto unlock;
1239
Johan Hedbergaee9b212012-02-18 15:07:59 +02001240 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001241
1242unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001243 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001244 hci_dev_put(hdev);
1245
1246 return err;
1247}
1248
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001249static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001250{
1251 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001252 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001253 int err;
1254
Szymon Janc4e51eae2011-02-25 19:05:48 +01001255 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001256
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001257 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001258 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1259 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001260
Szymon Janc4e51eae2011-02-25 19:05:48 +01001261 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001262 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001263 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1264 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001265
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001266 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001267
1268 hdev->major_class = cp->major;
1269 hdev->minor_class = cp->minor;
1270
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001271 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001272 hci_dev_unlock(hdev);
1273 cancel_delayed_work_sync(&hdev->service_cache);
1274 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001275 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001276 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001277
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001278 err = update_class(hdev);
1279
1280 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001281 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1282 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001283
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001284 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001285 hci_dev_put(hdev);
1286
1287 return err;
1288}
1289
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001290static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001291{
1292 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001293 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001294 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001295 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001296
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001297 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001298 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1299 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001300
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001301 key_count = get_unaligned_le16(&cp->key_count);
1302
Johan Hedberg86742e12011-11-07 23:13:38 +02001303 expected_len = sizeof(*cp) + key_count *
1304 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001305 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001306 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001307 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001308 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1309 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001310 }
1311
Szymon Janc4e51eae2011-02-25 19:05:48 +01001312 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001313 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001314 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1315 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001316
Szymon Janc4e51eae2011-02-25 19:05:48 +01001317 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001318 key_count);
1319
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001320 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001321
1322 hci_link_keys_clear(hdev);
1323
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001324 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001325
1326 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001327 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001328 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001329 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001330
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001331 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001332 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001333
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001334 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1335 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001336 }
1337
Johan Hedbergaee9b212012-02-18 15:07:59 +02001338 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001339
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001340 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001341 hci_dev_put(hdev);
1342
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001343 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001344}
1345
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001346static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1347 u8 addr_type, struct sock *skip_sk)
1348{
1349 struct mgmt_ev_device_unpaired ev;
1350
1351 bacpy(&ev.addr.bdaddr, bdaddr);
1352 ev.addr.type = addr_type;
1353
1354 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1355 skip_sk);
1356}
1357
Johan Hedberg124f6e32012-02-09 13:50:12 +02001358static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001359{
1360 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001361 struct mgmt_cp_unpair_device *cp = data;
1362 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001363 struct hci_cp_disconnect dc;
1364 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001365 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001366 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001367 int err;
1368
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001369 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001370 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001371 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001372
Szymon Janc4e51eae2011-02-25 19:05:48 +01001373 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001374 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001375 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001376 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001377
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001378 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001379
Johan Hedberga8a1d192011-11-10 15:54:38 +02001380 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001381 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1382 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001383
Johan Hedberg124f6e32012-02-09 13:50:12 +02001384 if (cp->addr.type == MGMT_ADDR_BREDR)
1385 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1386 else
1387 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001388
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001389 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001390 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001391 goto unlock;
1392 }
1393
Johan Hedberga8a1d192011-11-10 15:54:38 +02001394 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001395 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1396 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001397 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001398 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001399 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001400
Johan Hedberg124f6e32012-02-09 13:50:12 +02001401 if (cp->addr.type == MGMT_ADDR_BREDR)
1402 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1403 &cp->addr.bdaddr);
1404 else
1405 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1406 &cp->addr.bdaddr);
1407
Johan Hedberga8a1d192011-11-10 15:54:38 +02001408 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001409 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1410 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001411 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001412 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001413 }
1414
Johan Hedberg124f6e32012-02-09 13:50:12 +02001415 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1416 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001417 if (!cmd) {
1418 err = -ENOMEM;
1419 goto unlock;
1420 }
1421
1422 put_unaligned_le16(conn->handle, &dc.handle);
1423 dc.reason = 0x13; /* Remote User Terminated Connection */
1424 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1425 if (err < 0)
1426 mgmt_pending_remove(cmd);
1427
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001428unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001429 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001430 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1431 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001432 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001433 hci_dev_put(hdev);
1434
1435 return err;
1436}
1437
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001438static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001439{
1440 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001441 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001442 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001443 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001444 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001445 int err;
1446
1447 BT_DBG("");
1448
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001449 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001450 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1451 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001452
Szymon Janc4e51eae2011-02-25 19:05:48 +01001453 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001454 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001455 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1456 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001457
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001458 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001459
1460 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001461 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1462 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001463 goto failed;
1464 }
1465
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001466 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001467 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1468 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001469 goto failed;
1470 }
1471
Johan Hedberg88c3df12012-02-09 14:27:38 +02001472 if (cp->addr.type == MGMT_ADDR_BREDR)
1473 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1474 else
1475 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001476
Johan Hedberg8962ee72011-01-20 12:40:27 +02001477 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001478 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1479 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001480 goto failed;
1481 }
1482
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001483 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001484 if (!cmd) {
1485 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001486 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001487 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001488
1489 put_unaligned_le16(conn->handle, &dc.handle);
1490 dc.reason = 0x13; /* Remote User Terminated Connection */
1491
1492 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1493 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001494 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001495
1496failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001497 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001498 hci_dev_put(hdev);
1499
1500 return err;
1501}
1502
Johan Hedberg48264f02011-11-09 13:58:58 +02001503static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001504{
1505 switch (link_type) {
1506 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001507 switch (addr_type) {
1508 case ADDR_LE_DEV_PUBLIC:
1509 return MGMT_ADDR_LE_PUBLIC;
1510 case ADDR_LE_DEV_RANDOM:
1511 return MGMT_ADDR_LE_RANDOM;
1512 default:
1513 return MGMT_ADDR_INVALID;
1514 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001515 case ACL_LINK:
1516 return MGMT_ADDR_BREDR;
1517 default:
1518 return MGMT_ADDR_INVALID;
1519 }
1520}
1521
Szymon Janc8ce62842011-03-01 16:55:32 +01001522static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001523{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001524 struct mgmt_rp_get_connections *rp;
1525 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001526 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001527 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001528 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001529 int i, err;
1530
1531 BT_DBG("");
1532
Szymon Janc4e51eae2011-02-25 19:05:48 +01001533 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001534 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001535 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1536 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001538 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001539
1540 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001541 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1542 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1543 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001544 }
1545
Johan Hedberg4c659c32011-11-07 23:13:39 +02001546 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001547 rp = kmalloc(rp_len, GFP_ATOMIC);
1548 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001549 err = -ENOMEM;
1550 goto unlock;
1551 }
1552
Johan Hedberg2784eb42011-01-21 13:56:35 +02001553 put_unaligned_le16(count, &rp->conn_count);
1554
Johan Hedberg2784eb42011-01-21 13:56:35 +02001555 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001556 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001557 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1558 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001559 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001560 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001561 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1562 continue;
1563 i++;
1564 }
1565
1566 /* Recalculate length in case of filtered SCO connections, etc */
1567 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001568
Johan Hedbergaee9b212012-02-18 15:07:59 +02001569 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001570
1571unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001572 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001573 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001574 hci_dev_put(hdev);
1575 return err;
1576}
1577
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001578static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1579 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1580{
1581 struct pending_cmd *cmd;
1582 int err;
1583
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001584 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001585 sizeof(*cp));
1586 if (!cmd)
1587 return -ENOMEM;
1588
Johan Hedbergd8457692012-02-17 14:24:57 +02001589 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1590 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001591 if (err < 0)
1592 mgmt_pending_remove(cmd);
1593
1594 return err;
1595}
1596
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001597static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001598{
1599 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001600 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001601 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001602 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001603 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001604 int err;
1605
1606 BT_DBG("");
1607
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001608 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001609 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1610 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001611
Szymon Janc4e51eae2011-02-25 19:05:48 +01001612 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001613 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001614 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1615 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001616
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001617 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001618
1619 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001620 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1621 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001622 goto failed;
1623 }
1624
Johan Hedbergd8457692012-02-17 14:24:57 +02001625 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001626 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001627 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1628 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001629 goto failed;
1630 }
1631
1632 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001633 struct mgmt_cp_pin_code_neg_reply ncp;
1634
1635 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001636
1637 BT_ERR("PIN code is not 16 bytes long");
1638
1639 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1640 if (err >= 0)
1641 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001642 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001643
1644 goto failed;
1645 }
1646
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001647 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1648 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001649 if (!cmd) {
1650 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001651 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001652 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001653
Johan Hedbergd8457692012-02-17 14:24:57 +02001654 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001655 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001656 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001657
1658 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1659 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001660 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001661
1662failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001663 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001664 hci_dev_put(hdev);
1665
1666 return err;
1667}
1668
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001669static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001670{
1671 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001672 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001673 int err;
1674
1675 BT_DBG("");
1676
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001677 if (len != sizeof(*cp))
1678 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001679 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001680
Szymon Janc4e51eae2011-02-25 19:05:48 +01001681 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001682 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001683 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001684 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001685
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001686 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001687
1688 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001689 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001690 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001691 goto failed;
1692 }
1693
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001694 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001695
1696failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001697 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001698 hci_dev_put(hdev);
1699
1700 return err;
1701}
1702
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001703static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001704{
1705 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001706 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001707
1708 BT_DBG("");
1709
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001710 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001711 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1712 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001713
Szymon Janc4e51eae2011-02-25 19:05:48 +01001714 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001715 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001716 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1717 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001718
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001719 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001720
1721 hdev->io_capability = cp->io_capability;
1722
1723 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001724 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001725
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001726 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001727 hci_dev_put(hdev);
1728
Johan Hedbergaee9b212012-02-18 15:07:59 +02001729 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001730}
1731
Johan Hedberge9a416b2011-02-19 12:05:56 -03001732static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1733{
1734 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001735 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001736
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001737 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001738 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1739 continue;
1740
Johan Hedberge9a416b2011-02-19 12:05:56 -03001741 if (cmd->user_data != conn)
1742 continue;
1743
1744 return cmd;
1745 }
1746
1747 return NULL;
1748}
1749
1750static void pairing_complete(struct pending_cmd *cmd, u8 status)
1751{
1752 struct mgmt_rp_pair_device rp;
1753 struct hci_conn *conn = cmd->user_data;
1754
Johan Hedbergba4e5642011-11-11 00:07:34 +02001755 bacpy(&rp.addr.bdaddr, &conn->dst);
1756 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001757
Johan Hedbergaee9b212012-02-18 15:07:59 +02001758 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1759 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001760
1761 /* So we don't get further callbacks for this connection */
1762 conn->connect_cfm_cb = NULL;
1763 conn->security_cfm_cb = NULL;
1764 conn->disconn_cfm_cb = NULL;
1765
1766 hci_conn_put(conn);
1767
Johan Hedberga664b5b2011-02-19 12:06:02 -03001768 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001769}
1770
1771static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1772{
1773 struct pending_cmd *cmd;
1774
1775 BT_DBG("status %u", status);
1776
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001777 cmd = find_pairing(conn);
1778 if (!cmd)
1779 BT_DBG("Unable to find a pending command");
1780 else
Johan Hedberge2113262012-02-18 15:20:03 +02001781 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001782}
1783
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001784static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001785{
1786 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001787 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001788 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001789 struct pending_cmd *cmd;
1790 u8 sec_level, auth_type;
1791 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001792 int err;
1793
1794 BT_DBG("");
1795
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001796 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001797 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1798 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001799
Szymon Janc4e51eae2011-02-25 19:05:48 +01001800 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001801 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001802 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1803 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001804
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001805 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001806
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001807 sec_level = BT_SECURITY_MEDIUM;
1808 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001809 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001810 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001811 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001812
Johan Hedbergba4e5642011-11-11 00:07:34 +02001813 if (cp->addr.type == MGMT_ADDR_BREDR)
1814 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001815 auth_type);
1816 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001817 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001818 auth_type);
1819
Johan Hedberg1425acb2011-11-11 00:07:35 +02001820 memset(&rp, 0, sizeof(rp));
1821 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1822 rp.addr.type = cp->addr.type;
1823
Ville Tervo30e76272011-02-22 16:10:53 -03001824 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001825 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1826 MGMT_STATUS_CONNECT_FAILED,
1827 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001828 goto unlock;
1829 }
1830
1831 if (conn->connect_cfm_cb) {
1832 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001833 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1834 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001835 goto unlock;
1836 }
1837
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001838 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001839 if (!cmd) {
1840 err = -ENOMEM;
1841 hci_conn_put(conn);
1842 goto unlock;
1843 }
1844
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001845 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001846 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001847 conn->connect_cfm_cb = pairing_complete_cb;
1848
Johan Hedberge9a416b2011-02-19 12:05:56 -03001849 conn->security_cfm_cb = pairing_complete_cb;
1850 conn->disconn_cfm_cb = pairing_complete_cb;
1851 conn->io_capability = cp->io_cap;
1852 cmd->user_data = conn;
1853
1854 if (conn->state == BT_CONNECTED &&
1855 hci_conn_security(conn, sec_level, auth_type))
1856 pairing_complete(cmd, 0);
1857
1858 err = 0;
1859
1860unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001861 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001862 hci_dev_put(hdev);
1863
1864 return err;
1865}
1866
Johan Hedberg28424702012-02-02 04:02:29 +02001867static int cancel_pair_device(struct sock *sk, u16 index,
1868 unsigned char *data, u16 len)
1869{
1870 struct mgmt_addr_info *addr = (void *) data;
1871 struct hci_dev *hdev;
1872 struct pending_cmd *cmd;
1873 struct hci_conn *conn;
1874 int err;
1875
1876 BT_DBG("");
1877
1878 if (len != sizeof(*addr))
1879 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1880 MGMT_STATUS_INVALID_PARAMS);
1881
1882 hdev = hci_dev_get(index);
1883 if (!hdev)
1884 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1885 MGMT_STATUS_INVALID_PARAMS);
1886
1887 hci_dev_lock(hdev);
1888
1889 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1890 if (!cmd) {
1891 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1892 MGMT_STATUS_INVALID_PARAMS);
1893 goto unlock;
1894 }
1895
1896 conn = cmd->user_data;
1897
1898 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1899 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1900 MGMT_STATUS_INVALID_PARAMS);
1901 goto unlock;
1902 }
1903
1904 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1905
Johan Hedbergaee9b212012-02-18 15:07:59 +02001906 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001907 sizeof(*addr));
1908unlock:
1909 hci_dev_unlock(hdev);
1910 hci_dev_put(hdev);
1911
1912 return err;
1913}
1914
Brian Gix0df4c182011-11-16 13:53:13 -08001915static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001916 u8 type, u16 mgmt_op, u16 hci_op,
1917 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001918{
Johan Hedberga5c29682011-02-19 12:05:57 -03001919 struct pending_cmd *cmd;
1920 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001921 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001922 int err;
1923
Szymon Janc4e51eae2011-02-25 19:05:48 +01001924 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001925 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001926 return cmd_status(sk, index, mgmt_op,
1927 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001928
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001929 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001930
Johan Hedberga5c29682011-02-19 12:05:57 -03001931 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001932 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1933 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001934 }
1935
Johan Hedberg272d90d2012-02-09 15:26:12 +02001936 if (type == MGMT_ADDR_BREDR)
1937 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1938 else
Brian Gix47c15e22011-11-16 13:53:14 -08001939 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001940
Johan Hedberg272d90d2012-02-09 15:26:12 +02001941 if (!conn) {
1942 err = cmd_status(sk, index, mgmt_op,
1943 MGMT_STATUS_NOT_CONNECTED);
1944 goto done;
1945 }
1946
1947 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001948 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001949 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001950
Brian Gix5fe57d92011-12-21 16:12:13 -08001951 if (!err)
1952 err = cmd_status(sk, index, mgmt_op,
1953 MGMT_STATUS_SUCCESS);
1954 else
1955 err = cmd_status(sk, index, mgmt_op,
1956 MGMT_STATUS_FAILED);
1957
Brian Gix47c15e22011-11-16 13:53:14 -08001958 goto done;
1959 }
1960
Brian Gix0df4c182011-11-16 13:53:13 -08001961 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001962 if (!cmd) {
1963 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001964 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001965 }
1966
Brian Gix0df4c182011-11-16 13:53:13 -08001967 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001968 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1969 struct hci_cp_user_passkey_reply cp;
1970
1971 bacpy(&cp.bdaddr, bdaddr);
1972 cp.passkey = passkey;
1973 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1974 } else
1975 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1976
Johan Hedberga664b5b2011-02-19 12:06:02 -03001977 if (err < 0)
1978 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001979
Brian Gix0df4c182011-11-16 13:53:13 -08001980done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001981 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001982 hci_dev_put(hdev);
1983
1984 return err;
1985}
1986
Brian Gix0df4c182011-11-16 13:53:13 -08001987static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1988{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001989 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001990
1991 BT_DBG("");
1992
1993 if (len != sizeof(*cp))
1994 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1995 MGMT_STATUS_INVALID_PARAMS);
1996
Johan Hedberg272d90d2012-02-09 15:26:12 +02001997 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1998 MGMT_OP_USER_CONFIRM_REPLY,
1999 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002000}
2001
2002static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2003 u16 len)
2004{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002005 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002006
2007 BT_DBG("");
2008
2009 if (len != sizeof(*cp))
2010 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2011 MGMT_STATUS_INVALID_PARAMS);
2012
Johan Hedberg272d90d2012-02-09 15:26:12 +02002013 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2014 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2015 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002016}
2017
Brian Gix604086b2011-11-23 08:28:33 -08002018static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2019{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002020 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002021
2022 BT_DBG("");
2023
2024 if (len != sizeof(*cp))
2025 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2026 EINVAL);
2027
Johan Hedberg272d90d2012-02-09 15:26:12 +02002028 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2029 MGMT_OP_USER_PASSKEY_REPLY,
2030 HCI_OP_USER_PASSKEY_REPLY,
2031 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002032}
2033
2034static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2035 u16 len)
2036{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002037 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002038
2039 BT_DBG("");
2040
2041 if (len != sizeof(*cp))
2042 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2043 EINVAL);
2044
Johan Hedberg272d90d2012-02-09 15:26:12 +02002045 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2046 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2047 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002048}
2049
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002050static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002051 u16 len)
2052{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002053 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002054 struct hci_cp_write_local_name hci_cp;
2055 struct hci_dev *hdev;
2056 struct pending_cmd *cmd;
2057 int err;
2058
2059 BT_DBG("");
2060
2061 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002062 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2063 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002064
2065 hdev = hci_dev_get(index);
2066 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002067 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2068 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002069
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002070 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002071
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002072 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2073 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002074 if (!cmd) {
2075 err = -ENOMEM;
2076 goto failed;
2077 }
2078
2079 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2080 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2081 &hci_cp);
2082 if (err < 0)
2083 mgmt_pending_remove(cmd);
2084
2085failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002086 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002087 hci_dev_put(hdev);
2088
2089 return err;
2090}
2091
Szymon Jancc35938b2011-03-22 13:12:21 +01002092static int read_local_oob_data(struct sock *sk, u16 index)
2093{
2094 struct hci_dev *hdev;
2095 struct pending_cmd *cmd;
2096 int err;
2097
2098 BT_DBG("hci%u", index);
2099
2100 hdev = hci_dev_get(index);
2101 if (!hdev)
2102 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002103 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002104
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002105 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002106
2107 if (!test_bit(HCI_UP, &hdev->flags)) {
2108 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002109 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002110 goto unlock;
2111 }
2112
2113 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2114 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002115 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002116 goto unlock;
2117 }
2118
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002119 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002120 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2121 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002122 goto unlock;
2123 }
2124
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002125 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002126 if (!cmd) {
2127 err = -ENOMEM;
2128 goto unlock;
2129 }
2130
2131 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2132 if (err < 0)
2133 mgmt_pending_remove(cmd);
2134
2135unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002136 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002137 hci_dev_put(hdev);
2138
2139 return err;
2140}
2141
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002142static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2143 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002144{
2145 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002146 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002147 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002148 int err;
2149
2150 BT_DBG("hci%u ", index);
2151
2152 if (len != sizeof(*cp))
2153 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002154 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002155
2156 hdev = hci_dev_get(index);
2157 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002158 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2159 MGMT_STATUS_INVALID_PARAMS,
2160 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002161
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002162 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002163
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002164 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002165 cp->randomizer);
2166 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002167 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002168 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002169 status = 0;
2170
2171 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2172 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002173
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002174 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002175 hci_dev_put(hdev);
2176
2177 return err;
2178}
2179
2180static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002181 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002182{
2183 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002184 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002185 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002186 int err;
2187
2188 BT_DBG("hci%u ", index);
2189
2190 if (len != sizeof(*cp))
2191 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002192 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002193
2194 hdev = hci_dev_get(index);
2195 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002196 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2197 MGMT_STATUS_INVALID_PARAMS,
2198 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002199
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002200 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002201
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002202 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002203 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002204 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002205 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002206 status = 0;
2207
2208 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2209 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002210
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002211 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002212 hci_dev_put(hdev);
2213
2214 return err;
2215}
2216
Andre Guedes5e0452c2012-02-17 20:39:38 -03002217static int discovery(struct hci_dev *hdev)
2218{
2219 int err;
2220
2221 if (lmp_host_le_capable(hdev)) {
2222 if (lmp_bredr_capable(hdev)) {
2223 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2224 LE_SCAN_INT, LE_SCAN_WIN,
2225 LE_SCAN_TIMEOUT_BREDR_LE);
2226 } else {
2227 hdev->discovery.type = DISCOV_TYPE_LE;
2228 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2229 LE_SCAN_INT, LE_SCAN_WIN,
2230 LE_SCAN_TIMEOUT_LE_ONLY);
2231 }
2232 } else {
2233 hdev->discovery.type = DISCOV_TYPE_BREDR;
2234 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2235 }
2236
2237 return err;
2238}
2239
2240int mgmt_interleaved_discovery(struct hci_dev *hdev)
2241{
2242 int err;
2243
2244 BT_DBG("%s", hdev->name);
2245
2246 hci_dev_lock(hdev);
2247
2248 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2249 if (err < 0)
2250 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2251
2252 hci_dev_unlock(hdev);
2253
2254 return err;
2255}
2256
Johan Hedberg450dfda2011-11-12 11:58:22 +02002257static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002258 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002259{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002260 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002261 struct pending_cmd *cmd;
2262 struct hci_dev *hdev;
2263 int err;
2264
2265 BT_DBG("hci%u", index);
2266
Johan Hedberg450dfda2011-11-12 11:58:22 +02002267 if (len != sizeof(*cp))
2268 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2269 MGMT_STATUS_INVALID_PARAMS);
2270
Johan Hedberg14a53662011-04-27 10:29:56 -04002271 hdev = hci_dev_get(index);
2272 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002273 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2274 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002275
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002276 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002277
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002278 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002279 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2280 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002281 goto failed;
2282 }
2283
Johan Hedbergff9ef572012-01-04 14:23:45 +02002284 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2285 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2286 MGMT_STATUS_BUSY);
2287 goto failed;
2288 }
2289
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002290 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002291 if (!cmd) {
2292 err = -ENOMEM;
2293 goto failed;
2294 }
2295
Andre Guedes4aab14e2012-02-17 20:39:36 -03002296 hdev->discovery.type = cp->type;
2297
2298 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002299 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002300 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002301 break;
2302
2303 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002304 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2305 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002306 break;
2307
Andre Guedes5e0452c2012-02-17 20:39:38 -03002308 case DISCOV_TYPE_INTERLEAVED:
2309 err = discovery(hdev);
2310 break;
2311
Andre Guedesf39799f2012-02-17 20:39:35 -03002312 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002313 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002314 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002315
Johan Hedberg14a53662011-04-27 10:29:56 -04002316 if (err < 0)
2317 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002318 else
2319 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002320
2321failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002322 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002323 hci_dev_put(hdev);
2324
2325 return err;
2326}
2327
Johan Hedbergd9306502012-02-20 23:25:18 +02002328static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002329{
Johan Hedbergd9306502012-02-20 23:25:18 +02002330 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002331 struct hci_dev *hdev;
2332 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002333 struct hci_cp_remote_name_req_cancel cp;
2334 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002335 int err;
2336
2337 BT_DBG("hci%u", index);
2338
Johan Hedbergd9306502012-02-20 23:25:18 +02002339 if (len != sizeof(*mgmt_cp))
2340 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2341 MGMT_STATUS_INVALID_PARAMS);
2342
Johan Hedberg14a53662011-04-27 10:29:56 -04002343 hdev = hci_dev_get(index);
2344 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002345 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2346 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002347
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002348 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002349
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002350 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002351 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2352 MGMT_STATUS_REJECTED,
2353 &mgmt_cp->type, sizeof(mgmt_cp->type));
2354 goto unlock;
2355 }
2356
2357 if (hdev->discovery.type != mgmt_cp->type) {
2358 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2359 MGMT_STATUS_INVALID_PARAMS,
2360 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002361 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002362 }
2363
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002364 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002365 if (!cmd) {
2366 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002367 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002368 }
2369
Andre Guedes343f9352012-02-17 20:39:37 -03002370 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002371 err = hci_cancel_inquiry(hdev);
2372 if (err < 0)
2373 mgmt_pending_remove(cmd);
2374 else
2375 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2376 goto unlock;
2377 }
2378
2379 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2380 if (!e) {
2381 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002382 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002383 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002384 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2385 goto unlock;
2386 }
2387
2388 bacpy(&cp.bdaddr, &e->data.bdaddr);
2389 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2390 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002391 if (err < 0)
2392 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002393 else
2394 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002395
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002396unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002397 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002398 hci_dev_put(hdev);
2399
2400 return err;
2401}
2402
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002403static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002404{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002405 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002406 struct inquiry_entry *e;
2407 struct hci_dev *hdev;
2408 int err;
2409
2410 BT_DBG("hci%u", index);
2411
2412 if (len != sizeof(*cp))
2413 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2414 MGMT_STATUS_INVALID_PARAMS);
2415
2416 hdev = hci_dev_get(index);
2417 if (!hdev)
2418 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2419 MGMT_STATUS_INVALID_PARAMS);
2420
2421 hci_dev_lock(hdev);
2422
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002423 if (!hci_discovery_active(hdev)) {
2424 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2425 MGMT_STATUS_FAILED);
2426 goto failed;
2427 }
2428
Johan Hedberga198e7b2012-02-17 14:27:06 +02002429 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002430 if (!e) {
2431 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2432 MGMT_STATUS_INVALID_PARAMS);
2433 goto failed;
2434 }
2435
2436 if (cp->name_known) {
2437 e->name_state = NAME_KNOWN;
2438 list_del(&e->list);
2439 } else {
2440 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002441 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002442 }
2443
2444 err = 0;
2445
2446failed:
2447 hci_dev_unlock(hdev);
2448
2449 return err;
2450}
2451
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002452static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002453{
2454 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002455 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002456 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002457 int err;
2458
2459 BT_DBG("hci%u", index);
2460
Antti Julku7fbec222011-06-15 12:01:15 +03002461 if (len != sizeof(*cp))
2462 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002463 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002464
2465 hdev = hci_dev_get(index);
2466 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002467 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2468 MGMT_STATUS_INVALID_PARAMS,
2469 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002470
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002471 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002472
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002473 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002474 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002475 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002476 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002477 status = 0;
2478
2479 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2480 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002481
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002482 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002483 hci_dev_put(hdev);
2484
2485 return err;
2486}
2487
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002488static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002489{
2490 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002491 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002492 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002493 int err;
2494
2495 BT_DBG("hci%u", index);
2496
Antti Julku7fbec222011-06-15 12:01:15 +03002497 if (len != sizeof(*cp))
2498 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002499 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002500
2501 hdev = hci_dev_get(index);
2502 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002503 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2504 MGMT_STATUS_INVALID_PARAMS,
2505 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002506
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002507 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002508
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002509 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002510 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002511 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002512 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002513 status = 0;
2514
2515 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2516 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002517
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002518 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002519 hci_dev_put(hdev);
2520
2521 return err;
2522}
2523
Antti Julkuf6422ec2011-06-22 13:11:56 +03002524static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002525 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002526{
2527 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002528 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002529 struct hci_cp_write_page_scan_activity acp;
2530 u8 type;
2531 int err;
2532
2533 BT_DBG("hci%u", index);
2534
2535 if (len != sizeof(*cp))
2536 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002537 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002538
2539 hdev = hci_dev_get(index);
2540 if (!hdev)
2541 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002542 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002543
2544 hci_dev_lock(hdev);
2545
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002546 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002547 type = PAGE_SCAN_TYPE_INTERLACED;
2548 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2549 } else {
2550 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2551 acp.interval = 0x0800; /* default 1.28 sec page scan */
2552 }
2553
2554 acp.window = 0x0012; /* default 11.25 msec page scan window */
2555
2556 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2557 sizeof(acp), &acp);
2558 if (err < 0) {
2559 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002560 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002561 goto done;
2562 }
2563
2564 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2565 if (err < 0) {
2566 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002567 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002568 goto done;
2569 }
2570
Johan Hedbergaee9b212012-02-18 15:07:59 +02002571 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2572 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002573done:
2574 hci_dev_unlock(hdev);
2575 hci_dev_put(hdev);
2576
2577 return err;
2578}
2579
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002580static int load_long_term_keys(struct sock *sk, u16 index,
2581 void *cp_data, u16 len)
2582{
2583 struct hci_dev *hdev;
2584 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2585 u16 key_count, expected_len;
2586 int i;
2587
2588 if (len < sizeof(*cp))
2589 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2590 EINVAL);
2591
2592 key_count = get_unaligned_le16(&cp->key_count);
2593
2594 expected_len = sizeof(*cp) + key_count *
2595 sizeof(struct mgmt_ltk_info);
2596 if (expected_len != len) {
2597 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2598 len, expected_len);
2599 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2600 EINVAL);
2601 }
2602
2603 hdev = hci_dev_get(index);
2604 if (!hdev)
2605 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2606 ENODEV);
2607
2608 BT_DBG("hci%u key_count %u", index, key_count);
2609
2610 hci_dev_lock(hdev);
2611
2612 hci_smp_ltks_clear(hdev);
2613
2614 for (i = 0; i < key_count; i++) {
2615 struct mgmt_ltk_info *key = &cp->keys[i];
2616 u8 type;
2617
2618 if (key->master)
2619 type = HCI_SMP_LTK;
2620 else
2621 type = HCI_SMP_LTK_SLAVE;
2622
2623 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2624 type, 0, key->authenticated, key->val,
2625 key->enc_size, key->ediv, key->rand);
2626 }
2627
2628 hci_dev_unlock(hdev);
2629 hci_dev_put(hdev);
2630
2631 return 0;
2632}
2633
Johan Hedberg03811012010-12-08 00:21:06 +02002634int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2635{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002636 void *buf;
2637 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002638 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002639 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002640 int err;
2641
2642 BT_DBG("got %zu bytes", msglen);
2643
2644 if (msglen < sizeof(*hdr))
2645 return -EINVAL;
2646
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002647 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002648 if (!buf)
2649 return -ENOMEM;
2650
2651 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2652 err = -EFAULT;
2653 goto done;
2654 }
2655
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002656 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002657 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002658 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002659 len = get_unaligned_le16(&hdr->len);
2660
2661 if (len != msglen - sizeof(*hdr)) {
2662 err = -EINVAL;
2663 goto done;
2664 }
2665
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002666 cp = buf + sizeof(*hdr);
2667
Johan Hedberg03811012010-12-08 00:21:06 +02002668 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002669 case MGMT_OP_READ_VERSION:
2670 err = read_version(sk);
2671 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002672 case MGMT_OP_READ_COMMANDS:
2673 err = read_commands(sk);
2674 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002675 case MGMT_OP_READ_INDEX_LIST:
2676 err = read_index_list(sk);
2677 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002678 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002679 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002680 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002681 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002682 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002683 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002684 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002685 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002686 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002687 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002688 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002689 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002690 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002691 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002692 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002693 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002694 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002695 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002696 case MGMT_OP_SET_LINK_SECURITY:
2697 err = set_link_security(sk, index, cp, len);
2698 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002699 case MGMT_OP_SET_SSP:
2700 err = set_ssp(sk, index, cp, len);
2701 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002702 case MGMT_OP_SET_HS:
2703 err = set_hs(sk, index, cp, len);
2704 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002705 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002706 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002707 break;
2708 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002709 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002710 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002711 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002712 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002713 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002714 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002715 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002716 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002717 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002718 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002719 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002720 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002721 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002722 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002723 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002724 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002725 break;
2726 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002727 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002728 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002729 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002730 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002731 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002732 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002733 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002734 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002735 case MGMT_OP_CANCEL_PAIR_DEVICE:
2736 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2737 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002738 case MGMT_OP_UNPAIR_DEVICE:
2739 err = unpair_device(sk, index, cp, len);
2740 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002741 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002742 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002743 break;
2744 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002745 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002746 break;
Brian Gix604086b2011-11-23 08:28:33 -08002747 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002748 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002749 break;
2750 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002751 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002752 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002753 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002754 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002755 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002756 case MGMT_OP_READ_LOCAL_OOB_DATA:
2757 err = read_local_oob_data(sk, index);
2758 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002759 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002760 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002761 break;
2762 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002763 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002764 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002765 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002766 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002767 break;
2768 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002769 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002770 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002771 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002772 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002773 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002774 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002775 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002776 break;
2777 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002778 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002779 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002780 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2781 err = load_long_term_keys(sk, index, cp, len);
2782 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002783 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002784 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002785 err = cmd_status(sk, index, opcode,
2786 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002787 break;
2788 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002789
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002790 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002791 goto done;
2792
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002793 err = msglen;
2794
2795done:
2796 kfree(buf);
2797 return err;
2798}
2799
Johan Hedbergb24752f2011-11-03 14:40:33 +02002800static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2801{
2802 u8 *status = data;
2803
2804 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2805 mgmt_pending_remove(cmd);
2806}
2807
Johan Hedberg744cf192011-11-08 20:40:14 +02002808int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002809{
Johan Hedberg744cf192011-11-08 20:40:14 +02002810 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002811}
2812
Johan Hedberg744cf192011-11-08 20:40:14 +02002813int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002814{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002815 u8 status = ENODEV;
2816
Johan Hedberg744cf192011-11-08 20:40:14 +02002817 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002818
Johan Hedberg744cf192011-11-08 20:40:14 +02002819 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002820}
2821
2822struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002823 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002824 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002825};
2826
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002827static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002828{
Johan Hedberg03811012010-12-08 00:21:06 +02002829 struct cmd_lookup *match = data;
2830
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002831 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002832
2833 list_del(&cmd->list);
2834
2835 if (match->sk == NULL) {
2836 match->sk = cmd->sk;
2837 sock_hold(match->sk);
2838 }
2839
2840 mgmt_pending_free(cmd);
2841}
2842
Johan Hedberg744cf192011-11-08 20:40:14 +02002843int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002844{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002845 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002846 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002847 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002848
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002849 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002850
Johan Hedbergb24752f2011-11-03 14:40:33 +02002851 if (!powered) {
2852 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002853 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002854 }
2855
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002856 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002857
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002858 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002859 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002860
2861 if (match.sk)
2862 sock_put(match.sk);
2863
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002864 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002865}
2866
Johan Hedberg744cf192011-11-08 20:40:14 +02002867int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002868{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002869 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002870 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002871 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002872
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002873 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002874
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002875 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002876
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002877 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002878 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002879 if (match.sk)
2880 sock_put(match.sk);
2881
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002882 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002883}
2884
Johan Hedberg744cf192011-11-08 20:40:14 +02002885int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002886{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002887 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002888 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002889 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002890
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002891 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2892 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002893
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002894 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002895
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002896 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002897
2898 if (match.sk)
2899 sock_put(match.sk);
2900
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002901 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002902}
2903
Johan Hedberg744cf192011-11-08 20:40:14 +02002904int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002905{
Johan Hedbergca69b792011-11-11 18:10:00 +02002906 u8 mgmt_err = mgmt_status(status);
2907
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002908 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002909 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002910 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002911
2912 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002913 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002914 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002915
2916 return 0;
2917}
2918
Johan Hedberg744cf192011-11-08 20:40:14 +02002919int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2920 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002921{
Johan Hedberg86742e12011-11-07 23:13:38 +02002922 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002923
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002924 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002925
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002926 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002927 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2928 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002929 ev.key.type = key->type;
2930 memcpy(ev.key.val, key->val, 16);
2931 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002932
Johan Hedberg744cf192011-11-08 20:40:14 +02002933 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002934}
Johan Hedbergf7520542011-01-20 12:34:39 +02002935
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002936int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2937{
2938 struct mgmt_ev_new_long_term_key ev;
2939
2940 memset(&ev, 0, sizeof(ev));
2941
2942 ev.store_hint = persistent;
2943 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2944 ev.key.addr.type = key->bdaddr_type;
2945 ev.key.authenticated = key->authenticated;
2946 ev.key.enc_size = key->enc_size;
2947 ev.key.ediv = key->ediv;
2948
2949 if (key->type == HCI_SMP_LTK)
2950 ev.key.master = 1;
2951
2952 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2953 memcpy(ev.key.val, key->val, sizeof(key->val));
2954
2955 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2956 &ev, sizeof(ev), NULL);
2957}
2958
Johan Hedbergafc747a2012-01-15 18:11:07 +02002959int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002960 u8 addr_type, u8 *name, u8 name_len,
2961 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002962{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002963 char buf[512];
2964 struct mgmt_ev_device_connected *ev = (void *) buf;
2965 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002966
Johan Hedbergb644ba32012-01-17 21:48:47 +02002967 bacpy(&ev->addr.bdaddr, bdaddr);
2968 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002969
Johan Hedbergb644ba32012-01-17 21:48:47 +02002970 if (name_len > 0)
2971 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2972 name, name_len);
2973
2974 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2975 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2976 EIR_CLASS_OF_DEV, dev_class, 3);
2977
2978 put_unaligned_le16(eir_len, &ev->eir_len);
2979
2980 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2981 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002982}
2983
Johan Hedberg8962ee72011-01-20 12:40:27 +02002984static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2985{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002986 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002987 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002988 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002989
Johan Hedberg88c3df12012-02-09 14:27:38 +02002990 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2991 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002992
Johan Hedbergaee9b212012-02-18 15:07:59 +02002993 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
2994 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002995
2996 *sk = cmd->sk;
2997 sock_hold(*sk);
2998
Johan Hedberga664b5b2011-02-19 12:06:02 -03002999 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003000}
3001
Johan Hedberg124f6e32012-02-09 13:50:12 +02003002static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003003{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003004 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003005 struct mgmt_cp_unpair_device *cp = cmd->param;
3006 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003007
3008 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003009 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3010 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003011
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003012 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3013
Johan Hedbergaee9b212012-02-18 15:07:59 +02003014 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003015
3016 mgmt_pending_remove(cmd);
3017}
3018
Johan Hedbergafc747a2012-01-15 18:11:07 +02003019int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3020 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003021{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003022 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003023 struct sock *sk = NULL;
3024 int err;
3025
Johan Hedberg744cf192011-11-08 20:40:14 +02003026 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003027
Johan Hedbergf7520542011-01-20 12:34:39 +02003028 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003029 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003030
Johan Hedbergafc747a2012-01-15 18:11:07 +02003031 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3032 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003033
3034 if (sk)
3035 sock_put(sk);
3036
Johan Hedberg124f6e32012-02-09 13:50:12 +02003037 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003038 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003039
Johan Hedberg8962ee72011-01-20 12:40:27 +02003040 return err;
3041}
3042
Johan Hedberg88c3df12012-02-09 14:27:38 +02003043int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3044 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003045{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003046 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003047 struct pending_cmd *cmd;
3048 int err;
3049
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003050 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003051 if (!cmd)
3052 return -ENOENT;
3053
Johan Hedberg88c3df12012-02-09 14:27:38 +02003054 bacpy(&rp.addr.bdaddr, bdaddr);
3055 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003056
Johan Hedberg88c3df12012-02-09 14:27:38 +02003057 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003058 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003059
Johan Hedberga664b5b2011-02-19 12:06:02 -03003060 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003061
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003062 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3063 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003064 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003065}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003066
Johan Hedberg48264f02011-11-09 13:58:58 +02003067int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3068 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003069{
3070 struct mgmt_ev_connect_failed ev;
3071
Johan Hedberg4c659c32011-11-07 23:13:39 +02003072 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003073 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003074 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003075
Johan Hedberg744cf192011-11-08 20:40:14 +02003076 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003077}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003078
Johan Hedberg744cf192011-11-08 20:40:14 +02003079int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003080{
3081 struct mgmt_ev_pin_code_request ev;
3082
Johan Hedbergd8457692012-02-17 14:24:57 +02003083 bacpy(&ev.addr.bdaddr, bdaddr);
3084 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003085 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003086
Johan Hedberg744cf192011-11-08 20:40:14 +02003087 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003088 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003089}
3090
Johan Hedberg744cf192011-11-08 20:40:14 +02003091int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3092 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003093{
3094 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003095 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003096 int err;
3097
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003098 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003099 if (!cmd)
3100 return -ENOENT;
3101
Johan Hedbergd8457692012-02-17 14:24:57 +02003102 bacpy(&rp.addr.bdaddr, bdaddr);
3103 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003104
Johan Hedbergaee9b212012-02-18 15:07:59 +02003105 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3106 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003107
Johan Hedberga664b5b2011-02-19 12:06:02 -03003108 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003109
3110 return err;
3111}
3112
Johan Hedberg744cf192011-11-08 20:40:14 +02003113int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3114 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003115{
3116 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003117 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003118 int err;
3119
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003120 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003121 if (!cmd)
3122 return -ENOENT;
3123
Johan Hedbergd8457692012-02-17 14:24:57 +02003124 bacpy(&rp.addr.bdaddr, bdaddr);
3125 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003126
Johan Hedbergaee9b212012-02-18 15:07:59 +02003127 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3128 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003129
Johan Hedberga664b5b2011-02-19 12:06:02 -03003130 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003131
3132 return err;
3133}
Johan Hedberga5c29682011-02-19 12:05:57 -03003134
Johan Hedberg744cf192011-11-08 20:40:14 +02003135int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003136 u8 link_type, u8 addr_type, __le32 value,
3137 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003138{
3139 struct mgmt_ev_user_confirm_request ev;
3140
Johan Hedberg744cf192011-11-08 20:40:14 +02003141 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003142
Johan Hedberg272d90d2012-02-09 15:26:12 +02003143 bacpy(&ev.addr.bdaddr, bdaddr);
3144 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003145 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003146 put_unaligned_le32(value, &ev.value);
3147
Johan Hedberg744cf192011-11-08 20:40:14 +02003148 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003149 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003150}
3151
Johan Hedberg272d90d2012-02-09 15:26:12 +02003152int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3153 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003154{
3155 struct mgmt_ev_user_passkey_request ev;
3156
3157 BT_DBG("%s", hdev->name);
3158
Johan Hedberg272d90d2012-02-09 15:26:12 +02003159 bacpy(&ev.addr.bdaddr, bdaddr);
3160 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003161
3162 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3163 NULL);
3164}
3165
Brian Gix0df4c182011-11-16 13:53:13 -08003166static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003167 u8 link_type, u8 addr_type, u8 status,
3168 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003169{
3170 struct pending_cmd *cmd;
3171 struct mgmt_rp_user_confirm_reply rp;
3172 int err;
3173
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003174 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003175 if (!cmd)
3176 return -ENOENT;
3177
Johan Hedberg272d90d2012-02-09 15:26:12 +02003178 bacpy(&rp.addr.bdaddr, bdaddr);
3179 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003180 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3181 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003182
Johan Hedberga664b5b2011-02-19 12:06:02 -03003183 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003184
3185 return err;
3186}
3187
Johan Hedberg744cf192011-11-08 20:40:14 +02003188int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003189 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003190{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003191 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3192 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003193}
3194
Johan Hedberg272d90d2012-02-09 15:26:12 +02003195int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3196 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003197{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003198 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3199 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003200}
Johan Hedberg2a611692011-02-19 12:06:00 -03003201
Brian Gix604086b2011-11-23 08:28:33 -08003202int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003203 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003204{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003205 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3206 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003207}
3208
Johan Hedberg272d90d2012-02-09 15:26:12 +02003209int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3210 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003211{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003212 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3213 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003214}
3215
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003216int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3217 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003218{
3219 struct mgmt_ev_auth_failed ev;
3220
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003221 bacpy(&ev.addr.bdaddr, bdaddr);
3222 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003223 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003224
Johan Hedberg744cf192011-11-08 20:40:14 +02003225 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003226}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003227
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003228int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3229{
3230 struct cmd_lookup match = { NULL, hdev };
3231 __le32 ev;
3232 int err;
3233
3234 if (status) {
3235 u8 mgmt_err = mgmt_status(status);
3236 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3237 cmd_status_rsp, &mgmt_err);
3238 return 0;
3239 }
3240
3241 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3242 &match);
3243
3244 ev = cpu_to_le32(get_current_settings(hdev));
3245 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3246
3247 if (match.sk)
3248 sock_put(match.sk);
3249
3250 return err;
3251}
3252
Johan Hedbergcacaf522012-02-21 00:52:42 +02003253static int clear_eir(struct hci_dev *hdev)
3254{
3255 struct hci_cp_write_eir cp;
3256
3257 if (!(hdev->features[6] & LMP_EXT_INQ))
3258 return 0;
3259
3260 memset(&cp, 0, sizeof(cp));
3261
3262 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3263}
3264
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003265int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3266{
3267 struct cmd_lookup match = { NULL, hdev };
3268 __le32 ev;
3269 int err;
3270
3271 if (status) {
3272 u8 mgmt_err = mgmt_status(status);
3273 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3274 cmd_status_rsp, &mgmt_err);
3275 return 0;
3276 }
3277
3278 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3279
3280 ev = cpu_to_le32(get_current_settings(hdev));
3281 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3282
Johan Hedbergcacaf522012-02-21 00:52:42 +02003283 if (match.sk) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003284 sock_put(match.sk);
3285
Johan Hedbergcacaf522012-02-21 00:52:42 +02003286 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3287 update_eir(hdev);
3288 else
3289 clear_eir(hdev);
3290 }
3291
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003292 return err;
3293}
3294
Johan Hedberg744cf192011-11-08 20:40:14 +02003295int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003296{
3297 struct pending_cmd *cmd;
3298 struct mgmt_cp_set_local_name ev;
3299 int err;
3300
3301 memset(&ev, 0, sizeof(ev));
3302 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3303
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003304 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003305 if (!cmd)
3306 goto send_event;
3307
3308 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003309 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003310 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003311 goto failed;
3312 }
3313
Johan Hedberg744cf192011-11-08 20:40:14 +02003314 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003315
Johan Hedbergaee9b212012-02-18 15:07:59 +02003316 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003317 sizeof(ev));
3318 if (err < 0)
3319 goto failed;
3320
3321send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003322 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003323 cmd ? cmd->sk : NULL);
3324
3325failed:
3326 if (cmd)
3327 mgmt_pending_remove(cmd);
3328 return err;
3329}
Szymon Jancc35938b2011-03-22 13:12:21 +01003330
Johan Hedberg744cf192011-11-08 20:40:14 +02003331int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3332 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003333{
3334 struct pending_cmd *cmd;
3335 int err;
3336
Johan Hedberg744cf192011-11-08 20:40:14 +02003337 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003338
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003339 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003340 if (!cmd)
3341 return -ENOENT;
3342
3343 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003344 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003345 MGMT_OP_READ_LOCAL_OOB_DATA,
3346 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003347 } else {
3348 struct mgmt_rp_read_local_oob_data rp;
3349
3350 memcpy(rp.hash, hash, sizeof(rp.hash));
3351 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3352
Johan Hedberg744cf192011-11-08 20:40:14 +02003353 err = cmd_complete(cmd->sk, hdev->id,
3354 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003355 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003356 }
3357
3358 mgmt_pending_remove(cmd);
3359
3360 return err;
3361}
Johan Hedberge17acd42011-03-30 23:57:16 +03003362
Johan Hedberg48264f02011-11-09 13:58:58 +02003363int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003364 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003365 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003366{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003367 char buf[512];
3368 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003369 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003370
Johan Hedberg1dc06092012-01-15 21:01:23 +02003371 /* Leave 5 bytes for a potential CoD field */
3372 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003373 return -EINVAL;
3374
Johan Hedberg1dc06092012-01-15 21:01:23 +02003375 memset(buf, 0, sizeof(buf));
3376
Johan Hedberge319d2e2012-01-15 19:51:59 +02003377 bacpy(&ev->addr.bdaddr, bdaddr);
3378 ev->addr.type = link_to_mgmt(link_type, addr_type);
3379 ev->rssi = rssi;
3380 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003381
Johan Hedberg1dc06092012-01-15 21:01:23 +02003382 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003383 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003384
Johan Hedberg1dc06092012-01-15 21:01:23 +02003385 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3386 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3387 dev_class, 3);
3388
3389 put_unaligned_le16(eir_len, &ev->eir_len);
3390
3391 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003392
Johan Hedberge319d2e2012-01-15 19:51:59 +02003393 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003394}
Johan Hedberga88a9652011-03-30 13:18:12 +03003395
Johan Hedbergb644ba32012-01-17 21:48:47 +02003396int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3397 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003398{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003399 struct mgmt_ev_device_found *ev;
3400 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3401 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003402
Johan Hedbergb644ba32012-01-17 21:48:47 +02003403 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003404
Johan Hedbergb644ba32012-01-17 21:48:47 +02003405 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003406
Johan Hedbergb644ba32012-01-17 21:48:47 +02003407 bacpy(&ev->addr.bdaddr, bdaddr);
3408 ev->addr.type = link_to_mgmt(link_type, addr_type);
3409 ev->rssi = rssi;
3410
3411 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3412 name_len);
3413
3414 put_unaligned_le16(eir_len, &ev->eir_len);
3415
Johan Hedberg053c7e02012-02-04 00:06:00 +02003416 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3417 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003418}
Johan Hedberg314b2382011-04-27 10:29:57 -04003419
Andre Guedes7a135102011-11-09 17:14:25 -03003420int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003421{
3422 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003423 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003424 int err;
3425
Andre Guedes203159d2012-02-13 15:41:01 -03003426 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3427
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003428 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003429 if (!cmd)
3430 return -ENOENT;
3431
Johan Hedbergf808e162012-02-19 12:52:07 +02003432 type = hdev->discovery.type;
3433
3434 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3435 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003436 mgmt_pending_remove(cmd);
3437
3438 return err;
3439}
3440
Andre Guedese6d465c2011-11-09 17:14:26 -03003441int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3442{
3443 struct pending_cmd *cmd;
3444 int err;
3445
3446 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3447 if (!cmd)
3448 return -ENOENT;
3449
Johan Hedbergd9306502012-02-20 23:25:18 +02003450 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3451 &hdev->discovery.type,
3452 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003453 mgmt_pending_remove(cmd);
3454
3455 return err;
3456}
Johan Hedberg314b2382011-04-27 10:29:57 -04003457
Johan Hedberg744cf192011-11-08 20:40:14 +02003458int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003459{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003460 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003461 struct pending_cmd *cmd;
3462
Andre Guedes343fb142011-11-22 17:14:19 -03003463 BT_DBG("%s discovering %u", hdev->name, discovering);
3464
Johan Hedberg164a6e72011-11-01 17:06:44 +02003465 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003466 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003467 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003468 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003469
3470 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003471 u8 type = hdev->discovery.type;
3472
Johan Hedbergd9306502012-02-20 23:25:18 +02003473 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003474 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003475 mgmt_pending_remove(cmd);
3476 }
3477
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003478 memset(&ev, 0, sizeof(ev));
3479 ev.type = hdev->discovery.type;
3480 ev.discovering = discovering;
3481
3482 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003483}
Antti Julku5e762442011-08-25 16:48:02 +03003484
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003485int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003486{
3487 struct pending_cmd *cmd;
3488 struct mgmt_ev_device_blocked ev;
3489
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003490 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003491
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003492 bacpy(&ev.addr.bdaddr, bdaddr);
3493 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003494
Johan Hedberg744cf192011-11-08 20:40:14 +02003495 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3496 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003497}
3498
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003499int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003500{
3501 struct pending_cmd *cmd;
3502 struct mgmt_ev_device_unblocked ev;
3503
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003504 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003505
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003506 bacpy(&ev.addr.bdaddr, bdaddr);
3507 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003508
Johan Hedberg744cf192011-11-08 20:40:14 +02003509 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3510 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003511}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003512
3513module_param(enable_hs, bool, 0644);
3514MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3515
3516module_param(enable_le, bool, 0644);
3517MODULE_PARM_DESC(enable_le, "Enable Low Energy support");