blob: 3f4c50eebbeae9de32e4b47f7b051cceabaedd76 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
81};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Johan Hedberg7d785252011-12-15 00:47:39 +0200119#define SERVICE_CACHE_TIMEOUT (5 * 1000)
120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
227 put_unaligned_le16(cmd, &ev->opcode);
228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
257 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Johan Hedberga38528f2011-01-22 06:46:43 +0200270static int read_version(struct sock *sk)
271{
272 struct mgmt_rp_read_version rp;
273
274 BT_DBG("sock %p", sk);
275
276 rp.version = MGMT_VERSION;
277 put_unaligned_le16(MGMT_REVISION, &rp.revision);
278
Johan Hedbergaee9b212012-02-18 15:07:59 +0200279 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100280 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200281}
282
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200283static int read_commands(struct sock *sk)
284{
285 struct mgmt_rp_read_commands *rp;
286 u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 u16 num_events = ARRAY_SIZE(mgmt_events);
288 u16 *opcode;
289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
300 put_unaligned_le16(num_commands, &rp->num_commands);
301 put_unaligned_le16(num_events, &rp->num_events);
302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b212012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200310 rp_size);
311 kfree(rp);
312
313 return err;
314}
315
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316static int read_index_list(struct sock *sk)
317{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318 struct mgmt_rp_read_index_list *rp;
319 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200320 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200321 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200324
325 BT_DBG("sock %p", sk);
326
327 read_lock(&hci_dev_list_lock);
328
329 count = 0;
330 list_for_each(p, &hci_dev_list) {
331 count++;
332 }
333
Johan Hedberga38528f2011-01-22 06:46:43 +0200334 rp_len = sizeof(*rp) + (2 * count);
335 rp = kmalloc(rp_len, GFP_ATOMIC);
336 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100337 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200338 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100339 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 put_unaligned_le16(count, &rp->num_controllers);
342
343 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200344 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200345 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200346 continue;
347
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348 put_unaligned_le16(d->id, &rp->index[i++]);
349 BT_DBG("Added hci%u", d->id);
350 }
351
352 read_unlock(&hci_dev_list_lock);
353
Johan Hedbergaee9b212012-02-18 15:07:59 +0200354 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100355 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200356
Johan Hedberga38528f2011-01-22 06:46:43 +0200357 kfree(rp);
358
359 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360}
361
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200362static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200363{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 settings |= MGMT_SETTING_POWERED;
367 settings |= MGMT_SETTING_CONNECTABLE;
368 settings |= MGMT_SETTING_FAST_CONNECTABLE;
369 settings |= MGMT_SETTING_DISCOVERABLE;
370 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[6] & LMP_SIMPLE_PAIR)
373 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (!(hdev->features[4] & LMP_NO_BREDR)) {
376 settings |= MGMT_SETTING_BREDR;
377 settings |= MGMT_SETTING_LINK_SECURITY;
378 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200379
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100380 if (enable_hs)
381 settings |= MGMT_SETTING_HS;
382
383 if (enable_le) {
384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
386 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200387
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200388 return settings;
389}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200390
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200391static u32 get_current_settings(struct hci_dev *hdev)
392{
393 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200394
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200395 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100396 settings |= MGMT_SETTING_POWERED;
397
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200398 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_CONNECTABLE;
400
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200401 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 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
Johan Hedberg47990ea2012-02-22 11:58:37 +0200413 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200414 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200415
Johan Hedberg84bde9d6c2012-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 Hedberg84bde9d6c2012-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 Hedberg0cbf4ed2012-02-21 17:25:22 +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 Hedberg0cbf4ed2012-02-21 17:25:22 +0200607 /* Non-mgmt controlled devices get this bit set
608 * implicitly so that pairing works for them, however
609 * for mgmt we require user-space to explicitly enable
610 * it
611 */
612 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
613 }
614
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200615 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200616 schedule_delayed_work(&hdev->service_cache,
617 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
618}
619
Johan Hedberg03811012010-12-08 00:21:06 +0200620static int read_controller_info(struct sock *sk, u16 index)
621{
622 struct mgmt_rp_read_info rp;
623 struct hci_dev *hdev;
624
625 BT_DBG("sock %p hci%u", sk, index);
626
627 hdev = hci_dev_get(index);
628 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200629 return cmd_status(sk, index, MGMT_OP_READ_INFO,
630 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300632 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Johan Hedberg7d785252011-12-15 00:47:39 +0200634 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
635 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200636
637 memset(&rp, 0, sizeof(rp));
638
Johan Hedberg03811012010-12-08 00:21:06 +0200639 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200640
641 rp.version = hdev->hci_ver;
642
Johan Hedberg03811012010-12-08 00:21:06 +0200643 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200644
645 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
646 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
647
648 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200649
650 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
651
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300652 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200653 hci_dev_put(hdev);
654
Johan Hedbergaee9b212012-02-18 15:07:59 +0200655 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200656}
657
658static void mgmt_pending_free(struct pending_cmd *cmd)
659{
660 sock_put(cmd->sk);
661 kfree(cmd->param);
662 kfree(cmd);
663}
664
665static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
666 struct hci_dev *hdev,
667 void *data, u16 len)
668{
669 struct pending_cmd *cmd;
670
671 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
672 if (!cmd)
673 return NULL;
674
675 cmd->opcode = opcode;
676 cmd->index = hdev->id;
677
678 cmd->param = kmalloc(len, GFP_ATOMIC);
679 if (!cmd->param) {
680 kfree(cmd);
681 return NULL;
682 }
683
684 if (data)
685 memcpy(cmd->param, data, len);
686
687 cmd->sk = sk;
688 sock_hold(sk);
689
690 list_add(&cmd->list, &hdev->mgmt_pending);
691
692 return cmd;
693}
694
695static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
696 void (*cb)(struct pending_cmd *cmd, void *data),
697 void *data)
698{
699 struct list_head *p, *n;
700
701 list_for_each_safe(p, n, &hdev->mgmt_pending) {
702 struct pending_cmd *cmd;
703
704 cmd = list_entry(p, struct pending_cmd, list);
705
706 if (opcode > 0 && cmd->opcode != opcode)
707 continue;
708
709 cb(cmd, data);
710 }
711}
712
713static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
714{
715 struct pending_cmd *cmd;
716
717 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
718 if (cmd->opcode == opcode)
719 return cmd;
720 }
721
722 return NULL;
723}
724
725static void mgmt_pending_remove(struct pending_cmd *cmd)
726{
727 list_del(&cmd->list);
728 mgmt_pending_free(cmd);
729}
730
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200731static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200732{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200733 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200734
Johan Hedbergaee9b212012-02-18 15:07:59 +0200735 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
736 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200737}
738
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300739static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200740{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300741 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200742 struct hci_dev *hdev;
743 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200744 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200745
Johan Hedberg03811012010-12-08 00:21:06 +0200746 BT_DBG("request for hci%u", index);
747
748 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200749 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200751
752 hdev = hci_dev_get(index);
753 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200754 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
755 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200756
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300757 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200758
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100759 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
760 cancel_delayed_work(&hdev->power_off);
761
762 if (cp->val) {
763 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
764 mgmt_powered(hdev, 1);
765 goto failed;
766 }
767 }
768
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200769 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200770 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200771 goto failed;
772 }
773
774 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200775 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
776 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200777 goto failed;
778 }
779
780 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
781 if (!cmd) {
782 err = -ENOMEM;
783 goto failed;
784 }
785
786 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200787 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200789 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200790
791 err = 0;
792
793failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300794 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200795 hci_dev_put(hdev);
796 return err;
797}
798
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200799static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
800 u16 data_len, struct sock *skip_sk)
801{
802 struct sk_buff *skb;
803 struct mgmt_hdr *hdr;
804
805 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
806 if (!skb)
807 return -ENOMEM;
808
809 hdr = (void *) skb_put(skb, sizeof(*hdr));
810 hdr->opcode = cpu_to_le16(event);
811 if (hdev)
812 hdr->index = cpu_to_le16(hdev->id);
813 else
814 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
815 hdr->len = cpu_to_le16(data_len);
816
817 if (data)
818 memcpy(skb_put(skb, data_len), data, data_len);
819
820 hci_send_to_control(skb, skip_sk);
821 kfree_skb(skb);
822
823 return 0;
824}
825
826static int new_settings(struct hci_dev *hdev, struct sock *skip)
827{
828 __le32 ev;
829
830 ev = cpu_to_le32(get_current_settings(hdev));
831
832 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
833}
834
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300835static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200836{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300837 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200838 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200839 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200840 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200841 u8 scan;
842 int err;
843
Johan Hedberg03811012010-12-08 00:21:06 +0200844 BT_DBG("request for hci%u", index);
845
846 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200847 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
848 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200849
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200850 hdev = hci_dev_get(index);
851 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200852 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
853 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200854
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200855 timeout = get_unaligned_le16(&cp->timeout);
856
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300857 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200858
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200859 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200860 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
861 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200862 goto failed;
863 }
864
865 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
866 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200867 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
868 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200869 goto failed;
870 }
871
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200872 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
873 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
874 MGMT_STATUS_REJECTED);
875 goto failed;
876 }
877
878 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200879 bool changed = false;
880
881 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
882 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
883 changed = true;
884 }
885
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200886 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200887 if (err < 0)
888 goto failed;
889
890 if (changed)
891 err = new_settings(hdev, sk);
892
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200893 goto failed;
894 }
895
896 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200897 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200898 goto failed;
899 }
900
901 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
902 if (!cmd) {
903 err = -ENOMEM;
904 goto failed;
905 }
906
907 scan = SCAN_PAGE;
908
909 if (cp->val)
910 scan |= SCAN_INQUIRY;
911 else
912 cancel_delayed_work(&hdev->discov_off);
913
914 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
915 if (err < 0)
916 mgmt_pending_remove(cmd);
917
Johan Hedberg03811012010-12-08 00:21:06 +0200918 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200919 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200920
921failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300922 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200923 hci_dev_put(hdev);
924
925 return err;
926}
927
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300928static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200929{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300930 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200931 struct hci_dev *hdev;
932 struct pending_cmd *cmd;
933 u8 scan;
934 int err;
935
Johan Hedberge41d8b42010-12-13 21:07:03 +0200936 BT_DBG("request for hci%u", index);
937
Johan Hedberg03811012010-12-08 00:21:06 +0200938 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200939 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
940 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200941
942 hdev = hci_dev_get(index);
943 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200944 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
945 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200946
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300947 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200948
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200949 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200950 bool changed = false;
951
952 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
953 changed = true;
954
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200955 if (cp->val)
956 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
957 else {
958 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
959 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
960 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200961
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200962 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200963 if (err < 0)
964 goto failed;
965
966 if (changed)
967 err = new_settings(hdev, sk);
968
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200969 goto failed;
970 }
971
972 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
973 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200974 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
975 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200976 goto failed;
977 }
978
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200979 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200980 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200981 goto failed;
982 }
983
984 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
985 if (!cmd) {
986 err = -ENOMEM;
987 goto failed;
988 }
989
990 if (cp->val)
991 scan = SCAN_PAGE;
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200992 else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200993 scan = 0;
994
Johan Hedbergdf2c6c52012-02-21 19:15:49 +0200995 if (test_bit(HCI_ISCAN, &hdev->flags) &&
996 hdev->discov_timeout > 0)
997 cancel_delayed_work(&hdev->discov_off);
998 }
999
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001000 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1001 if (err < 0)
1002 mgmt_pending_remove(cmd);
1003
1004failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001005 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 hci_dev_put(hdev);
1007
1008 return err;
1009}
1010
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001011static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001012{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001013 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001014 struct hci_dev *hdev;
1015 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001016
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001017 BT_DBG("request for hci%u", index);
1018
1019 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001020 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1021 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001022
1023 hdev = hci_dev_get(index);
1024 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001025 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
1026 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001027
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001028 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001029
1030 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001031 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001033 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001035 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036 if (err < 0)
1037 goto failed;
1038
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001039 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
1041failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001042 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001043 hci_dev_put(hdev);
1044
1045 return err;
1046}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001047
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001048static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
1049{
1050 struct mgmt_mode *cp = data;
1051 struct pending_cmd *cmd;
1052 struct hci_dev *hdev;
1053 uint8_t val;
1054 int err;
1055
1056 BT_DBG("request for hci%u", index);
1057
1058 if (len != sizeof(*cp))
1059 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1060 MGMT_STATUS_INVALID_PARAMS);
1061
1062 hdev = hci_dev_get(index);
1063 if (!hdev)
1064 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1065 MGMT_STATUS_INVALID_PARAMS);
1066
1067 hci_dev_lock(hdev);
1068
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001069 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001070 bool changed = false;
1071
1072 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1073 &hdev->dev_flags)) {
1074 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1075 changed = true;
1076 }
1077
1078 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1079 if (err < 0)
1080 goto failed;
1081
1082 if (changed)
1083 err = new_settings(hdev, sk);
1084
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001085 goto failed;
1086 }
1087
1088 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1089 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1090 MGMT_STATUS_BUSY);
1091 goto failed;
1092 }
1093
1094 val = !!cp->val;
1095
1096 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1097 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1098 goto failed;
1099 }
1100
1101 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1102 if (!cmd) {
1103 err = -ENOMEM;
1104 goto failed;
1105 }
1106
1107 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1108 if (err < 0) {
1109 mgmt_pending_remove(cmd);
1110 goto failed;
1111 }
1112
1113failed:
1114 hci_dev_unlock(hdev);
1115 hci_dev_put(hdev);
1116
1117 return err;
1118}
1119
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001120static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1121{
1122 struct mgmt_mode *cp = data;
1123 struct pending_cmd *cmd;
1124 struct hci_dev *hdev;
1125 uint8_t val;
1126 int err;
1127
1128 BT_DBG("request for hci%u", index);
1129
1130 if (len != sizeof(*cp))
1131 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1132 MGMT_STATUS_INVALID_PARAMS);
1133
1134 hdev = hci_dev_get(index);
1135 if (!hdev)
1136 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1137 MGMT_STATUS_INVALID_PARAMS);
1138
1139 hci_dev_lock(hdev);
1140
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001141 val = !!cp->val;
1142
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001143 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001144 bool changed = false;
1145
1146 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1147 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1148 changed = true;
1149 }
1150
1151 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1152 if (err < 0)
1153 goto failed;
1154
1155 if (changed)
1156 err = new_settings(hdev, sk);
1157
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001158 goto failed;
1159 }
1160
Johan Hedberg1e163572012-02-20 23:53:46 +02001161 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1162 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1163 MGMT_STATUS_NOT_SUPPORTED);
1164 goto failed;
1165 }
1166
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001167 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1168 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1169 goto failed;
1170 }
1171
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001172 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1173 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1174 goto failed;
1175 }
1176
1177 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1178 if (!cmd) {
1179 err = -ENOMEM;
1180 goto failed;
1181 }
1182
1183 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1184 if (err < 0) {
1185 mgmt_pending_remove(cmd);
1186 goto failed;
1187 }
1188
1189failed:
1190 hci_dev_unlock(hdev);
1191 hci_dev_put(hdev);
1192
1193 return err;
1194}
1195
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001196static int set_hs(struct sock *sk, u16 index, void *data, u16 len)
1197{
1198 struct mgmt_mode *cp = data;
1199 struct hci_dev *hdev;
1200 int err;
1201
1202 BT_DBG("request for hci%u", index);
1203
1204 if (len != sizeof(*cp))
1205 return cmd_status(sk, index, MGMT_OP_SET_HS,
1206 MGMT_STATUS_INVALID_PARAMS);
1207
1208 hdev = hci_dev_get(index);
1209 if (!hdev)
1210 return cmd_status(sk, index, MGMT_OP_SET_HS,
1211 MGMT_STATUS_INVALID_PARAMS);
1212
1213 if (!enable_hs) {
1214 err = cmd_status(sk, index, MGMT_OP_SET_HS,
1215 MGMT_STATUS_NOT_SUPPORTED);
1216 goto failed;
1217 }
1218
1219 if (cp->val)
1220 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1221 else
1222 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1223
1224 err = send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
1225
1226failed:
1227 hci_dev_put(hdev);
1228 return err;
1229}
1230
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001231static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001232{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001233 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001234 struct hci_dev *hdev;
1235 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001236 int err;
1237
Szymon Janc4e51eae2011-02-25 19:05:48 +01001238 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001239
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001240 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001241 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1242 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001243
Szymon Janc4e51eae2011-02-25 19:05:48 +01001244 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001245 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001246 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1247 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001248
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001249 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001250
1251 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1252 if (!uuid) {
1253 err = -ENOMEM;
1254 goto failed;
1255 }
1256
1257 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001258 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001259
1260 list_add(&uuid->list, &hdev->uuids);
1261
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001262 err = update_class(hdev);
1263 if (err < 0)
1264 goto failed;
1265
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001266 err = update_eir(hdev);
1267 if (err < 0)
1268 goto failed;
1269
Johan Hedbergaee9b212012-02-18 15:07:59 +02001270 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001271
1272failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001273 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001274 hci_dev_put(hdev);
1275
1276 return err;
1277}
1278
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001279static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001280{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001281 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001282 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001283 struct hci_dev *hdev;
1284 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 +02001285 int err, found;
1286
Szymon Janc4e51eae2011-02-25 19:05:48 +01001287 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001288
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001289 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001290 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1291 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001292
Szymon Janc4e51eae2011-02-25 19:05:48 +01001293 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001294 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001295 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1296 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001297
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001298 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001299
1300 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1301 err = hci_uuids_clear(hdev);
1302 goto unlock;
1303 }
1304
1305 found = 0;
1306
1307 list_for_each_safe(p, n, &hdev->uuids) {
1308 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1309
1310 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1311 continue;
1312
1313 list_del(&match->list);
1314 found++;
1315 }
1316
1317 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001318 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1319 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001320 goto unlock;
1321 }
1322
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001323 err = update_class(hdev);
1324 if (err < 0)
1325 goto unlock;
1326
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001327 err = update_eir(hdev);
1328 if (err < 0)
1329 goto unlock;
1330
Johan Hedbergaee9b212012-02-18 15:07:59 +02001331 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001332
1333unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001334 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001335 hci_dev_put(hdev);
1336
1337 return err;
1338}
1339
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001340static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001341{
1342 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001343 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001344 int err;
1345
Szymon Janc4e51eae2011-02-25 19:05:48 +01001346 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001347
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001348 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001349 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1350 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001351
Szymon Janc4e51eae2011-02-25 19:05:48 +01001352 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001353 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001354 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1355 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001356
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001357 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001358
Johan Hedbergb5235a62012-02-21 14:32:24 +02001359 if (!hdev_is_powered(hdev)) {
1360 err = cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1361 MGMT_STATUS_NOT_POWERED);
1362 goto unlock;
1363 }
1364
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001365 hdev->major_class = cp->major;
1366 hdev->minor_class = cp->minor;
1367
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001368 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001369 hci_dev_unlock(hdev);
1370 cancel_delayed_work_sync(&hdev->service_cache);
1371 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001372 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001373 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001374
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001375 err = update_class(hdev);
1376
1377 if (err == 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001378 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1379 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001380
Johan Hedbergb5235a62012-02-21 14:32:24 +02001381unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001382 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001383 hci_dev_put(hdev);
1384
1385 return err;
1386}
1387
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001388static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001389{
1390 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001391 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001392 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001393 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001394
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001395 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001396 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1397 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001398
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001399 key_count = get_unaligned_le16(&cp->key_count);
1400
Johan Hedberg86742e12011-11-07 23:13:38 +02001401 expected_len = sizeof(*cp) + key_count *
1402 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001403 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001404 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001405 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001406 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1407 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001408 }
1409
Szymon Janc4e51eae2011-02-25 19:05:48 +01001410 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001411 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001412 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1413 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001414
Szymon Janc4e51eae2011-02-25 19:05:48 +01001415 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001416 key_count);
1417
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001418 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001419
1420 hci_link_keys_clear(hdev);
1421
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001422 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001423
1424 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001425 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001426 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001427 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001428
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001429 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001430 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001431
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001432 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1433 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001434 }
1435
Johan Hedbergaee9b212012-02-18 15:07:59 +02001436 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001437
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001438 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001439 hci_dev_put(hdev);
1440
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001441 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001442}
1443
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001444static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1445 u8 addr_type, struct sock *skip_sk)
1446{
1447 struct mgmt_ev_device_unpaired ev;
1448
1449 bacpy(&ev.addr.bdaddr, bdaddr);
1450 ev.addr.type = addr_type;
1451
1452 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1453 skip_sk);
1454}
1455
Johan Hedberg124f6e32012-02-09 13:50:12 +02001456static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001457{
1458 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001459 struct mgmt_cp_unpair_device *cp = data;
1460 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001461 struct hci_cp_disconnect dc;
1462 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001463 struct hci_conn *conn;
Johan Hedbergaee9b212012-02-18 15:07:59 +02001464 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001465 int err;
1466
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001467 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001468 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001469 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001470
Szymon Janc4e51eae2011-02-25 19:05:48 +01001471 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001472 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001473 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001474 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001475
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001476 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001477
Johan Hedberga8a1d192011-11-10 15:54:38 +02001478 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001479 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1480 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001481
Johan Hedberg124f6e32012-02-09 13:50:12 +02001482 if (cp->addr.type == MGMT_ADDR_BREDR)
1483 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1484 else
1485 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001486
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001487 if (err < 0) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001488 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001489 goto unlock;
1490 }
1491
Johan Hedberga8a1d192011-11-10 15:54:38 +02001492 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001493 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1494 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001495 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001496 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001497 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001498
Johan Hedberg124f6e32012-02-09 13:50:12 +02001499 if (cp->addr.type == MGMT_ADDR_BREDR)
1500 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1501 &cp->addr.bdaddr);
1502 else
1503 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1504 &cp->addr.bdaddr);
1505
Johan Hedberga8a1d192011-11-10 15:54:38 +02001506 if (!conn) {
Johan Hedbergaee9b212012-02-18 15:07:59 +02001507 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1508 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001509 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001510 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001511 }
1512
Johan Hedberg124f6e32012-02-09 13:50:12 +02001513 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1514 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001515 if (!cmd) {
1516 err = -ENOMEM;
1517 goto unlock;
1518 }
1519
1520 put_unaligned_le16(conn->handle, &dc.handle);
1521 dc.reason = 0x13; /* Remote User Terminated Connection */
1522 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1523 if (err < 0)
1524 mgmt_pending_remove(cmd);
1525
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001526unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001527 if (err < 0)
Johan Hedbergaee9b212012-02-18 15:07:59 +02001528 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1529 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001530 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001531 hci_dev_put(hdev);
1532
1533 return err;
1534}
1535
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001536static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001537{
1538 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001539 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001540 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001541 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001542 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001543 int err;
1544
1545 BT_DBG("");
1546
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001547 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001548 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1549 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001550
Szymon Janc4e51eae2011-02-25 19:05:48 +01001551 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001552 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001553 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1554 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001555
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001556 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001557
1558 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001559 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1560 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001561 goto failed;
1562 }
1563
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001564 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001565 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1566 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001567 goto failed;
1568 }
1569
Johan Hedberg88c3df12012-02-09 14:27:38 +02001570 if (cp->addr.type == MGMT_ADDR_BREDR)
1571 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1572 else
1573 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001574
Johan Hedberg8962ee72011-01-20 12:40:27 +02001575 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001576 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1577 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001578 goto failed;
1579 }
1580
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001581 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001582 if (!cmd) {
1583 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001584 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001585 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001586
1587 put_unaligned_le16(conn->handle, &dc.handle);
1588 dc.reason = 0x13; /* Remote User Terminated Connection */
1589
1590 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1591 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001592 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001593
1594failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001595 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001596 hci_dev_put(hdev);
1597
1598 return err;
1599}
1600
Johan Hedberg48264f02011-11-09 13:58:58 +02001601static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001602{
1603 switch (link_type) {
1604 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001605 switch (addr_type) {
1606 case ADDR_LE_DEV_PUBLIC:
1607 return MGMT_ADDR_LE_PUBLIC;
1608 case ADDR_LE_DEV_RANDOM:
1609 return MGMT_ADDR_LE_RANDOM;
1610 default:
1611 return MGMT_ADDR_INVALID;
1612 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001613 case ACL_LINK:
1614 return MGMT_ADDR_BREDR;
1615 default:
1616 return MGMT_ADDR_INVALID;
1617 }
1618}
1619
Szymon Janc8ce62842011-03-01 16:55:32 +01001620static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001621{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001622 struct mgmt_rp_get_connections *rp;
1623 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001624 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001625 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001626 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001627 int i, err;
1628
1629 BT_DBG("");
1630
Szymon Janc4e51eae2011-02-25 19:05:48 +01001631 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001632 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001633 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1634 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001635
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001636 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001637
1638 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001639 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1640 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1641 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001642 }
1643
Johan Hedberg4c659c32011-11-07 23:13:39 +02001644 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001645 rp = kmalloc(rp_len, GFP_ATOMIC);
1646 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001647 err = -ENOMEM;
1648 goto unlock;
1649 }
1650
Johan Hedberg2784eb42011-01-21 13:56:35 +02001651 put_unaligned_le16(count, &rp->conn_count);
1652
Johan Hedberg2784eb42011-01-21 13:56:35 +02001653 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001654 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001655 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1656 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001657 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001658 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001659 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1660 continue;
1661 i++;
1662 }
1663
1664 /* Recalculate length in case of filtered SCO connections, etc */
1665 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001666
Johan Hedbergaee9b212012-02-18 15:07:59 +02001667 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001668
1669unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001670 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001671 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001672 hci_dev_put(hdev);
1673 return err;
1674}
1675
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001676static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1677 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1678{
1679 struct pending_cmd *cmd;
1680 int err;
1681
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001682 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001683 sizeof(*cp));
1684 if (!cmd)
1685 return -ENOMEM;
1686
Johan Hedbergd8457692012-02-17 14:24:57 +02001687 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1688 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001689 if (err < 0)
1690 mgmt_pending_remove(cmd);
1691
1692 return err;
1693}
1694
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001695static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001696{
1697 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001698 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001699 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001700 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001701 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001702 int err;
1703
1704 BT_DBG("");
1705
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001706 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001707 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1708 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001709
Szymon Janc4e51eae2011-02-25 19:05:48 +01001710 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001711 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001712 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1713 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001714
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001715 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001716
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001717 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001718 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1719 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001720 goto failed;
1721 }
1722
Johan Hedbergd8457692012-02-17 14:24:57 +02001723 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001724 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001725 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1726 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001727 goto failed;
1728 }
1729
1730 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001731 struct mgmt_cp_pin_code_neg_reply ncp;
1732
1733 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001734
1735 BT_ERR("PIN code is not 16 bytes long");
1736
1737 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1738 if (err >= 0)
1739 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001740 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001741
1742 goto failed;
1743 }
1744
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001745 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1746 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001747 if (!cmd) {
1748 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001749 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001750 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001751
Johan Hedbergd8457692012-02-17 14:24:57 +02001752 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001753 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001754 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001755
1756 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1757 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001758 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001759
1760failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001761 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001762 hci_dev_put(hdev);
1763
1764 return err;
1765}
1766
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001767static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001768{
1769 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001770 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001771 int err;
1772
1773 BT_DBG("");
1774
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001775 if (len != sizeof(*cp))
1776 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001777 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001778
Szymon Janc4e51eae2011-02-25 19:05:48 +01001779 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001780 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001781 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001782 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001783
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001784 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001785
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001786 if (!hdev_is_powered(hdev)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001787 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001788 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001789 goto failed;
1790 }
1791
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001792 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001793
1794failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001795 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001796 hci_dev_put(hdev);
1797
1798 return err;
1799}
1800
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001801static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001802{
1803 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001804 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001805
1806 BT_DBG("");
1807
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001808 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001809 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1810 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001811
Szymon Janc4e51eae2011-02-25 19:05:48 +01001812 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001813 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001814 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1815 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001816
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001817 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001818
1819 hdev->io_capability = cp->io_capability;
1820
1821 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001822 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001823
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001824 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001825 hci_dev_put(hdev);
1826
Johan Hedbergaee9b212012-02-18 15:07:59 +02001827 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001828}
1829
Johan Hedberge9a416b2011-02-19 12:05:56 -03001830static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1831{
1832 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001833 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001834
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001835 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001836 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1837 continue;
1838
Johan Hedberge9a416b2011-02-19 12:05:56 -03001839 if (cmd->user_data != conn)
1840 continue;
1841
1842 return cmd;
1843 }
1844
1845 return NULL;
1846}
1847
1848static void pairing_complete(struct pending_cmd *cmd, u8 status)
1849{
1850 struct mgmt_rp_pair_device rp;
1851 struct hci_conn *conn = cmd->user_data;
1852
Johan Hedbergba4e5642011-11-11 00:07:34 +02001853 bacpy(&rp.addr.bdaddr, &conn->dst);
1854 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001855
Johan Hedbergaee9b212012-02-18 15:07:59 +02001856 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1857 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001858
1859 /* So we don't get further callbacks for this connection */
1860 conn->connect_cfm_cb = NULL;
1861 conn->security_cfm_cb = NULL;
1862 conn->disconn_cfm_cb = NULL;
1863
1864 hci_conn_put(conn);
1865
Johan Hedberga664b5b2011-02-19 12:06:02 -03001866 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001867}
1868
1869static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1870{
1871 struct pending_cmd *cmd;
1872
1873 BT_DBG("status %u", status);
1874
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001875 cmd = find_pairing(conn);
1876 if (!cmd)
1877 BT_DBG("Unable to find a pending command");
1878 else
Johan Hedberge2113262012-02-18 15:20:03 +02001879 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001880}
1881
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001882static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001883{
1884 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001885 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001886 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001887 struct pending_cmd *cmd;
1888 u8 sec_level, auth_type;
1889 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001890 int err;
1891
1892 BT_DBG("");
1893
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001894 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001895 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1896 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001897
Szymon Janc4e51eae2011-02-25 19:05:48 +01001898 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001899 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001900 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1901 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001902
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001903 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001904
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001905 sec_level = BT_SECURITY_MEDIUM;
1906 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001907 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001908 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001909 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001910
Johan Hedbergba4e5642011-11-11 00:07:34 +02001911 if (cp->addr.type == MGMT_ADDR_BREDR)
1912 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001913 auth_type);
1914 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001915 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001916 auth_type);
1917
Johan Hedberg1425acb2011-11-11 00:07:35 +02001918 memset(&rp, 0, sizeof(rp));
1919 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1920 rp.addr.type = cp->addr.type;
1921
Ville Tervo30e76272011-02-22 16:10:53 -03001922 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001923 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1924 MGMT_STATUS_CONNECT_FAILED,
1925 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001926 goto unlock;
1927 }
1928
1929 if (conn->connect_cfm_cb) {
1930 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001931 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1932 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001933 goto unlock;
1934 }
1935
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001936 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001937 if (!cmd) {
1938 err = -ENOMEM;
1939 hci_conn_put(conn);
1940 goto unlock;
1941 }
1942
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001943 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001944 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001945 conn->connect_cfm_cb = pairing_complete_cb;
1946
Johan Hedberge9a416b2011-02-19 12:05:56 -03001947 conn->security_cfm_cb = pairing_complete_cb;
1948 conn->disconn_cfm_cb = pairing_complete_cb;
1949 conn->io_capability = cp->io_cap;
1950 cmd->user_data = conn;
1951
1952 if (conn->state == BT_CONNECTED &&
1953 hci_conn_security(conn, sec_level, auth_type))
1954 pairing_complete(cmd, 0);
1955
1956 err = 0;
1957
1958unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001959 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001960 hci_dev_put(hdev);
1961
1962 return err;
1963}
1964
Johan Hedberg28424702012-02-02 04:02:29 +02001965static int cancel_pair_device(struct sock *sk, u16 index,
1966 unsigned char *data, u16 len)
1967{
1968 struct mgmt_addr_info *addr = (void *) data;
1969 struct hci_dev *hdev;
1970 struct pending_cmd *cmd;
1971 struct hci_conn *conn;
1972 int err;
1973
1974 BT_DBG("");
1975
1976 if (len != sizeof(*addr))
1977 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1978 MGMT_STATUS_INVALID_PARAMS);
1979
1980 hdev = hci_dev_get(index);
1981 if (!hdev)
1982 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1983 MGMT_STATUS_INVALID_PARAMS);
1984
1985 hci_dev_lock(hdev);
1986
1987 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1988 if (!cmd) {
1989 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1990 MGMT_STATUS_INVALID_PARAMS);
1991 goto unlock;
1992 }
1993
1994 conn = cmd->user_data;
1995
1996 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1997 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1998 MGMT_STATUS_INVALID_PARAMS);
1999 goto unlock;
2000 }
2001
2002 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2003
Johan Hedbergaee9b212012-02-18 15:07:59 +02002004 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02002005 sizeof(*addr));
2006unlock:
2007 hci_dev_unlock(hdev);
2008 hci_dev_put(hdev);
2009
2010 return err;
2011}
2012
Brian Gix0df4c182011-11-16 13:53:13 -08002013static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002014 u8 type, u16 mgmt_op, u16 hci_op,
2015 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002016{
Johan Hedberga5c29682011-02-19 12:05:57 -03002017 struct pending_cmd *cmd;
2018 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08002019 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002020 int err;
2021
Szymon Janc4e51eae2011-02-25 19:05:48 +01002022 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03002023 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002024 return cmd_status(sk, index, mgmt_op,
2025 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03002026
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002027 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002028
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002029 if (!hdev_is_powered(hdev)) {
Brian Gix0df4c182011-11-16 13:53:13 -08002030 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
2031 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002032 }
2033
Johan Hedberg272d90d2012-02-09 15:26:12 +02002034 if (type == MGMT_ADDR_BREDR)
2035 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2036 else
Brian Gix47c15e22011-11-16 13:53:14 -08002037 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002038
Johan Hedberg272d90d2012-02-09 15:26:12 +02002039 if (!conn) {
2040 err = cmd_status(sk, index, mgmt_op,
2041 MGMT_STATUS_NOT_CONNECTED);
2042 goto done;
2043 }
2044
2045 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002046 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002047 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002048
Brian Gix5fe57d92011-12-21 16:12:13 -08002049 if (!err)
2050 err = cmd_status(sk, index, mgmt_op,
2051 MGMT_STATUS_SUCCESS);
2052 else
2053 err = cmd_status(sk, index, mgmt_op,
2054 MGMT_STATUS_FAILED);
2055
Brian Gix47c15e22011-11-16 13:53:14 -08002056 goto done;
2057 }
2058
Brian Gix0df4c182011-11-16 13:53:13 -08002059 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002060 if (!cmd) {
2061 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002062 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002063 }
2064
Brian Gix0df4c182011-11-16 13:53:13 -08002065 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002066 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2067 struct hci_cp_user_passkey_reply cp;
2068
2069 bacpy(&cp.bdaddr, bdaddr);
2070 cp.passkey = passkey;
2071 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2072 } else
2073 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2074
Johan Hedberga664b5b2011-02-19 12:06:02 -03002075 if (err < 0)
2076 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002077
Brian Gix0df4c182011-11-16 13:53:13 -08002078done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002079 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002080 hci_dev_put(hdev);
2081
2082 return err;
2083}
2084
Brian Gix0df4c182011-11-16 13:53:13 -08002085static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
2086{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002087 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002088
2089 BT_DBG("");
2090
2091 if (len != sizeof(*cp))
2092 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
2093 MGMT_STATUS_INVALID_PARAMS);
2094
Johan Hedberg272d90d2012-02-09 15:26:12 +02002095 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2096 MGMT_OP_USER_CONFIRM_REPLY,
2097 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002098}
2099
2100static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
2101 u16 len)
2102{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002103 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002104
2105 BT_DBG("");
2106
2107 if (len != sizeof(*cp))
2108 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
2109 MGMT_STATUS_INVALID_PARAMS);
2110
Johan Hedberg272d90d2012-02-09 15:26:12 +02002111 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2112 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2113 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002114}
2115
Brian Gix604086b2011-11-23 08:28:33 -08002116static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
2117{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002118 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002119
2120 BT_DBG("");
2121
2122 if (len != sizeof(*cp))
2123 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
2124 EINVAL);
2125
Johan Hedberg272d90d2012-02-09 15:26:12 +02002126 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2127 MGMT_OP_USER_PASSKEY_REPLY,
2128 HCI_OP_USER_PASSKEY_REPLY,
2129 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002130}
2131
2132static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
2133 u16 len)
2134{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002135 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002136
2137 BT_DBG("");
2138
2139 if (len != sizeof(*cp))
2140 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
2141 EINVAL);
2142
Johan Hedberg272d90d2012-02-09 15:26:12 +02002143 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
2144 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2145 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002146}
2147
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002148static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002149 u16 len)
2150{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002151 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002152 struct hci_cp_write_local_name hci_cp;
2153 struct hci_dev *hdev;
2154 struct pending_cmd *cmd;
2155 int err;
2156
2157 BT_DBG("");
2158
2159 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002160 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2161 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002162
2163 hdev = hci_dev_get(index);
2164 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002165 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2166 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002167
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002168 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002169
Johan Hedbergb5235a62012-02-21 14:32:24 +02002170 if (!hdev_is_powered(hdev)) {
2171 err = cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2172 MGMT_STATUS_NOT_POWERED);
2173 goto failed;
2174 }
2175
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002176 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2177 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002178 if (!cmd) {
2179 err = -ENOMEM;
2180 goto failed;
2181 }
2182
2183 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2184 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2185 &hci_cp);
2186 if (err < 0)
2187 mgmt_pending_remove(cmd);
2188
2189failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002190 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002191 hci_dev_put(hdev);
2192
2193 return err;
2194}
2195
Szymon Jancc35938b2011-03-22 13:12:21 +01002196static int read_local_oob_data(struct sock *sk, u16 index)
2197{
2198 struct hci_dev *hdev;
2199 struct pending_cmd *cmd;
2200 int err;
2201
2202 BT_DBG("hci%u", index);
2203
2204 hdev = hci_dev_get(index);
2205 if (!hdev)
2206 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002207 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002208
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002209 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002210
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002211 if (!hdev_is_powered(hdev)) {
Szymon Jancc35938b2011-03-22 13:12:21 +01002212 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002213 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002214 goto unlock;
2215 }
2216
2217 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2218 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002219 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002220 goto unlock;
2221 }
2222
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002223 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002224 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2225 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002226 goto unlock;
2227 }
2228
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002229 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002230 if (!cmd) {
2231 err = -ENOMEM;
2232 goto unlock;
2233 }
2234
2235 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2236 if (err < 0)
2237 mgmt_pending_remove(cmd);
2238
2239unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002240 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002241 hci_dev_put(hdev);
2242
2243 return err;
2244}
2245
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002246static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2247 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002248{
2249 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002250 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002251 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002252 int err;
2253
2254 BT_DBG("hci%u ", index);
2255
2256 if (len != sizeof(*cp))
2257 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002258 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002259
2260 hdev = hci_dev_get(index);
2261 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002262 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2263 MGMT_STATUS_INVALID_PARAMS,
2264 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002265
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002266 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002267
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002268 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002269 cp->randomizer);
2270 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002271 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002272 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002273 status = 0;
2274
2275 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2276 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002277
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002278 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002279 hci_dev_put(hdev);
2280
2281 return err;
2282}
2283
2284static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002285 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002286{
2287 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002288 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002289 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002290 int err;
2291
2292 BT_DBG("hci%u ", index);
2293
2294 if (len != sizeof(*cp))
2295 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002296 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002297
2298 hdev = hci_dev_get(index);
2299 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002300 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2301 MGMT_STATUS_INVALID_PARAMS,
2302 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002303
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002304 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002305
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002306 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002307 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002308 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002309 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002310 status = 0;
2311
2312 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2313 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002314
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002315 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002316 hci_dev_put(hdev);
2317
2318 return err;
2319}
2320
Andre Guedes5e0452c2012-02-17 20:39:38 -03002321static int discovery(struct hci_dev *hdev)
2322{
2323 int err;
2324
2325 if (lmp_host_le_capable(hdev)) {
2326 if (lmp_bredr_capable(hdev)) {
2327 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2328 LE_SCAN_INT, LE_SCAN_WIN,
2329 LE_SCAN_TIMEOUT_BREDR_LE);
2330 } else {
2331 hdev->discovery.type = DISCOV_TYPE_LE;
2332 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2333 LE_SCAN_INT, LE_SCAN_WIN,
2334 LE_SCAN_TIMEOUT_LE_ONLY);
2335 }
2336 } else {
2337 hdev->discovery.type = DISCOV_TYPE_BREDR;
2338 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2339 }
2340
2341 return err;
2342}
2343
2344int mgmt_interleaved_discovery(struct hci_dev *hdev)
2345{
2346 int err;
2347
2348 BT_DBG("%s", hdev->name);
2349
2350 hci_dev_lock(hdev);
2351
2352 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2353 if (err < 0)
2354 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2355
2356 hci_dev_unlock(hdev);
2357
2358 return err;
2359}
2360
Johan Hedberg450dfda2011-11-12 11:58:22 +02002361static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002362 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002363{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002364 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002365 struct pending_cmd *cmd;
2366 struct hci_dev *hdev;
2367 int err;
2368
2369 BT_DBG("hci%u", index);
2370
Johan Hedberg450dfda2011-11-12 11:58:22 +02002371 if (len != sizeof(*cp))
2372 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2373 MGMT_STATUS_INVALID_PARAMS);
2374
Johan Hedberg14a53662011-04-27 10:29:56 -04002375 hdev = hci_dev_get(index);
2376 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002377 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2378 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002379
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002380 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002381
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002382 if (!hdev_is_powered(hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002383 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2384 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002385 goto failed;
2386 }
2387
Johan Hedbergff9ef572012-01-04 14:23:45 +02002388 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2389 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2390 MGMT_STATUS_BUSY);
2391 goto failed;
2392 }
2393
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002394 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002395 if (!cmd) {
2396 err = -ENOMEM;
2397 goto failed;
2398 }
2399
Andre Guedes4aab14e2012-02-17 20:39:36 -03002400 hdev->discovery.type = cp->type;
2401
2402 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002403 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002404 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002405 break;
2406
2407 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002408 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2409 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002410 break;
2411
Andre Guedes5e0452c2012-02-17 20:39:38 -03002412 case DISCOV_TYPE_INTERLEAVED:
2413 err = discovery(hdev);
2414 break;
2415
Andre Guedesf39799f2012-02-17 20:39:35 -03002416 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002417 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002418 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002419
Johan Hedberg14a53662011-04-27 10:29:56 -04002420 if (err < 0)
2421 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002422 else
2423 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002424
2425failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002426 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002427 hci_dev_put(hdev);
2428
2429 return err;
2430}
2431
Johan Hedbergd9306502012-02-20 23:25:18 +02002432static int stop_discovery(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002433{
Johan Hedbergd9306502012-02-20 23:25:18 +02002434 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002435 struct hci_dev *hdev;
2436 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002437 struct hci_cp_remote_name_req_cancel cp;
2438 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002439 int err;
2440
2441 BT_DBG("hci%u", index);
2442
Johan Hedbergd9306502012-02-20 23:25:18 +02002443 if (len != sizeof(*mgmt_cp))
2444 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2445 MGMT_STATUS_INVALID_PARAMS);
2446
Johan Hedberg14a53662011-04-27 10:29:56 -04002447 hdev = hci_dev_get(index);
2448 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002449 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2450 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002451
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002452 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002453
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002454 if (!hci_discovery_active(hdev)) {
Johan Hedbergd9306502012-02-20 23:25:18 +02002455 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2456 MGMT_STATUS_REJECTED,
2457 &mgmt_cp->type, sizeof(mgmt_cp->type));
2458 goto unlock;
2459 }
2460
2461 if (hdev->discovery.type != mgmt_cp->type) {
2462 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY,
2463 MGMT_STATUS_INVALID_PARAMS,
2464 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002465 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002466 }
2467
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002468 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002469 if (!cmd) {
2470 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002471 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002472 }
2473
Andre Guedes343f9352012-02-17 20:39:37 -03002474 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002475 err = hci_cancel_inquiry(hdev);
2476 if (err < 0)
2477 mgmt_pending_remove(cmd);
2478 else
2479 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2480 goto unlock;
2481 }
2482
2483 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2484 if (!e) {
2485 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002486 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
Johan Hedbergd9306502012-02-20 23:25:18 +02002487 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002488 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2489 goto unlock;
2490 }
2491
2492 bacpy(&cp.bdaddr, &e->data.bdaddr);
2493 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2494 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002495 if (err < 0)
2496 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002497 else
2498 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002499
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002500unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002501 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002502 hci_dev_put(hdev);
2503
2504 return err;
2505}
2506
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002507static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002508{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002509 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002510 struct inquiry_entry *e;
2511 struct hci_dev *hdev;
2512 int err;
2513
2514 BT_DBG("hci%u", index);
2515
2516 if (len != sizeof(*cp))
2517 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2518 MGMT_STATUS_INVALID_PARAMS);
2519
2520 hdev = hci_dev_get(index);
2521 if (!hdev)
2522 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2523 MGMT_STATUS_INVALID_PARAMS);
2524
2525 hci_dev_lock(hdev);
2526
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002527 if (!hci_discovery_active(hdev)) {
2528 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2529 MGMT_STATUS_FAILED);
2530 goto failed;
2531 }
2532
Johan Hedberga198e7b2012-02-17 14:27:06 +02002533 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002534 if (!e) {
Marcel Holtmanne5f0e152012-02-22 11:59:01 +01002535 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002536 MGMT_STATUS_INVALID_PARAMS);
2537 goto failed;
2538 }
2539
2540 if (cp->name_known) {
2541 e->name_state = NAME_KNOWN;
2542 list_del(&e->list);
2543 } else {
2544 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002545 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002546 }
2547
2548 err = 0;
2549
2550failed:
2551 hci_dev_unlock(hdev);
2552
2553 return err;
2554}
2555
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002556static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002557{
2558 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002559 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002560 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002561 int err;
2562
2563 BT_DBG("hci%u", index);
2564
Antti Julku7fbec222011-06-15 12:01:15 +03002565 if (len != sizeof(*cp))
2566 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002567 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002568
2569 hdev = hci_dev_get(index);
2570 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002571 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2572 MGMT_STATUS_INVALID_PARAMS,
2573 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002574
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002575 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002576
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002577 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002578 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002579 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002580 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002581 status = 0;
2582
2583 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2584 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002585
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002586 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002587 hci_dev_put(hdev);
2588
2589 return err;
2590}
2591
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002592static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002593{
2594 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002595 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002596 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002597 int err;
2598
2599 BT_DBG("hci%u", index);
2600
Antti Julku7fbec222011-06-15 12:01:15 +03002601 if (len != sizeof(*cp))
2602 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002603 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002604
2605 hdev = hci_dev_get(index);
2606 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002607 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2608 MGMT_STATUS_INVALID_PARAMS,
2609 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002610
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002611 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002612
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002613 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002614 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002615 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002616 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002617 status = 0;
2618
2619 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2620 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002621
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002622 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002623 hci_dev_put(hdev);
2624
2625 return err;
2626}
2627
Antti Julkuf6422ec2011-06-22 13:11:56 +03002628static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002629 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002630{
2631 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002632 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002633 struct hci_cp_write_page_scan_activity acp;
2634 u8 type;
2635 int err;
2636
2637 BT_DBG("hci%u", index);
2638
2639 if (len != sizeof(*cp))
2640 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002641 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002642
2643 hdev = hci_dev_get(index);
2644 if (!hdev)
2645 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002646 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg5400c042012-02-21 16:40:33 +02002647 if (!hdev_is_powered(hdev))
2648 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2649 MGMT_STATUS_NOT_POWERED);
2650
2651 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2652 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2653 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002654
2655 hci_dev_lock(hdev);
2656
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002657 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002658 type = PAGE_SCAN_TYPE_INTERLACED;
2659 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2660 } else {
2661 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2662 acp.interval = 0x0800; /* default 1.28 sec page scan */
2663 }
2664
2665 acp.window = 0x0012; /* default 11.25 msec page scan window */
2666
2667 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2668 sizeof(acp), &acp);
2669 if (err < 0) {
2670 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002671 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002672 goto done;
2673 }
2674
2675 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2676 if (err < 0) {
2677 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002678 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002679 goto done;
2680 }
2681
Johan Hedbergaee9b212012-02-18 15:07:59 +02002682 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2683 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002684done:
2685 hci_dev_unlock(hdev);
2686 hci_dev_put(hdev);
2687
2688 return err;
2689}
2690
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002691static int load_long_term_keys(struct sock *sk, u16 index,
2692 void *cp_data, u16 len)
2693{
2694 struct hci_dev *hdev;
2695 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2696 u16 key_count, expected_len;
2697 int i;
2698
2699 if (len < sizeof(*cp))
2700 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2701 EINVAL);
2702
2703 key_count = get_unaligned_le16(&cp->key_count);
2704
2705 expected_len = sizeof(*cp) + key_count *
2706 sizeof(struct mgmt_ltk_info);
2707 if (expected_len != len) {
2708 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2709 len, expected_len);
2710 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2711 EINVAL);
2712 }
2713
2714 hdev = hci_dev_get(index);
2715 if (!hdev)
2716 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2717 ENODEV);
2718
2719 BT_DBG("hci%u key_count %u", index, key_count);
2720
2721 hci_dev_lock(hdev);
2722
2723 hci_smp_ltks_clear(hdev);
2724
2725 for (i = 0; i < key_count; i++) {
2726 struct mgmt_ltk_info *key = &cp->keys[i];
2727 u8 type;
2728
2729 if (key->master)
2730 type = HCI_SMP_LTK;
2731 else
2732 type = HCI_SMP_LTK_SLAVE;
2733
2734 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2735 type, 0, key->authenticated, key->val,
2736 key->enc_size, key->ediv, key->rand);
2737 }
2738
2739 hci_dev_unlock(hdev);
2740 hci_dev_put(hdev);
2741
2742 return 0;
2743}
2744
Johan Hedberg03811012010-12-08 00:21:06 +02002745int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2746{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002747 void *buf;
2748 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002749 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002750 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002751 int err;
2752
2753 BT_DBG("got %zu bytes", msglen);
2754
2755 if (msglen < sizeof(*hdr))
2756 return -EINVAL;
2757
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002758 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002759 if (!buf)
2760 return -ENOMEM;
2761
2762 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2763 err = -EFAULT;
2764 goto done;
2765 }
2766
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002767 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002768 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002769 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002770 len = get_unaligned_le16(&hdr->len);
2771
2772 if (len != msglen - sizeof(*hdr)) {
2773 err = -EINVAL;
2774 goto done;
2775 }
2776
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002777 cp = buf + sizeof(*hdr);
2778
Johan Hedberg03811012010-12-08 00:21:06 +02002779 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002780 case MGMT_OP_READ_VERSION:
2781 err = read_version(sk);
2782 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002783 case MGMT_OP_READ_COMMANDS:
2784 err = read_commands(sk);
2785 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002786 case MGMT_OP_READ_INDEX_LIST:
2787 err = read_index_list(sk);
2788 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002789 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002790 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002791 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002792 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002793 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002794 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002795 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002796 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002797 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002798 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002799 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002800 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002801 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002802 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002803 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002804 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002805 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002806 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002807 case MGMT_OP_SET_LINK_SECURITY:
2808 err = set_link_security(sk, index, cp, len);
2809 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002810 case MGMT_OP_SET_SSP:
2811 err = set_ssp(sk, index, cp, len);
2812 break;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02002813 case MGMT_OP_SET_HS:
2814 err = set_hs(sk, index, cp, len);
2815 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002816 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002817 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002818 break;
2819 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002820 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002821 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002822 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002823 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002824 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002825 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002826 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002827 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002828 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002829 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002830 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002831 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002832 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002833 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002834 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002835 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002836 break;
2837 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002838 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002839 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002840 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002841 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002842 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002843 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002844 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002845 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002846 case MGMT_OP_CANCEL_PAIR_DEVICE:
2847 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2848 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002849 case MGMT_OP_UNPAIR_DEVICE:
2850 err = unpair_device(sk, index, cp, len);
2851 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002852 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002853 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002854 break;
2855 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002856 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002857 break;
Brian Gix604086b2011-11-23 08:28:33 -08002858 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002859 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002860 break;
2861 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002862 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002863 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002864 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002865 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002866 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002867 case MGMT_OP_READ_LOCAL_OOB_DATA:
2868 err = read_local_oob_data(sk, index);
2869 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002870 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002871 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002872 break;
2873 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002874 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002875 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002876 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002877 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002878 break;
2879 case MGMT_OP_STOP_DISCOVERY:
Johan Hedbergd9306502012-02-20 23:25:18 +02002880 err = stop_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002881 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002882 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002883 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002884 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002885 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002886 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002887 break;
2888 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002889 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002890 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002891 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2892 err = load_long_term_keys(sk, index, cp, len);
2893 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002894 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002895 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002896 err = cmd_status(sk, index, opcode,
2897 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002898 break;
2899 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002900
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002901 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002902 goto done;
2903
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002904 err = msglen;
2905
2906done:
2907 kfree(buf);
2908 return err;
2909}
2910
Johan Hedbergb24752f2011-11-03 14:40:33 +02002911static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2912{
2913 u8 *status = data;
2914
2915 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2916 mgmt_pending_remove(cmd);
2917}
2918
Johan Hedberg744cf192011-11-08 20:40:14 +02002919int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002920{
Johan Hedberg744cf192011-11-08 20:40:14 +02002921 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002922}
2923
Johan Hedberg744cf192011-11-08 20:40:14 +02002924int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002925{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002926 u8 status = ENODEV;
2927
Johan Hedberg744cf192011-11-08 20:40:14 +02002928 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002929
Johan Hedberg744cf192011-11-08 20:40:14 +02002930 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002931}
2932
2933struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002934 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002935 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002936};
2937
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002938static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002939{
Johan Hedberg03811012010-12-08 00:21:06 +02002940 struct cmd_lookup *match = data;
2941
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002942 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002943
2944 list_del(&cmd->list);
2945
2946 if (match->sk == NULL) {
2947 match->sk = cmd->sk;
2948 sock_hold(match->sk);
2949 }
2950
2951 mgmt_pending_free(cmd);
2952}
2953
Johan Hedberg744cf192011-11-08 20:40:14 +02002954int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002955{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002956 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002957 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002958
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002959 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2960 return 0;
2961
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002962 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002963
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002964 if (powered) {
2965 u8 scan = 0;
2966
2967 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2968 scan |= SCAN_PAGE;
2969 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2970 scan |= SCAN_INQUIRY;
2971
2972 if (scan)
2973 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
2974 } else {
Johan Hedbergb24752f2011-11-03 14:40:33 +02002975 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002976 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002977 }
2978
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002979 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002980
2981 if (match.sk)
2982 sock_put(match.sk);
2983
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002984 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002985}
2986
Johan Hedberg744cf192011-11-08 20:40:14 +02002987int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002988{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002989 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002990 bool changed = false;
2991 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02002992
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002993 if (discoverable) {
2994 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2995 changed = true;
2996 } else {
2997 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2998 changed = true;
2999 }
Johan Hedberg03811012010-12-08 00:21:06 +02003000
Johan Hedberged9b5f22012-02-21 20:47:06 +02003001 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
3002 &match);
3003
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003004 if (changed)
3005 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003006
Johan Hedberg03811012010-12-08 00:21:06 +02003007 if (match.sk)
3008 sock_put(match.sk);
3009
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003010 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003011}
3012
Johan Hedberg744cf192011-11-08 20:40:14 +02003013int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02003014{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02003015 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003016 bool changed = false;
3017 int err = 0;
Johan Hedberg03811012010-12-08 00:21:06 +02003018
Johan Hedberg5e5282b2012-02-21 16:01:30 +02003019 if (connectable) {
3020 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3021 changed = true;
3022 } else {
3023 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
3024 changed = true;
3025 }
Johan Hedberg03811012010-12-08 00:21:06 +02003026
Johan Hedberged9b5f22012-02-21 20:47:06 +02003027 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
3028 &match);
3029
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02003030 if (changed)
3031 err = new_settings(hdev, match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02003032
3033 if (match.sk)
3034 sock_put(match.sk);
3035
Johan Hedberg7bb895d2012-02-17 01:20:00 +02003036 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02003037}
3038
Johan Hedberg744cf192011-11-08 20:40:14 +02003039int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003040{
Johan Hedbergca69b792011-11-11 18:10:00 +02003041 u8 mgmt_err = mgmt_status(status);
3042
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003043 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02003044 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003045 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003046
3047 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02003048 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02003049 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02003050
3051 return 0;
3052}
3053
Johan Hedberg744cf192011-11-08 20:40:14 +02003054int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
3055 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02003056{
Johan Hedberg86742e12011-11-07 23:13:38 +02003057 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02003058
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003059 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02003060
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003061 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02003062 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3063 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03003064 ev.key.type = key->type;
3065 memcpy(ev.key.val, key->val, 16);
3066 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02003067
Johan Hedberg744cf192011-11-08 20:40:14 +02003068 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02003069}
Johan Hedbergf7520542011-01-20 12:34:39 +02003070
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003071int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
3072{
3073 struct mgmt_ev_new_long_term_key ev;
3074
3075 memset(&ev, 0, sizeof(ev));
3076
3077 ev.store_hint = persistent;
3078 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
3079 ev.key.addr.type = key->bdaddr_type;
3080 ev.key.authenticated = key->authenticated;
3081 ev.key.enc_size = key->enc_size;
3082 ev.key.ediv = key->ediv;
3083
3084 if (key->type == HCI_SMP_LTK)
3085 ev.key.master = 1;
3086
3087 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3088 memcpy(ev.key.val, key->val, sizeof(key->val));
3089
3090 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
3091 &ev, sizeof(ev), NULL);
3092}
3093
Johan Hedbergafc747a2012-01-15 18:11:07 +02003094int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02003095 u8 addr_type, u8 *name, u8 name_len,
3096 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003097{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003098 char buf[512];
3099 struct mgmt_ev_device_connected *ev = (void *) buf;
3100 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003101
Johan Hedbergb644ba32012-01-17 21:48:47 +02003102 bacpy(&ev->addr.bdaddr, bdaddr);
3103 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003104
Johan Hedbergb644ba32012-01-17 21:48:47 +02003105 if (name_len > 0)
3106 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
3107 name, name_len);
3108
3109 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
3110 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
3111 EIR_CLASS_OF_DEV, dev_class, 3);
3112
3113 put_unaligned_le16(eir_len, &ev->eir_len);
3114
3115 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
3116 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003117}
3118
Johan Hedberg8962ee72011-01-20 12:40:27 +02003119static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3120{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003121 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003122 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003123 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003124
Johan Hedberg88c3df12012-02-09 14:27:38 +02003125 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3126 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003127
Johan Hedbergaee9b212012-02-18 15:07:59 +02003128 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
3129 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003130
3131 *sk = cmd->sk;
3132 sock_hold(*sk);
3133
Johan Hedberga664b5b2011-02-19 12:06:02 -03003134 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003135}
3136
Johan Hedberg124f6e32012-02-09 13:50:12 +02003137static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003138{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003139 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003140 struct mgmt_cp_unpair_device *cp = cmd->param;
3141 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003142
3143 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003144 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3145 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003146
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003147 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3148
Johan Hedbergaee9b212012-02-18 15:07:59 +02003149 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003150
3151 mgmt_pending_remove(cmd);
3152}
3153
Johan Hedbergafc747a2012-01-15 18:11:07 +02003154int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
3155 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003156{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003157 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003158 struct sock *sk = NULL;
3159 int err;
3160
Johan Hedberg744cf192011-11-08 20:40:14 +02003161 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003162
Johan Hedbergf7520542011-01-20 12:34:39 +02003163 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003164 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003165
Johan Hedbergafc747a2012-01-15 18:11:07 +02003166 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
3167 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003168
3169 if (sk)
3170 sock_put(sk);
3171
Johan Hedberg124f6e32012-02-09 13:50:12 +02003172 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003173 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003174
Johan Hedberg8962ee72011-01-20 12:40:27 +02003175 return err;
3176}
3177
Johan Hedberg88c3df12012-02-09 14:27:38 +02003178int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
3179 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003180{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003181 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003182 struct pending_cmd *cmd;
3183 int err;
3184
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003185 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003186 if (!cmd)
3187 return -ENOENT;
3188
Johan Hedberg88c3df12012-02-09 14:27:38 +02003189 bacpy(&rp.addr.bdaddr, bdaddr);
3190 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003191
Johan Hedberg88c3df12012-02-09 14:27:38 +02003192 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003193 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003194
Johan Hedberga664b5b2011-02-19 12:06:02 -03003195 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003196
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003197 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3198 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003199 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003200}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003201
Johan Hedberg48264f02011-11-09 13:58:58 +02003202int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3203 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003204{
3205 struct mgmt_ev_connect_failed ev;
3206
Johan Hedberg4c659c32011-11-07 23:13:39 +02003207 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003208 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003209 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003210
Johan Hedberg744cf192011-11-08 20:40:14 +02003211 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003212}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003213
Johan Hedberg744cf192011-11-08 20:40:14 +02003214int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003215{
3216 struct mgmt_ev_pin_code_request ev;
3217
Johan Hedbergd8457692012-02-17 14:24:57 +02003218 bacpy(&ev.addr.bdaddr, bdaddr);
3219 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003220 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003221
Johan Hedberg744cf192011-11-08 20:40:14 +02003222 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003223 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003224}
3225
Johan Hedberg744cf192011-11-08 20:40:14 +02003226int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3227 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003228{
3229 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003230 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003231 int err;
3232
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003233 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003234 if (!cmd)
3235 return -ENOENT;
3236
Johan Hedbergd8457692012-02-17 14:24:57 +02003237 bacpy(&rp.addr.bdaddr, bdaddr);
3238 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003239
Johan Hedbergaee9b212012-02-18 15:07:59 +02003240 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3241 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003242
Johan Hedberga664b5b2011-02-19 12:06:02 -03003243 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003244
3245 return err;
3246}
3247
Johan Hedberg744cf192011-11-08 20:40:14 +02003248int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3249 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003250{
3251 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003252 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003253 int err;
3254
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003255 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003256 if (!cmd)
3257 return -ENOENT;
3258
Johan Hedbergd8457692012-02-17 14:24:57 +02003259 bacpy(&rp.addr.bdaddr, bdaddr);
3260 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003261
Johan Hedbergaee9b212012-02-18 15:07:59 +02003262 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3263 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003264
Johan Hedberga664b5b2011-02-19 12:06:02 -03003265 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003266
3267 return err;
3268}
Johan Hedberga5c29682011-02-19 12:05:57 -03003269
Johan Hedberg744cf192011-11-08 20:40:14 +02003270int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003271 u8 link_type, u8 addr_type, __le32 value,
3272 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003273{
3274 struct mgmt_ev_user_confirm_request ev;
3275
Johan Hedberg744cf192011-11-08 20:40:14 +02003276 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003277
Johan Hedberg272d90d2012-02-09 15:26:12 +02003278 bacpy(&ev.addr.bdaddr, bdaddr);
3279 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003280 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003281 put_unaligned_le32(value, &ev.value);
3282
Johan Hedberg744cf192011-11-08 20:40:14 +02003283 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003284 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003285}
3286
Johan Hedberg272d90d2012-02-09 15:26:12 +02003287int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3288 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003289{
3290 struct mgmt_ev_user_passkey_request ev;
3291
3292 BT_DBG("%s", hdev->name);
3293
Johan Hedberg272d90d2012-02-09 15:26:12 +02003294 bacpy(&ev.addr.bdaddr, bdaddr);
3295 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003296
3297 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3298 NULL);
3299}
3300
Brian Gix0df4c182011-11-16 13:53:13 -08003301static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003302 u8 link_type, u8 addr_type, u8 status,
3303 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003304{
3305 struct pending_cmd *cmd;
3306 struct mgmt_rp_user_confirm_reply rp;
3307 int err;
3308
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003309 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003310 if (!cmd)
3311 return -ENOENT;
3312
Johan Hedberg272d90d2012-02-09 15:26:12 +02003313 bacpy(&rp.addr.bdaddr, bdaddr);
3314 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003315 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3316 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003317
Johan Hedberga664b5b2011-02-19 12:06:02 -03003318 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003319
3320 return err;
3321}
3322
Johan Hedberg744cf192011-11-08 20:40:14 +02003323int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003324 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003325{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003326 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3327 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003328}
3329
Johan Hedberg272d90d2012-02-09 15:26:12 +02003330int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3331 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003332{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003333 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3334 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003335}
Johan Hedberg2a611692011-02-19 12:06:00 -03003336
Brian Gix604086b2011-11-23 08:28:33 -08003337int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003338 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003339{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003340 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3341 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003342}
3343
Johan Hedberg272d90d2012-02-09 15:26:12 +02003344int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3345 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003346{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003347 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3348 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003349}
3350
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003351int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3352 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003353{
3354 struct mgmt_ev_auth_failed ev;
3355
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003356 bacpy(&ev.addr.bdaddr, bdaddr);
3357 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003358 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003359
Johan Hedberg744cf192011-11-08 20:40:14 +02003360 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003361}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003362
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003363int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3364{
3365 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003366 bool changed = false;
3367 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003368
3369 if (status) {
3370 u8 mgmt_err = mgmt_status(status);
3371 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3372 cmd_status_rsp, &mgmt_err);
3373 return 0;
3374 }
3375
Johan Hedberg47990ea2012-02-22 11:58:37 +02003376 if (test_bit(HCI_AUTH, &hdev->flags)) {
3377 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3378 changed = true;
3379 } else {
3380 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3381 changed = true;
3382 }
3383
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003384 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3385 &match);
3386
Johan Hedberg47990ea2012-02-22 11:58:37 +02003387 if (changed)
3388 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003389
3390 if (match.sk)
3391 sock_put(match.sk);
3392
3393 return err;
3394}
3395
Johan Hedbergcacaf522012-02-21 00:52:42 +02003396static int clear_eir(struct hci_dev *hdev)
3397{
3398 struct hci_cp_write_eir cp;
3399
3400 if (!(hdev->features[6] & LMP_EXT_INQ))
3401 return 0;
3402
3403 memset(&cp, 0, sizeof(cp));
3404
3405 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3406}
3407
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003408int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003409{
3410 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003411 bool changed = false;
3412 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003413
3414 if (status) {
3415 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003416
3417 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
3418 &hdev->dev_flags))
3419 err = new_settings(hdev, NULL);
3420
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003421 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3422 cmd_status_rsp, &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003423
3424 return err;
3425 }
3426
3427 if (enable) {
3428 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3429 changed = true;
3430 } else {
3431 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3432 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003433 }
3434
3435 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3436
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003437 if (changed)
3438 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003439
Johan Hedbergcacaf522012-02-21 00:52:42 +02003440 if (match.sk) {
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003441 sock_put(match.sk);
3442
Johan Hedbergcacaf522012-02-21 00:52:42 +02003443 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3444 update_eir(hdev);
3445 else
3446 clear_eir(hdev);
3447 }
3448
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003449 return err;
3450}
3451
Johan Hedberg744cf192011-11-08 20:40:14 +02003452int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003453{
3454 struct pending_cmd *cmd;
3455 struct mgmt_cp_set_local_name ev;
3456 int err;
3457
3458 memset(&ev, 0, sizeof(ev));
3459 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3460
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003461 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003462 if (!cmd)
3463 goto send_event;
3464
3465 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003466 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003467 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003468 goto failed;
3469 }
3470
Johan Hedberg744cf192011-11-08 20:40:14 +02003471 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003472
Johan Hedbergaee9b212012-02-18 15:07:59 +02003473 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003474 sizeof(ev));
3475 if (err < 0)
3476 goto failed;
3477
3478send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003479 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003480 cmd ? cmd->sk : NULL);
3481
3482failed:
3483 if (cmd)
3484 mgmt_pending_remove(cmd);
3485 return err;
3486}
Szymon Jancc35938b2011-03-22 13:12:21 +01003487
Johan Hedberg744cf192011-11-08 20:40:14 +02003488int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3489 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003490{
3491 struct pending_cmd *cmd;
3492 int err;
3493
Johan Hedberg744cf192011-11-08 20:40:14 +02003494 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003495
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003496 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003497 if (!cmd)
3498 return -ENOENT;
3499
3500 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003501 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003502 MGMT_OP_READ_LOCAL_OOB_DATA,
3503 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003504 } else {
3505 struct mgmt_rp_read_local_oob_data rp;
3506
3507 memcpy(rp.hash, hash, sizeof(rp.hash));
3508 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3509
Johan Hedberg744cf192011-11-08 20:40:14 +02003510 err = cmd_complete(cmd->sk, hdev->id,
3511 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003512 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003513 }
3514
3515 mgmt_pending_remove(cmd);
3516
3517 return err;
3518}
Johan Hedberge17acd42011-03-30 23:57:16 +03003519
Johan Hedberg48264f02011-11-09 13:58:58 +02003520int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003521 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003522 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003523{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003524 char buf[512];
3525 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003526 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003527
Johan Hedberg1dc06092012-01-15 21:01:23 +02003528 /* Leave 5 bytes for a potential CoD field */
3529 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003530 return -EINVAL;
3531
Johan Hedberg1dc06092012-01-15 21:01:23 +02003532 memset(buf, 0, sizeof(buf));
3533
Johan Hedberge319d2e2012-01-15 19:51:59 +02003534 bacpy(&ev->addr.bdaddr, bdaddr);
3535 ev->addr.type = link_to_mgmt(link_type, addr_type);
3536 ev->rssi = rssi;
3537 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003538
Johan Hedberg1dc06092012-01-15 21:01:23 +02003539 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003540 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003541
Johan Hedberg1dc06092012-01-15 21:01:23 +02003542 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3543 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3544 dev_class, 3);
3545
3546 put_unaligned_le16(eir_len, &ev->eir_len);
3547
3548 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003549
Johan Hedberge319d2e2012-01-15 19:51:59 +02003550 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003551}
Johan Hedberga88a9652011-03-30 13:18:12 +03003552
Johan Hedbergb644ba32012-01-17 21:48:47 +02003553int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3554 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003555{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003556 struct mgmt_ev_device_found *ev;
3557 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3558 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003559
Johan Hedbergb644ba32012-01-17 21:48:47 +02003560 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003561
Johan Hedbergb644ba32012-01-17 21:48:47 +02003562 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003563
Johan Hedbergb644ba32012-01-17 21:48:47 +02003564 bacpy(&ev->addr.bdaddr, bdaddr);
3565 ev->addr.type = link_to_mgmt(link_type, addr_type);
3566 ev->rssi = rssi;
3567
3568 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3569 name_len);
3570
3571 put_unaligned_le16(eir_len, &ev->eir_len);
3572
Johan Hedberg053c7e02012-02-04 00:06:00 +02003573 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3574 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003575}
Johan Hedberg314b2382011-04-27 10:29:57 -04003576
Andre Guedes7a135102011-11-09 17:14:25 -03003577int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003578{
3579 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003580 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003581 int err;
3582
Andre Guedes203159d2012-02-13 15:41:01 -03003583 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3584
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003585 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003586 if (!cmd)
3587 return -ENOENT;
3588
Johan Hedbergf808e162012-02-19 12:52:07 +02003589 type = hdev->discovery.type;
3590
3591 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3592 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003593 mgmt_pending_remove(cmd);
3594
3595 return err;
3596}
3597
Andre Guedese6d465c2011-11-09 17:14:26 -03003598int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3599{
3600 struct pending_cmd *cmd;
3601 int err;
3602
3603 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3604 if (!cmd)
3605 return -ENOENT;
3606
Johan Hedbergd9306502012-02-20 23:25:18 +02003607 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3608 &hdev->discovery.type,
3609 sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003610 mgmt_pending_remove(cmd);
3611
3612 return err;
3613}
Johan Hedberg314b2382011-04-27 10:29:57 -04003614
Johan Hedberg744cf192011-11-08 20:40:14 +02003615int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003616{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003617 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003618 struct pending_cmd *cmd;
3619
Andre Guedes343fb142011-11-22 17:14:19 -03003620 BT_DBG("%s discovering %u", hdev->name, discovering);
3621
Johan Hedberg164a6e72011-11-01 17:06:44 +02003622 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003623 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003624 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003625 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003626
3627 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003628 u8 type = hdev->discovery.type;
3629
Johan Hedbergd9306502012-02-20 23:25:18 +02003630 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
Johan Hedbergf808e162012-02-19 12:52:07 +02003631 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003632 mgmt_pending_remove(cmd);
3633 }
3634
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003635 memset(&ev, 0, sizeof(ev));
3636 ev.type = hdev->discovery.type;
3637 ev.discovering = discovering;
3638
3639 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003640}
Antti Julku5e762442011-08-25 16:48:02 +03003641
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003642int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003643{
3644 struct pending_cmd *cmd;
3645 struct mgmt_ev_device_blocked ev;
3646
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003647 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003648
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003649 bacpy(&ev.addr.bdaddr, bdaddr);
3650 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003651
Johan Hedberg744cf192011-11-08 20:40:14 +02003652 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3653 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003654}
3655
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003656int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003657{
3658 struct pending_cmd *cmd;
3659 struct mgmt_ev_device_unblocked ev;
3660
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003661 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003662
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003663 bacpy(&ev.addr.bdaddr, bdaddr);
3664 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003665
Johan Hedberg744cf192011-11-08 20:40:14 +02003666 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3667 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003668}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003669
3670module_param(enable_hs, bool, 0644);
3671MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3672
3673module_param(enable_le, bool, 0644);
3674MODULE_PARM_DESC(enable_le, "Enable Low Energy support");