blob: c25cb648059e4b7c8acc1a019fd04e853c6b9c7a [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_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200343 continue;
344
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345 put_unaligned_le16(d->id, &rp->index[i++]);
346 BT_DBG("Added hci%u", d->id);
347 }
348
349 read_unlock(&hci_dev_list_lock);
350
Johan Hedbergaee9b212012-02-18 15:07:59 +0200351 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100352 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200353
Johan Hedberga38528f2011-01-22 06:46:43 +0200354 kfree(rp);
355
356 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200357}
358
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200359static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200360{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200361 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200362
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200363 settings |= MGMT_SETTING_POWERED;
364 settings |= MGMT_SETTING_CONNECTABLE;
365 settings |= MGMT_SETTING_FAST_CONNECTABLE;
366 settings |= MGMT_SETTING_DISCOVERABLE;
367 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 if (hdev->features[6] & LMP_SIMPLE_PAIR)
370 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (!(hdev->features[4] & LMP_NO_BREDR)) {
373 settings |= MGMT_SETTING_BREDR;
374 settings |= MGMT_SETTING_LINK_SECURITY;
375 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200376
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100377 if (enable_hs)
378 settings |= MGMT_SETTING_HS;
379
380 if (enable_le) {
381 if (hdev->features[4] & LMP_LE)
382 settings |= MGMT_SETTING_LE;
383 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200384
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200385 return settings;
386}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388static u32 get_current_settings(struct hci_dev *hdev)
389{
390 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200391
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100392 if (!test_bit(HCI_UP, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200393 return settings;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200394
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100395 if (!test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200398 if (test_bit(HCI_PSCAN, &hdev->flags))
399 settings |= MGMT_SETTING_CONNECTABLE;
400
401 if (test_bit(HCI_ISCAN, &hdev->flags))
402 settings |= MGMT_SETTING_DISCOVERABLE;
403
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200404 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_PAIRABLE;
406
407 if (!(hdev->features[4] & LMP_NO_BREDR))
408 settings |= MGMT_SETTING_BREDR;
409
Andre Guedes59e29402011-12-30 10:34:03 -0300410 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200412
413 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200416 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200417 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200418
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200419 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
420 settings |= MGMT_SETTING_HS;
421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200423}
424
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300425#define PNP_INFO_SVCLASS_ID 0x1200
426
427static u8 bluetooth_base_uuid[] = {
428 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
429 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
430};
431
432static u16 get_uuid16(u8 *uuid128)
433{
434 u32 val;
435 int i;
436
437 for (i = 0; i < 12; i++) {
438 if (bluetooth_base_uuid[i] != uuid128[i])
439 return 0;
440 }
441
442 memcpy(&val, &uuid128[12], 4);
443
444 val = le32_to_cpu(val);
445 if (val > 0xffff)
446 return 0;
447
448 return (u16) val;
449}
450
451static void create_eir(struct hci_dev *hdev, u8 *data)
452{
453 u8 *ptr = data;
454 u16 eir_len = 0;
455 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
456 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200457 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300458 size_t name_len;
459
460 name_len = strlen(hdev->dev_name);
461
462 if (name_len > 0) {
463 /* EIR Data type */
464 if (name_len > 48) {
465 name_len = 48;
466 ptr[1] = EIR_NAME_SHORT;
467 } else
468 ptr[1] = EIR_NAME_COMPLETE;
469
470 /* EIR Data length */
471 ptr[0] = name_len + 1;
472
473 memcpy(ptr + 2, hdev->dev_name, name_len);
474
475 eir_len += (name_len + 2);
476 ptr += (name_len + 2);
477 }
478
479 memset(uuid16_list, 0, sizeof(uuid16_list));
480
481 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200482 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300483 u16 uuid16;
484
485 uuid16 = get_uuid16(uuid->uuid);
486 if (uuid16 == 0)
487 return;
488
489 if (uuid16 < 0x1100)
490 continue;
491
492 if (uuid16 == PNP_INFO_SVCLASS_ID)
493 continue;
494
495 /* Stop if not enough space to put next UUID */
496 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
497 truncated = 1;
498 break;
499 }
500
501 /* Check for duplicates */
502 for (i = 0; uuid16_list[i] != 0; i++)
503 if (uuid16_list[i] == uuid16)
504 break;
505
506 if (uuid16_list[i] == 0) {
507 uuid16_list[i] = uuid16;
508 eir_len += sizeof(u16);
509 }
510 }
511
512 if (uuid16_list[0] != 0) {
513 u8 *length = ptr;
514
515 /* EIR Data type */
516 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
517
518 ptr += 2;
519 eir_len += 2;
520
521 for (i = 0; uuid16_list[i] != 0; i++) {
522 *ptr++ = (uuid16_list[i] & 0x00ff);
523 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
524 }
525
526 /* EIR Data length */
527 *length = (i * sizeof(u16)) + 1;
528 }
529}
530
531static int update_eir(struct hci_dev *hdev)
532{
533 struct hci_cp_write_eir cp;
534
535 if (!(hdev->features[6] & LMP_EXT_INQ))
536 return 0;
537
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200538 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300539 return 0;
540
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200541 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300542 return 0;
543
544 memset(&cp, 0, sizeof(cp));
545
546 create_eir(hdev, cp.data);
547
548 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
549 return 0;
550
551 memcpy(hdev->eir, cp.data, sizeof(cp.data));
552
553 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
554}
555
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200556static u8 get_service_classes(struct hci_dev *hdev)
557{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300558 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200559 u8 val = 0;
560
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300561 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200563
564 return val;
565}
566
567static int update_class(struct hci_dev *hdev)
568{
569 u8 cod[3];
570
571 BT_DBG("%s", hdev->name);
572
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200573 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200574 return 0;
575
576 cod[0] = hdev->minor_class;
577 cod[1] = hdev->major_class;
578 cod[2] = get_service_classes(hdev);
579
580 if (memcmp(cod, hdev->dev_class, 3) == 0)
581 return 0;
582
583 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
584}
585
Johan Hedberg7d785252011-12-15 00:47:39 +0200586static void service_cache_off(struct work_struct *work)
587{
588 struct hci_dev *hdev = container_of(work, struct hci_dev,
589 service_cache.work);
590
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200591 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200592 return;
593
594 hci_dev_lock(hdev);
595
596 update_eir(hdev);
597 update_class(hdev);
598
599 hci_dev_unlock(hdev);
600}
601
602static void mgmt_init_hdev(struct hci_dev *hdev)
603{
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200604 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200605 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
606
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200607 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200608 schedule_delayed_work(&hdev->service_cache,
609 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
610}
611
Johan Hedberg03811012010-12-08 00:21:06 +0200612static int read_controller_info(struct sock *sk, u16 index)
613{
614 struct mgmt_rp_read_info rp;
615 struct hci_dev *hdev;
616
617 BT_DBG("sock %p hci%u", sk, index);
618
619 hdev = hci_dev_get(index);
620 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200621 return cmd_status(sk, index, MGMT_OP_READ_INFO,
622 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200623
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300624 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200625
Johan Hedberg7d785252011-12-15 00:47:39 +0200626 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
627 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200628
629 memset(&rp, 0, sizeof(rp));
630
Johan Hedberg03811012010-12-08 00:21:06 +0200631 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200632
633 rp.version = hdev->hci_ver;
634
Johan Hedberg03811012010-12-08 00:21:06 +0200635 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200636
637 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
638 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
639
640 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200641
642 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
643
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300644 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200645 hci_dev_put(hdev);
646
Johan Hedbergaee9b212012-02-18 15:07:59 +0200647 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200648}
649
650static void mgmt_pending_free(struct pending_cmd *cmd)
651{
652 sock_put(cmd->sk);
653 kfree(cmd->param);
654 kfree(cmd);
655}
656
657static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
658 struct hci_dev *hdev,
659 void *data, u16 len)
660{
661 struct pending_cmd *cmd;
662
663 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
664 if (!cmd)
665 return NULL;
666
667 cmd->opcode = opcode;
668 cmd->index = hdev->id;
669
670 cmd->param = kmalloc(len, GFP_ATOMIC);
671 if (!cmd->param) {
672 kfree(cmd);
673 return NULL;
674 }
675
676 if (data)
677 memcpy(cmd->param, data, len);
678
679 cmd->sk = sk;
680 sock_hold(sk);
681
682 list_add(&cmd->list, &hdev->mgmt_pending);
683
684 return cmd;
685}
686
687static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
688 void (*cb)(struct pending_cmd *cmd, void *data),
689 void *data)
690{
691 struct list_head *p, *n;
692
693 list_for_each_safe(p, n, &hdev->mgmt_pending) {
694 struct pending_cmd *cmd;
695
696 cmd = list_entry(p, struct pending_cmd, list);
697
698 if (opcode > 0 && cmd->opcode != opcode)
699 continue;
700
701 cb(cmd, data);
702 }
703}
704
705static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
706{
707 struct pending_cmd *cmd;
708
709 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
710 if (cmd->opcode == opcode)
711 return cmd;
712 }
713
714 return NULL;
715}
716
717static void mgmt_pending_remove(struct pending_cmd *cmd)
718{
719 list_del(&cmd->list);
720 mgmt_pending_free(cmd);
721}
722
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200723static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200724{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200725 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200726
Johan Hedbergaee9b212012-02-18 15:07:59 +0200727 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
728 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200729}
730
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300731static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200732{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300733 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200734 struct hci_dev *hdev;
735 struct pending_cmd *cmd;
736 int err, up;
737
Johan Hedberg03811012010-12-08 00:21:06 +0200738 BT_DBG("request for hci%u", index);
739
740 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200741 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
742 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200743
744 hdev = hci_dev_get(index);
745 if (!hdev)
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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300749 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200750
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100751 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
752 cancel_delayed_work(&hdev->power_off);
753
754 if (cp->val) {
755 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
756 mgmt_powered(hdev, 1);
757 goto failed;
758 }
759 }
760
Johan Hedberg03811012010-12-08 00:21:06 +0200761 up = test_bit(HCI_UP, &hdev->flags);
762 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200763 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200764 goto failed;
765 }
766
767 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200768 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
769 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200770 goto failed;
771 }
772
773 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
774 if (!cmd) {
775 err = -ENOMEM;
776 goto failed;
777 }
778
779 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200780 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200781 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200782 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200783
784 err = 0;
785
786failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300787 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 hci_dev_put(hdev);
789 return err;
790}
791
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300792static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200793{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300794 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200795 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200796 struct pending_cmd *cmd;
797 u8 scan;
798 int err;
799
Johan Hedberg03811012010-12-08 00:21:06 +0200800 BT_DBG("request for hci%u", index);
801
802 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200803 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
804 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200805
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200806 hdev = hci_dev_get(index);
807 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200808 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
809 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300811 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200812
813 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200814 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
815 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200816 goto failed;
817 }
818
819 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
820 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200821 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
822 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200823 goto failed;
824 }
825
826 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
827 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200828 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200829 goto failed;
830 }
831
832 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
833 if (!cmd) {
834 err = -ENOMEM;
835 goto failed;
836 }
837
838 scan = SCAN_PAGE;
839
840 if (cp->val)
841 scan |= SCAN_INQUIRY;
842 else
843 cancel_delayed_work(&hdev->discov_off);
844
845 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
846 if (err < 0)
847 mgmt_pending_remove(cmd);
848
Johan Hedberg03811012010-12-08 00:21:06 +0200849 if (cp->val)
850 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
851
Johan Hedberge41d8b42010-12-13 21:07:03 +0200852failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300853 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200854 hci_dev_put(hdev);
855
856 return err;
857}
858
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300859static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200860{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300861 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200862 struct hci_dev *hdev;
863 struct pending_cmd *cmd;
864 u8 scan;
865 int err;
866
Johan Hedberge41d8b42010-12-13 21:07:03 +0200867 BT_DBG("request for hci%u", index);
868
Johan Hedberg03811012010-12-08 00:21:06 +0200869 if (len != sizeof(*cp))
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
873 hdev = hci_dev_get(index);
874 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200875 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
876 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200877
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300878 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200879
880 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200881 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
882 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200883 goto failed;
884 }
885
886 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
887 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200888 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
889 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200890 goto failed;
891 }
892
893 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200894 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200895 goto failed;
896 }
897
898 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
899 if (!cmd) {
900 err = -ENOMEM;
901 goto failed;
902 }
903
904 if (cp->val)
905 scan = SCAN_PAGE;
906 else
907 scan = 0;
908
909 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
910 if (err < 0)
911 mgmt_pending_remove(cmd);
912
913failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300914 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200915 hci_dev_put(hdev);
916
917 return err;
918}
919
920static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
921 u16 data_len, struct sock *skip_sk)
922{
923 struct sk_buff *skb;
924 struct mgmt_hdr *hdr;
925
926 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
927 if (!skb)
928 return -ENOMEM;
929
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200930 hdr = (void *) skb_put(skb, sizeof(*hdr));
931 hdr->opcode = cpu_to_le16(event);
932 if (hdev)
933 hdr->index = cpu_to_le16(hdev->id);
934 else
935 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
936 hdr->len = cpu_to_le16(data_len);
937
938 if (data)
939 memcpy(skb_put(skb, data_len), data, data_len);
940
Marcel Holtmann470fe1b2012-02-20 14:50:30 +0100941 hci_send_to_control(skb, skip_sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200942 kfree_skb(skb);
943
944 return 0;
945}
946
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300947static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200948{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300949 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200950 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200951 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200952 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200953
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200954 BT_DBG("request for hci%u", index);
955
956 if (len != sizeof(*cp))
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
960 hdev = hci_dev_get(index);
961 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200962 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
963 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200964
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300965 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200966
967 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200968 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200969 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200970 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200971
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200972 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200973 if (err < 0)
974 goto failed;
975
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200976 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200977
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200978 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200979
980failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300981 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200982 hci_dev_put(hdev);
983
984 return err;
985}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200986
Johan Hedberg33ef95e2012-02-16 23:56:27 +0200987static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
988{
989 struct mgmt_mode *cp = data;
990 struct pending_cmd *cmd;
991 struct hci_dev *hdev;
992 uint8_t val;
993 int err;
994
995 BT_DBG("request for hci%u", index);
996
997 if (len != sizeof(*cp))
998 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
999 MGMT_STATUS_INVALID_PARAMS);
1000
1001 hdev = hci_dev_get(index);
1002 if (!hdev)
1003 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1004 MGMT_STATUS_INVALID_PARAMS);
1005
1006 hci_dev_lock(hdev);
1007
1008 if (!test_bit(HCI_UP, &hdev->flags)) {
1009 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1010 MGMT_STATUS_NOT_POWERED);
1011 goto failed;
1012 }
1013
1014 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1015 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1016 MGMT_STATUS_BUSY);
1017 goto failed;
1018 }
1019
1020 val = !!cp->val;
1021
1022 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1023 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1024 goto failed;
1025 }
1026
1027 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1028 if (!cmd) {
1029 err = -ENOMEM;
1030 goto failed;
1031 }
1032
1033 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1034 if (err < 0) {
1035 mgmt_pending_remove(cmd);
1036 goto failed;
1037 }
1038
1039failed:
1040 hci_dev_unlock(hdev);
1041 hci_dev_put(hdev);
1042
1043 return err;
1044}
1045
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001046static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1047{
1048 struct mgmt_mode *cp = data;
1049 struct pending_cmd *cmd;
1050 struct hci_dev *hdev;
1051 uint8_t val;
1052 int err;
1053
1054 BT_DBG("request for hci%u", index);
1055
1056 if (len != sizeof(*cp))
1057 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1058 MGMT_STATUS_INVALID_PARAMS);
1059
1060 hdev = hci_dev_get(index);
1061 if (!hdev)
1062 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1063 MGMT_STATUS_INVALID_PARAMS);
1064
1065 hci_dev_lock(hdev);
1066
1067 if (!test_bit(HCI_UP, &hdev->flags)) {
1068 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1069 MGMT_STATUS_NOT_POWERED);
1070 goto failed;
1071 }
1072
Johan Hedberg1e163572012-02-20 23:53:46 +02001073 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1074 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1075 MGMT_STATUS_NOT_SUPPORTED);
1076 goto failed;
1077 }
1078
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001079 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1080 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1081 goto failed;
1082 }
1083
1084 val = !!cp->val;
1085
1086 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1087 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1088 goto failed;
1089 }
1090
1091 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1092 if (!cmd) {
1093 err = -ENOMEM;
1094 goto failed;
1095 }
1096
1097 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1098 if (err < 0) {
1099 mgmt_pending_remove(cmd);
1100 goto failed;
1101 }
1102
1103failed:
1104 hci_dev_unlock(hdev);
1105 hci_dev_put(hdev);
1106
1107 return err;
1108}
1109
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001110static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1111{
1112 struct mgmt_mode *cp = data;
1113 struct hci_dev *hdev;
1114 int err;
1115
1116 BT_DBG("request for hci%u", index);
1117
1118 if (len != sizeof(*cp))
1119 return cmd_status(sk, index, MGMT_OP_SET_HS,
1120 MGMT_STATUS_INVALID_PARAMS);
1121
1122 hdev = hci_dev_get(index);
1123 if (!hdev)
1124 return cmd_status(sk, index, MGMT_OP_SET_HS,
1125 MGMT_STATUS_INVALID_PARAMS);
1126
1127 if (!enable_hs) {
1128 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1129 MGMT_STATUS_NOT_SUPPORTED);
1130 goto failed;
1131 }
1132
1133 if (cp->val)
1134 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1135 else
1136 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1137
1138 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1139
1140failed:
1141 hci_dev_put(hdev);
1142 return err;
1143}
1144
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001145static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001146{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001147 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001148 struct hci_dev *hdev;
1149 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001150 int err;
1151
Szymon Janc4e51eae2011-02-25 19:05:48 +01001152 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001153
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001154 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001155 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1156 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001157
Szymon Janc4e51eae2011-02-25 19:05:48 +01001158 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001159 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001160 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1161 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001162
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001163 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001164
1165 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1166 if (!uuid) {
1167 err = -ENOMEM;
1168 goto failed;
1169 }
1170
1171 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001172 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001173
1174 list_add(&uuid->list, &hdev->uuids);
1175
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001176 err = update_class(hdev);
1177 if (err < 0)
1178 goto failed;
1179
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001180 err = update_eir(hdev);
1181 if (err < 0)
1182 goto failed;
1183
Johan Hedbergaee9b212012-02-18 15:07:59 +02001184 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001185
1186failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001187 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001188 hci_dev_put(hdev);
1189
1190 return err;
1191}
1192
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001193static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001194{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001195 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001196 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001197 struct hci_dev *hdev;
1198 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 +02001199 int err, found;
1200
Szymon Janc4e51eae2011-02-25 19:05:48 +01001201 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001202
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001203 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001204 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1205 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001206
Szymon Janc4e51eae2011-02-25 19:05:48 +01001207 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001208 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001209 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1210 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001211
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001212 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001213
1214 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1215 err = hci_uuids_clear(hdev);
1216 goto unlock;
1217 }
1218
1219 found = 0;
1220
1221 list_for_each_safe(p, n, &hdev->uuids) {
1222 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1223
1224 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1225 continue;
1226
1227 list_del(&match->list);
1228 found++;
1229 }
1230
1231 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001232 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1233 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001234 goto unlock;
1235 }
1236
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001237 err = update_class(hdev);
1238 if (err < 0)
1239 goto unlock;
1240
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001241 err = update_eir(hdev);
1242 if (err < 0)
1243 goto unlock;
1244
Johan Hedbergaee9b212012-02-18 15:07:59 +02001245 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001246
1247unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001248 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001249 hci_dev_put(hdev);
1250
1251 return err;
1252}
1253
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001254static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001255{
1256 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001257 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001258 int err;
1259
Szymon Janc4e51eae2011-02-25 19:05:48 +01001260 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001261
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001262 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001263 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1264 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001265
Szymon Janc4e51eae2011-02-25 19:05:48 +01001266 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001267 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001268 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1269 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001270
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001271 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001272
1273 hdev->major_class = cp->major;
1274 hdev->minor_class = cp->minor;
1275
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001276 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001277 hci_dev_unlock(hdev);
1278 cancel_delayed_work_sync(&hdev->service_cache);
1279 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001280 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001281 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001282
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001283 err = update_class(hdev);
1284
1285 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001286 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1287 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001288
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001289 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001290 hci_dev_put(hdev);
1291
1292 return err;
1293}
1294
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001295static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001296{
1297 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001298 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001299 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001300 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001301
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001302 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001303 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1304 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001305
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001306 key_count = get_unaligned_le16(&cp->key_count);
1307
Johan Hedberg86742e12011-11-07 23:13:38 +02001308 expected_len = sizeof(*cp) + key_count *
1309 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001310 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001311 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001312 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001313 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1314 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001315 }
1316
Szymon Janc4e51eae2011-02-25 19:05:48 +01001317 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001318 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001319 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1320 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001321
Szymon Janc4e51eae2011-02-25 19:05:48 +01001322 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001323 key_count);
1324
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001325 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001326
1327 hci_link_keys_clear(hdev);
1328
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001329 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001330
1331 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001332 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001333 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001334 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001335
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001336 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001337 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001338
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001339 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1340 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001341 }
1342
Johan Hedbergaee9b212012-02-18 15:07:59 +02001343 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001344
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001345 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001346 hci_dev_put(hdev);
1347
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001348 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001349}
1350
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001351static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1352 u8 addr_type, struct sock *skip_sk)
1353{
1354 struct mgmt_ev_device_unpaired ev;
1355
1356 bacpy(&ev.addr.bdaddr, bdaddr);
1357 ev.addr.type = addr_type;
1358
1359 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1360 skip_sk);
1361}
1362
Johan Hedberg124f6e32012-02-09 13:50:12 +02001363static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001364{
1365 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001366 struct mgmt_cp_unpair_device *cp = data;
1367 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001368 struct hci_cp_disconnect dc;
1369 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001370 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001371 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001372 int err;
1373
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001374 if (len != sizeof(*cp))
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);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001377
Szymon Janc4e51eae2011-02-25 19:05:48 +01001378 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001379 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001380 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001381 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001382
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001383 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001384
Johan Hedberga8a1d192011-11-10 15:54:38 +02001385 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001386 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1387 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001388
Johan Hedberg124f6e32012-02-09 13:50:12 +02001389 if (cp->addr.type == MGMT_ADDR_BREDR)
1390 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1391 else
1392 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001393
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001394 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001395 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001396 goto unlock;
1397 }
1398
Johan Hedberga8a1d192011-11-10 15:54:38 +02001399 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001400 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1401 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001402 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001403 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001404 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001405
Johan Hedberg124f6e32012-02-09 13:50:12 +02001406 if (cp->addr.type == MGMT_ADDR_BREDR)
1407 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1408 &cp->addr.bdaddr);
1409 else
1410 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1411 &cp->addr.bdaddr);
1412
Johan Hedberga8a1d192011-11-10 15:54:38 +02001413 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001414 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1415 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001416 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001417 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001418 }
1419
Johan Hedberg124f6e32012-02-09 13:50:12 +02001420 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1421 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001422 if (!cmd) {
1423 err = -ENOMEM;
1424 goto unlock;
1425 }
1426
1427 put_unaligned_le16(conn->handle, &dc.handle);
1428 dc.reason = 0x13; /* Remote User Terminated Connection */
1429 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1430 if (err < 0)
1431 mgmt_pending_remove(cmd);
1432
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001433unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001434 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001435 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1436 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001437 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001438 hci_dev_put(hdev);
1439
1440 return err;
1441}
1442
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001443static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001444{
1445 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001446 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001447 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001448 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001449 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001450 int err;
1451
1452 BT_DBG("");
1453
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001454 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001455 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1456 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001457
Szymon Janc4e51eae2011-02-25 19:05:48 +01001458 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001459 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001460 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1461 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001462
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001463 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001464
1465 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001466 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1467 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001468 goto failed;
1469 }
1470
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001471 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001472 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1473 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001474 goto failed;
1475 }
1476
Johan Hedberg88c3df12012-02-09 14:27:38 +02001477 if (cp->addr.type == MGMT_ADDR_BREDR)
1478 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1479 else
1480 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001481
Johan Hedberg8962ee72011-01-20 12:40:27 +02001482 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001483 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1484 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001485 goto failed;
1486 }
1487
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001488 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001489 if (!cmd) {
1490 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001491 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001492 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001493
1494 put_unaligned_le16(conn->handle, &dc.handle);
1495 dc.reason = 0x13; /* Remote User Terminated Connection */
1496
1497 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1498 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001499 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001500
1501failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001502 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001503 hci_dev_put(hdev);
1504
1505 return err;
1506}
1507
Johan Hedberg48264f02011-11-09 13:58:58 +02001508static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001509{
1510 switch (link_type) {
1511 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001512 switch (addr_type) {
1513 case ADDR_LE_DEV_PUBLIC:
1514 return MGMT_ADDR_LE_PUBLIC;
1515 case ADDR_LE_DEV_RANDOM:
1516 return MGMT_ADDR_LE_RANDOM;
1517 default:
1518 return MGMT_ADDR_INVALID;
1519 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001520 case ACL_LINK:
1521 return MGMT_ADDR_BREDR;
1522 default:
1523 return MGMT_ADDR_INVALID;
1524 }
1525}
1526
Szymon Janc8ce62842011-03-01 16:55:32 +01001527static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001528{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001529 struct mgmt_rp_get_connections *rp;
1530 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001531 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001532 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001533 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001534 int i, err;
1535
1536 BT_DBG("");
1537
Szymon Janc4e51eae2011-02-25 19:05:48 +01001538 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001539 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001540 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1541 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001542
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001543 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001544
1545 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001546 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1547 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1548 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001549 }
1550
Johan Hedberg4c659c32011-11-07 23:13:39 +02001551 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001552 rp = kmalloc(rp_len, GFP_ATOMIC);
1553 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001554 err = -ENOMEM;
1555 goto unlock;
1556 }
1557
Johan Hedberg2784eb42011-01-21 13:56:35 +02001558 put_unaligned_le16(count, &rp->conn_count);
1559
Johan Hedberg2784eb42011-01-21 13:56:35 +02001560 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001561 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001562 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1563 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001564 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001565 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001566 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1567 continue;
1568 i++;
1569 }
1570
1571 /* Recalculate length in case of filtered SCO connections, etc */
1572 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001573
Johan Hedbergaee9b212012-02-18 15:07:59 +02001574 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001575
1576unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001577 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001578 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001579 hci_dev_put(hdev);
1580 return err;
1581}
1582
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001583static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1584 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1585{
1586 struct pending_cmd *cmd;
1587 int err;
1588
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001589 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001590 sizeof(*cp));
1591 if (!cmd)
1592 return -ENOMEM;
1593
Johan Hedbergd8457692012-02-17 14:24:57 +02001594 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1595 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001596 if (err < 0)
1597 mgmt_pending_remove(cmd);
1598
1599 return err;
1600}
1601
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001602static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001603{
1604 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001605 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001606 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001607 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001608 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001609 int err;
1610
1611 BT_DBG("");
1612
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001613 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001614 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1615 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001616
Szymon Janc4e51eae2011-02-25 19:05:48 +01001617 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001618 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001619 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1620 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001621
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001622 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001623
1624 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001625 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1626 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001627 goto failed;
1628 }
1629
Johan Hedbergd8457692012-02-17 14:24:57 +02001630 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001631 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001632 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1633 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001634 goto failed;
1635 }
1636
1637 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001638 struct mgmt_cp_pin_code_neg_reply ncp;
1639
1640 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001641
1642 BT_ERR("PIN code is not 16 bytes long");
1643
1644 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1645 if (err >= 0)
1646 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001647 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001648
1649 goto failed;
1650 }
1651
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001652 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1653 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001654 if (!cmd) {
1655 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001656 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001657 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001658
Johan Hedbergd8457692012-02-17 14:24:57 +02001659 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001660 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001661 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001662
1663 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1664 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001665 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001666
1667failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001668 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001669 hci_dev_put(hdev);
1670
1671 return err;
1672}
1673
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001674static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001675{
1676 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001677 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001678 int err;
1679
1680 BT_DBG("");
1681
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001682 if (len != sizeof(*cp))
1683 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001684 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001685
Szymon Janc4e51eae2011-02-25 19:05:48 +01001686 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001687 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001688 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001689 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001690
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001691 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001692
1693 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001694 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001695 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001696 goto failed;
1697 }
1698
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001699 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001700
1701failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001702 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001703 hci_dev_put(hdev);
1704
1705 return err;
1706}
1707
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001708static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001709{
1710 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001711 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001712
1713 BT_DBG("");
1714
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001715 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001716 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1717 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001718
Szymon Janc4e51eae2011-02-25 19:05:48 +01001719 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001720 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001721 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1722 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001723
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001724 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001725
1726 hdev->io_capability = cp->io_capability;
1727
1728 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001729 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001730
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001731 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001732 hci_dev_put(hdev);
1733
Johan Hedbergaee9b212012-02-18 15:07:59 +02001734 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001735}
1736
Johan Hedberge9a416b2011-02-19 12:05:56 -03001737static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1738{
1739 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001740 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001741
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001742 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001743 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1744 continue;
1745
Johan Hedberge9a416b2011-02-19 12:05:56 -03001746 if (cmd->user_data != conn)
1747 continue;
1748
1749 return cmd;
1750 }
1751
1752 return NULL;
1753}
1754
1755static void pairing_complete(struct pending_cmd *cmd, u8 status)
1756{
1757 struct mgmt_rp_pair_device rp;
1758 struct hci_conn *conn = cmd->user_data;
1759
Johan Hedbergba4e5642011-11-11 00:07:34 +02001760 bacpy(&rp.addr.bdaddr, &conn->dst);
1761 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001762
Johan Hedbergaee9b212012-02-18 15:07:59 +02001763 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1764 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001765
1766 /* So we don't get further callbacks for this connection */
1767 conn->connect_cfm_cb = NULL;
1768 conn->security_cfm_cb = NULL;
1769 conn->disconn_cfm_cb = NULL;
1770
1771 hci_conn_put(conn);
1772
Johan Hedberga664b5b2011-02-19 12:06:02 -03001773 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001774}
1775
1776static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1777{
1778 struct pending_cmd *cmd;
1779
1780 BT_DBG("status %u", status);
1781
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001782 cmd = find_pairing(conn);
1783 if (!cmd)
1784 BT_DBG("Unable to find a pending command");
1785 else
Johan Hedberge2113262012-02-18 15:20:03 +02001786 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001787}
1788
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001789static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001790{
1791 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001792 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001793 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001794 struct pending_cmd *cmd;
1795 u8 sec_level, auth_type;
1796 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001797 int err;
1798
1799 BT_DBG("");
1800
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001801 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001802 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1803 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001804
Szymon Janc4e51eae2011-02-25 19:05:48 +01001805 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001806 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001807 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1808 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001809
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001810 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001811
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001812 sec_level = BT_SECURITY_MEDIUM;
1813 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001814 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001815 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001816 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001817
Johan Hedbergba4e5642011-11-11 00:07:34 +02001818 if (cp->addr.type == MGMT_ADDR_BREDR)
1819 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001820 auth_type);
1821 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001822 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001823 auth_type);
1824
Johan Hedberg1425acb2011-11-11 00:07:35 +02001825 memset(&rp, 0, sizeof(rp));
1826 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1827 rp.addr.type = cp->addr.type;
1828
Ville Tervo30e76272011-02-22 16:10:53 -03001829 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001830 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1831 MGMT_STATUS_CONNECT_FAILED,
1832 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001833 goto unlock;
1834 }
1835
1836 if (conn->connect_cfm_cb) {
1837 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001838 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1839 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001840 goto unlock;
1841 }
1842
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001843 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001844 if (!cmd) {
1845 err = -ENOMEM;
1846 hci_conn_put(conn);
1847 goto unlock;
1848 }
1849
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001850 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001851 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001852 conn->connect_cfm_cb = pairing_complete_cb;
1853
Johan Hedberge9a416b2011-02-19 12:05:56 -03001854 conn->security_cfm_cb = pairing_complete_cb;
1855 conn->disconn_cfm_cb = pairing_complete_cb;
1856 conn->io_capability = cp->io_cap;
1857 cmd->user_data = conn;
1858
1859 if (conn->state == BT_CONNECTED &&
1860 hci_conn_security(conn, sec_level, auth_type))
1861 pairing_complete(cmd, 0);
1862
1863 err = 0;
1864
1865unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001866 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001867 hci_dev_put(hdev);
1868
1869 return err;
1870}
1871
Johan Hedberg28424702012-02-02 04:02:29 +02001872static int cancel_pair_device(struct sock *sk, u16 index,
1873 unsigned char *data, u16 len)
1874{
1875 struct mgmt_addr_info *addr = (void *) data;
1876 struct hci_dev *hdev;
1877 struct pending_cmd *cmd;
1878 struct hci_conn *conn;
1879 int err;
1880
1881 BT_DBG("");
1882
1883 if (len != sizeof(*addr))
1884 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1885 MGMT_STATUS_INVALID_PARAMS);
1886
1887 hdev = hci_dev_get(index);
1888 if (!hdev)
1889 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1890 MGMT_STATUS_INVALID_PARAMS);
1891
1892 hci_dev_lock(hdev);
1893
1894 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1895 if (!cmd) {
1896 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1897 MGMT_STATUS_INVALID_PARAMS);
1898 goto unlock;
1899 }
1900
1901 conn = cmd->user_data;
1902
1903 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1904 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1905 MGMT_STATUS_INVALID_PARAMS);
1906 goto unlock;
1907 }
1908
1909 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1910
Johan Hedbergaee9b212012-02-18 15:07:59 +02001911 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001912 sizeof(*addr));
1913unlock:
1914 hci_dev_unlock(hdev);
1915 hci_dev_put(hdev);
1916
1917 return err;
1918}
1919
Brian Gix0df4c182011-11-16 13:53:13 -08001920static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001921 u8 type, u16 mgmt_op, u16 hci_op,
1922 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001923{
Johan Hedberga5c29682011-02-19 12:05:57 -03001924 struct pending_cmd *cmd;
1925 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001926 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001927 int err;
1928
Szymon Janc4e51eae2011-02-25 19:05:48 +01001929 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001930 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001931 return cmd_status(sk, index, mgmt_op,
1932 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001933
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001934 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001935
Johan Hedberga5c29682011-02-19 12:05:57 -03001936 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001937 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1938 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001939 }
1940
Johan Hedberg272d90d2012-02-09 15:26:12 +02001941 if (type == MGMT_ADDR_BREDR)
1942 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1943 else
Brian Gix47c15e22011-11-16 13:53:14 -08001944 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001945
Johan Hedberg272d90d2012-02-09 15:26:12 +02001946 if (!conn) {
1947 err = cmd_status(sk, index, mgmt_op,
1948 MGMT_STATUS_NOT_CONNECTED);
1949 goto done;
1950 }
1951
1952 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001953 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001954 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001955
Brian Gix5fe57d92011-12-21 16:12:13 -08001956 if (!err)
1957 err = cmd_status(sk, index, mgmt_op,
1958 MGMT_STATUS_SUCCESS);
1959 else
1960 err = cmd_status(sk, index, mgmt_op,
1961 MGMT_STATUS_FAILED);
1962
Brian Gix47c15e22011-11-16 13:53:14 -08001963 goto done;
1964 }
1965
Brian Gix0df4c182011-11-16 13:53:13 -08001966 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001967 if (!cmd) {
1968 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001969 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001970 }
1971
Brian Gix0df4c182011-11-16 13:53:13 -08001972 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001973 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1974 struct hci_cp_user_passkey_reply cp;
1975
1976 bacpy(&cp.bdaddr, bdaddr);
1977 cp.passkey = passkey;
1978 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1979 } else
1980 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1981
Johan Hedberga664b5b2011-02-19 12:06:02 -03001982 if (err < 0)
1983 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001984
Brian Gix0df4c182011-11-16 13:53:13 -08001985done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001986 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001987 hci_dev_put(hdev);
1988
1989 return err;
1990}
1991
Brian Gix0df4c182011-11-16 13:53:13 -08001992static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1993{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001994 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001995
1996 BT_DBG("");
1997
1998 if (len != sizeof(*cp))
1999 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2000 MGMT_STATUS_INVALID_PARAMS);
2001
Johan Hedberg272d90d2012-02-09 15:26:12 +02002002 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2003 MGMT_OP_USER_CONFIRM_REPLY,
2004 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002005}
2006
2007static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2008 u16 len)
2009{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002010 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002011
2012 BT_DBG("");
2013
2014 if (len != sizeof(*cp))
2015 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2016 MGMT_STATUS_INVALID_PARAMS);
2017
Johan Hedberg272d90d2012-02-09 15:26:12 +02002018 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2019 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2020 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002021}
2022
Brian Gix604086b2011-11-23 08:28:33 -08002023static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2024{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002025 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002026
2027 BT_DBG("");
2028
2029 if (len != sizeof(*cp))
2030 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2031 EINVAL);
2032
Johan Hedberg272d90d2012-02-09 15:26:12 +02002033 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2034 MGMT_OP_USER_PASSKEY_REPLY,
2035 HCI_OP_USER_PASSKEY_REPLY,
2036 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002037}
2038
2039static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2040 u16 len)
2041{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002042 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002043
2044 BT_DBG("");
2045
2046 if (len != sizeof(*cp))
2047 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2048 EINVAL);
2049
Johan Hedberg272d90d2012-02-09 15:26:12 +02002050 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2051 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2052 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002053}
2054
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002055static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002056 u16 len)
2057{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002058 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002059 struct hci_cp_write_local_name hci_cp;
2060 struct hci_dev *hdev;
2061 struct pending_cmd *cmd;
2062 int err;
2063
2064 BT_DBG("");
2065
2066 if (len != sizeof(*mgmt_cp))
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
2070 hdev = hci_dev_get(index);
2071 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002072 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2073 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002074
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002075 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002076
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002077 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2078 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002079 if (!cmd) {
2080 err = -ENOMEM;
2081 goto failed;
2082 }
2083
2084 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2085 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2086 &hci_cp);
2087 if (err < 0)
2088 mgmt_pending_remove(cmd);
2089
2090failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002091 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002092 hci_dev_put(hdev);
2093
2094 return err;
2095}
2096
Szymon Jancc35938b2011-03-22 13:12:21 +01002097static int read_local_oob_data(struct sock *sk, u16 index)
2098{
2099 struct hci_dev *hdev;
2100 struct pending_cmd *cmd;
2101 int err;
2102
2103 BT_DBG("hci%u", index);
2104
2105 hdev = hci_dev_get(index);
2106 if (!hdev)
2107 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002108 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002109
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002110 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002111
2112 if (!test_bit(HCI_UP, &hdev->flags)) {
2113 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002114 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002115 goto unlock;
2116 }
2117
2118 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2119 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002120 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002121 goto unlock;
2122 }
2123
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002124 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002125 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2126 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002127 goto unlock;
2128 }
2129
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002130 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002131 if (!cmd) {
2132 err = -ENOMEM;
2133 goto unlock;
2134 }
2135
2136 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2137 if (err < 0)
2138 mgmt_pending_remove(cmd);
2139
2140unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002141 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002142 hci_dev_put(hdev);
2143
2144 return err;
2145}
2146
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002147static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2148 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002149{
2150 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002151 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002152 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002153 int err;
2154
2155 BT_DBG("hci%u ", index);
2156
2157 if (len != sizeof(*cp))
2158 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002159 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002160
2161 hdev = hci_dev_get(index);
2162 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002163 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2164 MGMT_STATUS_INVALID_PARAMS,
2165 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002166
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002167 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002168
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002169 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002170 cp->randomizer);
2171 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002172 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002173 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002174 status = 0;
2175
2176 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2177 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002178
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002179 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002180 hci_dev_put(hdev);
2181
2182 return err;
2183}
2184
2185static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002186 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002187{
2188 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002189 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002190 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002191 int err;
2192
2193 BT_DBG("hci%u ", index);
2194
2195 if (len != sizeof(*cp))
2196 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002197 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002198
2199 hdev = hci_dev_get(index);
2200 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002201 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2202 MGMT_STATUS_INVALID_PARAMS,
2203 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002204
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002205 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002206
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002207 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002208 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002209 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002210 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002211 status = 0;
2212
2213 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2214 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002215
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002216 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002217 hci_dev_put(hdev);
2218
2219 return err;
2220}
2221
Andre Guedes5e0452c2012-02-17 20:39:38 -03002222static int discovery(struct hci_dev *hdev)
2223{
2224 int err;
2225
2226 if (lmp_host_le_capable(hdev)) {
2227 if (lmp_bredr_capable(hdev)) {
2228 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2229 LE_SCAN_INT, LE_SCAN_WIN,
2230 LE_SCAN_TIMEOUT_BREDR_LE);
2231 } else {
2232 hdev->discovery.type = DISCOV_TYPE_LE;
2233 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2234 LE_SCAN_INT, LE_SCAN_WIN,
2235 LE_SCAN_TIMEOUT_LE_ONLY);
2236 }
2237 } else {
2238 hdev->discovery.type = DISCOV_TYPE_BREDR;
2239 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2240 }
2241
2242 return err;
2243}
2244
2245int mgmt_interleaved_discovery(struct hci_dev *hdev)
2246{
2247 int err;
2248
2249 BT_DBG("%s", hdev->name);
2250
2251 hci_dev_lock(hdev);
2252
2253 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2254 if (err < 0)
2255 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2256
2257 hci_dev_unlock(hdev);
2258
2259 return err;
2260}
2261
Johan Hedberg450dfda2011-11-12 11:58:22 +02002262static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002263 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002264{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002265 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002266 struct pending_cmd *cmd;
2267 struct hci_dev *hdev;
2268 int err;
2269
2270 BT_DBG("hci%u", index);
2271
Johan Hedberg450dfda2011-11-12 11:58:22 +02002272 if (len != sizeof(*cp))
2273 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2274 MGMT_STATUS_INVALID_PARAMS);
2275
Johan Hedberg14a53662011-04-27 10:29:56 -04002276 hdev = hci_dev_get(index);
2277 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002278 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2279 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002280
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002281 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002282
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002283 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002284 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2285 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002286 goto failed;
2287 }
2288
Johan Hedbergff9ef572012-01-04 14:23:45 +02002289 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2290 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2291 MGMT_STATUS_BUSY);
2292 goto failed;
2293 }
2294
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002295 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002296 if (!cmd) {
2297 err = -ENOMEM;
2298 goto failed;
2299 }
2300
Andre Guedes4aab14e2012-02-17 20:39:36 -03002301 hdev->discovery.type = cp->type;
2302
2303 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002304 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002305 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002306 break;
2307
2308 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002309 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2310 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002311 break;
2312
Andre Guedes5e0452c2012-02-17 20:39:38 -03002313 case DISCOV_TYPE_INTERLEAVED:
2314 err = discovery(hdev);
2315 break;
2316
Andre Guedesf39799f2012-02-17 20:39:35 -03002317 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002318 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002319 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002320
Johan Hedberg14a53662011-04-27 10:29:56 -04002321 if (err < 0)
2322 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002323 else
2324 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002325
2326failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002327 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002328 hci_dev_put(hdev);
2329
2330 return err;
2331}
2332
Johan Hedbergd9306502012-02-20 23:25:18 +02002333static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002334{
Johan Hedbergd9306502012-02-20 23:25:18 +02002335 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002336 struct hci_dev *hdev;
2337 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002338 struct hci_cp_remote_name_req_cancel cp;
2339 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002340 int err;
2341
2342 BT_DBG("hci%u", index);
2343
Johan Hedbergd9306502012-02-20 23:25:18 +02002344 if (len != sizeof(*mgmt_cp))
2345 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2346 MGMT_STATUS_INVALID_PARAMS);
2347
Johan Hedberg14a53662011-04-27 10:29:56 -04002348 hdev = hci_dev_get(index);
2349 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002350 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2351 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002352
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002353 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002354
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002355 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002356 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2357 MGMT_STATUS_REJECTED,
2358 &mgmt_cp->type, sizeof(mgmt_cp->type));
2359 goto unlock;
2360 }
2361
2362 if (hdev->discovery.type != mgmt_cp->type) {
2363 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2364 MGMT_STATUS_INVALID_PARAMS,
2365 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002366 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002367 }
2368
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002369 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002370 if (!cmd) {
2371 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002372 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002373 }
2374
Andre Guedes343f9352012-02-17 20:39:37 -03002375 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002376 err = hci_cancel_inquiry(hdev);
2377 if (err < 0)
2378 mgmt_pending_remove(cmd);
2379 else
2380 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2381 goto unlock;
2382 }
2383
2384 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2385 if (!e) {
2386 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002387 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002388 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002389 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2390 goto unlock;
2391 }
2392
2393 bacpy(&cp.bdaddr, &e->data.bdaddr);
2394 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2395 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002396 if (err < 0)
2397 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002398 else
2399 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002400
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002401unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002402 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002403 hci_dev_put(hdev);
2404
2405 return err;
2406}
2407
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002408static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002409{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002410 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002411 struct inquiry_entry *e;
2412 struct hci_dev *hdev;
2413 int err;
2414
2415 BT_DBG("hci%u", index);
2416
2417 if (len != sizeof(*cp))
2418 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2419 MGMT_STATUS_INVALID_PARAMS);
2420
2421 hdev = hci_dev_get(index);
2422 if (!hdev)
2423 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2424 MGMT_STATUS_INVALID_PARAMS);
2425
2426 hci_dev_lock(hdev);
2427
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002428 if (!hci_discovery_active(hdev)) {
2429 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2430 MGMT_STATUS_FAILED);
2431 goto failed;
2432 }
2433
Johan Hedberga198e7b2012-02-17 14:27:06 +02002434 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002435 if (!e) {
2436 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2437 MGMT_STATUS_INVALID_PARAMS);
2438 goto failed;
2439 }
2440
2441 if (cp->name_known) {
2442 e->name_state = NAME_KNOWN;
2443 list_del(&e->list);
2444 } else {
2445 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002446 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002447 }
2448
2449 err = 0;
2450
2451failed:
2452 hci_dev_unlock(hdev);
2453
2454 return err;
2455}
2456
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002457static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002458{
2459 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002460 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002461 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002462 int err;
2463
2464 BT_DBG("hci%u", index);
2465
Antti Julku7fbec222011-06-15 12:01:15 +03002466 if (len != sizeof(*cp))
2467 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002468 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002469
2470 hdev = hci_dev_get(index);
2471 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002472 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2473 MGMT_STATUS_INVALID_PARAMS,
2474 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002475
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002476 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002477
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002478 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002479 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002480 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002481 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002482 status = 0;
2483
2484 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2485 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002486
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002487 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002488 hci_dev_put(hdev);
2489
2490 return err;
2491}
2492
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002493static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002494{
2495 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002496 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002497 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002498 int err;
2499
2500 BT_DBG("hci%u", index);
2501
Antti Julku7fbec222011-06-15 12:01:15 +03002502 if (len != sizeof(*cp))
2503 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002504 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002505
2506 hdev = hci_dev_get(index);
2507 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002508 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2509 MGMT_STATUS_INVALID_PARAMS,
2510 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002511
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002512 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002513
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002514 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002515 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002516 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002517 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002518 status = 0;
2519
2520 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2521 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002522
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002523 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002524 hci_dev_put(hdev);
2525
2526 return err;
2527}
2528
Antti Julkuf6422ec2011-06-22 13:11:56 +03002529static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002530 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002531{
2532 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002533 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002534 struct hci_cp_write_page_scan_activity acp;
2535 u8 type;
2536 int err;
2537
2538 BT_DBG("hci%u", index);
2539
2540 if (len != sizeof(*cp))
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 hdev = hci_dev_get(index);
2545 if (!hdev)
2546 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002547 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002548
2549 hci_dev_lock(hdev);
2550
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002551 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002552 type = PAGE_SCAN_TYPE_INTERLACED;
2553 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2554 } else {
2555 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2556 acp.interval = 0x0800; /* default 1.28 sec page scan */
2557 }
2558
2559 acp.window = 0x0012; /* default 11.25 msec page scan window */
2560
2561 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2562 sizeof(acp), &acp);
2563 if (err < 0) {
2564 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002565 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002566 goto done;
2567 }
2568
2569 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2570 if (err < 0) {
2571 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002572 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002573 goto done;
2574 }
2575
Johan Hedbergaee9b212012-02-18 15:07:59 +02002576 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2577 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002578done:
2579 hci_dev_unlock(hdev);
2580 hci_dev_put(hdev);
2581
2582 return err;
2583}
2584
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002585static int load_long_term_keys(struct sock *sk, u16 index,
2586 void *cp_data, u16 len)
2587{
2588 struct hci_dev *hdev;
2589 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2590 u16 key_count, expected_len;
2591 int i;
2592
2593 if (len < sizeof(*cp))
2594 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2595 EINVAL);
2596
2597 key_count = get_unaligned_le16(&cp->key_count);
2598
2599 expected_len = sizeof(*cp) + key_count *
2600 sizeof(struct mgmt_ltk_info);
2601 if (expected_len != len) {
2602 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2603 len, expected_len);
2604 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2605 EINVAL);
2606 }
2607
2608 hdev = hci_dev_get(index);
2609 if (!hdev)
2610 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2611 ENODEV);
2612
2613 BT_DBG("hci%u key_count %u", index, key_count);
2614
2615 hci_dev_lock(hdev);
2616
2617 hci_smp_ltks_clear(hdev);
2618
2619 for (i = 0; i < key_count; i++) {
2620 struct mgmt_ltk_info *key = &cp->keys[i];
2621 u8 type;
2622
2623 if (key->master)
2624 type = HCI_SMP_LTK;
2625 else
2626 type = HCI_SMP_LTK_SLAVE;
2627
2628 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2629 type, 0, key->authenticated, key->val,
2630 key->enc_size, key->ediv, key->rand);
2631 }
2632
2633 hci_dev_unlock(hdev);
2634 hci_dev_put(hdev);
2635
2636 return 0;
2637}
2638
Johan Hedberg03811012010-12-08 00:21:06 +02002639int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2640{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002641 void *buf;
2642 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002643 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002644 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002645 int err;
2646
2647 BT_DBG("got %zu bytes", msglen);
2648
2649 if (msglen < sizeof(*hdr))
2650 return -EINVAL;
2651
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002652 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002653 if (!buf)
2654 return -ENOMEM;
2655
2656 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2657 err = -EFAULT;
2658 goto done;
2659 }
2660
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002661 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002662 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002663 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002664 len = get_unaligned_le16(&hdr->len);
2665
2666 if (len != msglen - sizeof(*hdr)) {
2667 err = -EINVAL;
2668 goto done;
2669 }
2670
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002671 cp = buf + sizeof(*hdr);
2672
Johan Hedberg03811012010-12-08 00:21:06 +02002673 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002674 case MGMT_OP_READ_VERSION:
2675 err = read_version(sk);
2676 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002677 case MGMT_OP_READ_COMMANDS:
2678 err = read_commands(sk);
2679 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002680 case MGMT_OP_READ_INDEX_LIST:
2681 err = read_index_list(sk);
2682 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002683 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002684 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002685 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002686 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002687 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002688 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002689 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002690 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002691 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002692 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002693 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002694 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002695 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002696 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002697 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002698 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002699 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002700 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002701 case MGMT_OP_SET_LINK_SECURITY:
2702 err = set_link_security(sk, index, cp, len);
2703 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002704 case MGMT_OP_SET_SSP:
2705 err = set_ssp(sk, index, cp, len);
2706 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002707 case MGMT_OP_SET_HS:
2708 err = set_hs(sk, index, cp, len);
2709 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002710 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002711 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002712 break;
2713 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002714 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002715 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002716 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002717 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002718 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002719 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002720 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002721 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002722 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002723 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002724 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002725 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002726 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002727 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002728 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002729 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002730 break;
2731 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002732 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002733 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002734 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002735 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002736 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002737 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002738 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002739 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002740 case MGMT_OP_CANCEL_PAIR_DEVICE:
2741 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2742 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002743 case MGMT_OP_UNPAIR_DEVICE:
2744 err = unpair_device(sk, index, cp, len);
2745 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002746 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002747 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002748 break;
2749 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002750 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002751 break;
Brian Gix604086b2011-11-23 08:28:33 -08002752 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002753 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002754 break;
2755 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002756 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002757 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002758 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002759 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002760 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002761 case MGMT_OP_READ_LOCAL_OOB_DATA:
2762 err = read_local_oob_data(sk, index);
2763 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002764 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002765 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002766 break;
2767 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002768 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002769 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002770 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002771 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002772 break;
2773 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002774 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002775 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002776 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002777 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002778 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002779 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002780 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002781 break;
2782 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002783 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002784 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002785 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2786 err = load_long_term_keys(sk, index, cp, len);
2787 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002788 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002789 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002790 err = cmd_status(sk, index, opcode,
2791 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002792 break;
2793 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002794
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002795 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002796 goto done;
2797
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002798 err = msglen;
2799
2800done:
2801 kfree(buf);
2802 return err;
2803}
2804
Johan Hedbergb24752f2011-11-03 14:40:33 +02002805static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2806{
2807 u8 *status = data;
2808
2809 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2810 mgmt_pending_remove(cmd);
2811}
2812
Johan Hedberg744cf192011-11-08 20:40:14 +02002813int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002814{
Johan Hedberg744cf192011-11-08 20:40:14 +02002815 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002816}
2817
Johan Hedberg744cf192011-11-08 20:40:14 +02002818int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002819{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002820 u8 status = ENODEV;
2821
Johan Hedberg744cf192011-11-08 20:40:14 +02002822 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002823
Johan Hedberg744cf192011-11-08 20:40:14 +02002824 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002825}
2826
2827struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002828 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002829 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002830};
2831
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002832static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002833{
Johan Hedberg03811012010-12-08 00:21:06 +02002834 struct cmd_lookup *match = data;
2835
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002836 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002837
2838 list_del(&cmd->list);
2839
2840 if (match->sk == NULL) {
2841 match->sk = cmd->sk;
2842 sock_hold(match->sk);
2843 }
2844
2845 mgmt_pending_free(cmd);
2846}
2847
Johan Hedberg744cf192011-11-08 20:40:14 +02002848int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002849{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002850 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002851 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002852 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002853
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002854 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002855
Johan Hedbergb24752f2011-11-03 14:40:33 +02002856 if (!powered) {
2857 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002858 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002859 }
2860
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002861 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002862
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002863 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002864 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002865
2866 if (match.sk)
2867 sock_put(match.sk);
2868
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002869 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002870}
2871
Johan Hedberg744cf192011-11-08 20:40:14 +02002872int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002873{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002874 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002875 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002876 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002877
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002878 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002879
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002880 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002881
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002882 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002883 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002884 if (match.sk)
2885 sock_put(match.sk);
2886
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002887 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002888}
2889
Johan Hedberg744cf192011-11-08 20:40:14 +02002890int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002891{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002892 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002893 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002894 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002895
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002896 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2897 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002898
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002899 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002900
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002901 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002902
2903 if (match.sk)
2904 sock_put(match.sk);
2905
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002906 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002907}
2908
Johan Hedberg744cf192011-11-08 20:40:14 +02002909int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002910{
Johan Hedbergca69b792011-11-11 18:10:00 +02002911 u8 mgmt_err = mgmt_status(status);
2912
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002913 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002914 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002915 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002916
2917 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002918 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002919 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002920
2921 return 0;
2922}
2923
Johan Hedberg744cf192011-11-08 20:40:14 +02002924int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2925 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002926{
Johan Hedberg86742e12011-11-07 23:13:38 +02002927 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002928
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002929 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002930
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002931 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002932 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2933 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002934 ev.key.type = key->type;
2935 memcpy(ev.key.val, key->val, 16);
2936 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002937
Johan Hedberg744cf192011-11-08 20:40:14 +02002938 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002939}
Johan Hedbergf7520542011-01-20 12:34:39 +02002940
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002941int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2942{
2943 struct mgmt_ev_new_long_term_key ev;
2944
2945 memset(&ev, 0, sizeof(ev));
2946
2947 ev.store_hint = persistent;
2948 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2949 ev.key.addr.type = key->bdaddr_type;
2950 ev.key.authenticated = key->authenticated;
2951 ev.key.enc_size = key->enc_size;
2952 ev.key.ediv = key->ediv;
2953
2954 if (key->type == HCI_SMP_LTK)
2955 ev.key.master = 1;
2956
2957 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2958 memcpy(ev.key.val, key->val, sizeof(key->val));
2959
2960 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2961 &ev, sizeof(ev), NULL);
2962}
2963
Johan Hedbergafc747a2012-01-15 18:11:07 +02002964int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002965 u8 addr_type, u8 *name, u8 name_len,
2966 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002967{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002968 char buf[512];
2969 struct mgmt_ev_device_connected *ev = (void *) buf;
2970 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002971
Johan Hedbergb644ba32012-01-17 21:48:47 +02002972 bacpy(&ev->addr.bdaddr, bdaddr);
2973 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002974
Johan Hedbergb644ba32012-01-17 21:48:47 +02002975 if (name_len > 0)
2976 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2977 name, name_len);
2978
2979 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2980 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2981 EIR_CLASS_OF_DEV, dev_class, 3);
2982
2983 put_unaligned_le16(eir_len, &ev->eir_len);
2984
2985 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2986 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002987}
2988
Johan Hedberg8962ee72011-01-20 12:40:27 +02002989static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2990{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002991 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002992 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002993 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002994
Johan Hedberg88c3df12012-02-09 14:27:38 +02002995 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2996 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002997
Johan Hedbergaee9b212012-02-18 15:07:59 +02002998 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
2999 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003000
3001 *sk = cmd->sk;
3002 sock_hold(*sk);
3003
Johan Hedberga664b5b2011-02-19 12:06:02 -03003004 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003005}
3006
Johan Hedberg124f6e32012-02-09 13:50:12 +02003007static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003008{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003009 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003010 struct mgmt_cp_unpair_device *cp = cmd->param;
3011 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003012
3013 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003014 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3015 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003016
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003017 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3018
Johan Hedbergaee9b212012-02-18 15:07:59 +02003019 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003020
3021 mgmt_pending_remove(cmd);
3022}
3023
Johan Hedbergafc747a2012-01-15 18:11:07 +02003024int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3025 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003026{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003027 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003028 struct sock *sk = NULL;
3029 int err;
3030
Johan Hedberg744cf192011-11-08 20:40:14 +02003031 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003032
Johan Hedbergf7520542011-01-20 12:34:39 +02003033 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003034 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003035
Johan Hedbergafc747a2012-01-15 18:11:07 +02003036 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3037 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003038
3039 if (sk)
3040 sock_put(sk);
3041
Johan Hedberg124f6e32012-02-09 13:50:12 +02003042 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003043 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003044
Johan Hedberg8962ee72011-01-20 12:40:27 +02003045 return err;
3046}
3047
Johan Hedberg88c3df12012-02-09 14:27:38 +02003048int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3049 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003050{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003051 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003052 struct pending_cmd *cmd;
3053 int err;
3054
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003055 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003056 if (!cmd)
3057 return -ENOENT;
3058
Johan Hedberg88c3df12012-02-09 14:27:38 +02003059 bacpy(&rp.addr.bdaddr, bdaddr);
3060 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003061
Johan Hedberg88c3df12012-02-09 14:27:38 +02003062 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003063 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003064
Johan Hedberga664b5b2011-02-19 12:06:02 -03003065 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003066
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003067 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3068 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003069 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003070}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003071
Johan Hedberg48264f02011-11-09 13:58:58 +02003072int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3073 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003074{
3075 struct mgmt_ev_connect_failed ev;
3076
Johan Hedberg4c659c32011-11-07 23:13:39 +02003077 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003078 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003079 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003080
Johan Hedberg744cf192011-11-08 20:40:14 +02003081 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003082}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003083
Johan Hedberg744cf192011-11-08 20:40:14 +02003084int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003085{
3086 struct mgmt_ev_pin_code_request ev;
3087
Johan Hedbergd8457692012-02-17 14:24:57 +02003088 bacpy(&ev.addr.bdaddr, bdaddr);
3089 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003090 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003091
Johan Hedberg744cf192011-11-08 20:40:14 +02003092 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003093 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003094}
3095
Johan Hedberg744cf192011-11-08 20:40:14 +02003096int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3097 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003098{
3099 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003100 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003101 int err;
3102
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003103 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003104 if (!cmd)
3105 return -ENOENT;
3106
Johan Hedbergd8457692012-02-17 14:24:57 +02003107 bacpy(&rp.addr.bdaddr, bdaddr);
3108 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003109
Johan Hedbergaee9b212012-02-18 15:07:59 +02003110 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3111 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003112
Johan Hedberga664b5b2011-02-19 12:06:02 -03003113 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003114
3115 return err;
3116}
3117
Johan Hedberg744cf192011-11-08 20:40:14 +02003118int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3119 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003120{
3121 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003122 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003123 int err;
3124
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003125 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003126 if (!cmd)
3127 return -ENOENT;
3128
Johan Hedbergd8457692012-02-17 14:24:57 +02003129 bacpy(&rp.addr.bdaddr, bdaddr);
3130 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003131
Johan Hedbergaee9b212012-02-18 15:07:59 +02003132 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3133 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003134
Johan Hedberga664b5b2011-02-19 12:06:02 -03003135 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003136
3137 return err;
3138}
Johan Hedberga5c29682011-02-19 12:05:57 -03003139
Johan Hedberg744cf192011-11-08 20:40:14 +02003140int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003141 u8 link_type, u8 addr_type, __le32 value,
3142 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003143{
3144 struct mgmt_ev_user_confirm_request ev;
3145
Johan Hedberg744cf192011-11-08 20:40:14 +02003146 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003147
Johan Hedberg272d90d2012-02-09 15:26:12 +02003148 bacpy(&ev.addr.bdaddr, bdaddr);
3149 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003150 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003151 put_unaligned_le32(value, &ev.value);
3152
Johan Hedberg744cf192011-11-08 20:40:14 +02003153 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003154 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003155}
3156
Johan Hedberg272d90d2012-02-09 15:26:12 +02003157int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3158 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003159{
3160 struct mgmt_ev_user_passkey_request ev;
3161
3162 BT_DBG("%s", hdev->name);
3163
Johan Hedberg272d90d2012-02-09 15:26:12 +02003164 bacpy(&ev.addr.bdaddr, bdaddr);
3165 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003166
3167 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3168 NULL);
3169}
3170
Brian Gix0df4c182011-11-16 13:53:13 -08003171static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003172 u8 link_type, u8 addr_type, u8 status,
3173 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003174{
3175 struct pending_cmd *cmd;
3176 struct mgmt_rp_user_confirm_reply rp;
3177 int err;
3178
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003179 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003180 if (!cmd)
3181 return -ENOENT;
3182
Johan Hedberg272d90d2012-02-09 15:26:12 +02003183 bacpy(&rp.addr.bdaddr, bdaddr);
3184 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003185 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3186 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003187
Johan Hedberga664b5b2011-02-19 12:06:02 -03003188 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003189
3190 return err;
3191}
3192
Johan Hedberg744cf192011-11-08 20:40:14 +02003193int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003194 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003195{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003196 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3197 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003198}
3199
Johan Hedberg272d90d2012-02-09 15:26:12 +02003200int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3201 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003202{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003203 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3204 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003205}
Johan Hedberg2a611692011-02-19 12:06:00 -03003206
Brian Gix604086b2011-11-23 08:28:33 -08003207int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003208 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003209{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003210 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3211 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003212}
3213
Johan Hedberg272d90d2012-02-09 15:26:12 +02003214int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3215 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003216{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003217 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3218 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003219}
3220
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003221int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3222 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003223{
3224 struct mgmt_ev_auth_failed ev;
3225
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003226 bacpy(&ev.addr.bdaddr, bdaddr);
3227 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003228 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003229
Johan Hedberg744cf192011-11-08 20:40:14 +02003230 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003231}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003232
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003233int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3234{
3235 struct cmd_lookup match = { NULL, hdev };
3236 __le32 ev;
3237 int err;
3238
3239 if (status) {
3240 u8 mgmt_err = mgmt_status(status);
3241 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3242 cmd_status_rsp, &mgmt_err);
3243 return 0;
3244 }
3245
3246 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3247 &match);
3248
3249 ev = cpu_to_le32(get_current_settings(hdev));
3250 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3251
3252 if (match.sk)
3253 sock_put(match.sk);
3254
3255 return err;
3256}
3257
Johan Hedbergcacaf522012-02-21 00:52:42 +02003258static int clear_eir(struct hci_dev *hdev)
3259{
3260 struct hci_cp_write_eir cp;
3261
3262 if (!(hdev->features[6] & LMP_EXT_INQ))
3263 return 0;
3264
3265 memset(&cp, 0, sizeof(cp));
3266
3267 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3268}
3269
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003270int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3271{
3272 struct cmd_lookup match = { NULL, hdev };
3273 __le32 ev;
3274 int err;
3275
3276 if (status) {
3277 u8 mgmt_err = mgmt_status(status);
3278 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3279 cmd_status_rsp, &mgmt_err);
3280 return 0;
3281 }
3282
3283 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3284
3285 ev = cpu_to_le32(get_current_settings(hdev));
3286 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3287
Johan Hedbergcacaf522012-02-21 00:52:42 +02003288 if (match.sk) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003289 sock_put(match.sk);
3290
Johan Hedbergcacaf522012-02-21 00:52:42 +02003291 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3292 update_eir(hdev);
3293 else
3294 clear_eir(hdev);
3295 }
3296
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003297 return err;
3298}
3299
Johan Hedberg744cf192011-11-08 20:40:14 +02003300int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003301{
3302 struct pending_cmd *cmd;
3303 struct mgmt_cp_set_local_name ev;
3304 int err;
3305
3306 memset(&ev, 0, sizeof(ev));
3307 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3308
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003309 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003310 if (!cmd)
3311 goto send_event;
3312
3313 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003314 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003315 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003316 goto failed;
3317 }
3318
Johan Hedberg744cf192011-11-08 20:40:14 +02003319 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003320
Johan Hedbergaee9b212012-02-18 15:07:59 +02003321 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003322 sizeof(ev));
3323 if (err < 0)
3324 goto failed;
3325
3326send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003327 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003328 cmd ? cmd->sk : NULL);
3329
3330failed:
3331 if (cmd)
3332 mgmt_pending_remove(cmd);
3333 return err;
3334}
Szymon Jancc35938b2011-03-22 13:12:21 +01003335
Johan Hedberg744cf192011-11-08 20:40:14 +02003336int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3337 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003338{
3339 struct pending_cmd *cmd;
3340 int err;
3341
Johan Hedberg744cf192011-11-08 20:40:14 +02003342 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003343
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003344 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003345 if (!cmd)
3346 return -ENOENT;
3347
3348 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003349 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003350 MGMT_OP_READ_LOCAL_OOB_DATA,
3351 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003352 } else {
3353 struct mgmt_rp_read_local_oob_data rp;
3354
3355 memcpy(rp.hash, hash, sizeof(rp.hash));
3356 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3357
Johan Hedberg744cf192011-11-08 20:40:14 +02003358 err = cmd_complete(cmd->sk, hdev->id,
3359 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003360 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003361 }
3362
3363 mgmt_pending_remove(cmd);
3364
3365 return err;
3366}
Johan Hedberge17acd42011-03-30 23:57:16 +03003367
Johan Hedberg48264f02011-11-09 13:58:58 +02003368int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003369 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003370 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003371{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003372 char buf[512];
3373 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003374 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003375
Johan Hedberg1dc06092012-01-15 21:01:23 +02003376 /* Leave 5 bytes for a potential CoD field */
3377 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003378 return -EINVAL;
3379
Johan Hedberg1dc06092012-01-15 21:01:23 +02003380 memset(buf, 0, sizeof(buf));
3381
Johan Hedberge319d2e2012-01-15 19:51:59 +02003382 bacpy(&ev->addr.bdaddr, bdaddr);
3383 ev->addr.type = link_to_mgmt(link_type, addr_type);
3384 ev->rssi = rssi;
3385 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003386
Johan Hedberg1dc06092012-01-15 21:01:23 +02003387 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003388 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003389
Johan Hedberg1dc06092012-01-15 21:01:23 +02003390 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3391 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3392 dev_class, 3);
3393
3394 put_unaligned_le16(eir_len, &ev->eir_len);
3395
3396 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003397
Johan Hedberge319d2e2012-01-15 19:51:59 +02003398 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003399}
Johan Hedberga88a9652011-03-30 13:18:12 +03003400
Johan Hedbergb644ba32012-01-17 21:48:47 +02003401int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3402 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003403{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003404 struct mgmt_ev_device_found *ev;
3405 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3406 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003407
Johan Hedbergb644ba32012-01-17 21:48:47 +02003408 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003409
Johan Hedbergb644ba32012-01-17 21:48:47 +02003410 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003411
Johan Hedbergb644ba32012-01-17 21:48:47 +02003412 bacpy(&ev->addr.bdaddr, bdaddr);
3413 ev->addr.type = link_to_mgmt(link_type, addr_type);
3414 ev->rssi = rssi;
3415
3416 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3417 name_len);
3418
3419 put_unaligned_le16(eir_len, &ev->eir_len);
3420
Johan Hedberg053c7e02012-02-04 00:06:00 +02003421 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3422 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003423}
Johan Hedberg314b2382011-04-27 10:29:57 -04003424
Andre Guedes7a135102011-11-09 17:14:25 -03003425int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003426{
3427 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003428 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003429 int err;
3430
Andre Guedes203159d2012-02-13 15:41:01 -03003431 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3432
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003433 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003434 if (!cmd)
3435 return -ENOENT;
3436
Johan Hedbergf808e162012-02-19 12:52:07 +02003437 type = hdev->discovery.type;
3438
3439 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3440 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003441 mgmt_pending_remove(cmd);
3442
3443 return err;
3444}
3445
Andre Guedese6d465c2011-11-09 17:14:26 -03003446int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3447{
3448 struct pending_cmd *cmd;
3449 int err;
3450
3451 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3452 if (!cmd)
3453 return -ENOENT;
3454
Johan Hedbergd9306502012-02-20 23:25:18 +02003455 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3456 &hdev->discovery.type,
3457 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003458 mgmt_pending_remove(cmd);
3459
3460 return err;
3461}
Johan Hedberg314b2382011-04-27 10:29:57 -04003462
Johan Hedberg744cf192011-11-08 20:40:14 +02003463int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003464{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003465 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003466 struct pending_cmd *cmd;
3467
Andre Guedes343fb142011-11-22 17:14:19 -03003468 BT_DBG("%s discovering %u", hdev->name, discovering);
3469
Johan Hedberg164a6e72011-11-01 17:06:44 +02003470 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003471 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003472 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003473 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003474
3475 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003476 u8 type = hdev->discovery.type;
3477
Johan Hedbergd9306502012-02-20 23:25:18 +02003478 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003479 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003480 mgmt_pending_remove(cmd);
3481 }
3482
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003483 memset(&ev, 0, sizeof(ev));
3484 ev.type = hdev->discovery.type;
3485 ev.discovering = discovering;
3486
3487 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003488}
Antti Julku5e762442011-08-25 16:48:02 +03003489
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003490int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003491{
3492 struct pending_cmd *cmd;
3493 struct mgmt_ev_device_blocked ev;
3494
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003495 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003496
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003497 bacpy(&ev.addr.bdaddr, bdaddr);
3498 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003499
Johan Hedberg744cf192011-11-08 20:40:14 +02003500 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3501 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003502}
3503
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003504int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003505{
3506 struct pending_cmd *cmd;
3507 struct mgmt_ev_device_unblocked ev;
3508
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003509 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003510
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003511 bacpy(&ev.addr.bdaddr, bdaddr);
3512 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003513
Johan Hedberg744cf192011-11-08 20:40:14 +02003514 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3515 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003516}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003517
3518module_param(enable_hs, bool, 0644);
3519MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3520
3521module_param(enable_le, bool, 0644);
3522MODULE_PARM_DESC(enable_le, "Enable Low Energy support");