blob: 402cb0026f5dafc7c6defefaeff27ec3ca2ee393 [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,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020082};
83
84static const u16 mgmt_events[] = {
85 MGMT_EV_CONTROLLER_ERROR,
86 MGMT_EV_INDEX_ADDED,
87 MGMT_EV_INDEX_REMOVED,
88 MGMT_EV_NEW_SETTINGS,
89 MGMT_EV_CLASS_OF_DEV_CHANGED,
90 MGMT_EV_LOCAL_NAME_CHANGED,
91 MGMT_EV_NEW_LINK_KEY,
92 MGMT_EV_NEW_LONG_TERM_KEY,
93 MGMT_EV_DEVICE_CONNECTED,
94 MGMT_EV_DEVICE_DISCONNECTED,
95 MGMT_EV_CONNECT_FAILED,
96 MGMT_EV_PIN_CODE_REQUEST,
97 MGMT_EV_USER_CONFIRM_REQUEST,
98 MGMT_EV_USER_PASSKEY_REQUEST,
99 MGMT_EV_AUTH_FAILED,
100 MGMT_EV_DEVICE_FOUND,
101 MGMT_EV_DISCOVERING,
102 MGMT_EV_DEVICE_BLOCKED,
103 MGMT_EV_DEVICE_UNBLOCKED,
104 MGMT_EV_DEVICE_UNPAIRED,
105};
106
Andre Guedes3fd24152012-02-03 17:48:01 -0300107/*
108 * These LE scan and inquiry parameters were chosen according to LE General
109 * Discovery Procedure specification.
110 */
111#define LE_SCAN_TYPE 0x01
112#define LE_SCAN_WIN 0x12
113#define LE_SCAN_INT 0x12
114#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300115#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300116
Andre Guedese8777522012-02-03 17:48:02 -0300117#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300118#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300119
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800120#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200121
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200122#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
123 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
124
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200125struct pending_cmd {
126 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200127 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200128 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100129 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200130 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300131 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200132};
133
Johan Hedbergca69b792011-11-11 18:10:00 +0200134/* HCI to MGMT error code conversion table */
135static u8 mgmt_status_table[] = {
136 MGMT_STATUS_SUCCESS,
137 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
138 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
139 MGMT_STATUS_FAILED, /* Hardware Failure */
140 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
141 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
142 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
143 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
144 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
146 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
147 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
148 MGMT_STATUS_BUSY, /* Command Disallowed */
149 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
150 MGMT_STATUS_REJECTED, /* Rejected Security */
151 MGMT_STATUS_REJECTED, /* Rejected Personal */
152 MGMT_STATUS_TIMEOUT, /* Host Timeout */
153 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
154 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
155 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
156 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
157 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
158 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
159 MGMT_STATUS_BUSY, /* Repeated Attempts */
160 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
161 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
162 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
163 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
164 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
165 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
166 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
167 MGMT_STATUS_FAILED, /* Unspecified Error */
168 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
169 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
170 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
171 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
172 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
173 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
174 MGMT_STATUS_FAILED, /* Unit Link Key Used */
175 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
176 MGMT_STATUS_TIMEOUT, /* Instant Passed */
177 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
178 MGMT_STATUS_FAILED, /* Transaction Collision */
179 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
180 MGMT_STATUS_REJECTED, /* QoS Rejected */
181 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
182 MGMT_STATUS_REJECTED, /* Insufficient Security */
183 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
184 MGMT_STATUS_BUSY, /* Role Switch Pending */
185 MGMT_STATUS_FAILED, /* Slot Violation */
186 MGMT_STATUS_FAILED, /* Role Switch Failed */
187 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
188 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
189 MGMT_STATUS_BUSY, /* Host Busy Pairing */
190 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
191 MGMT_STATUS_BUSY, /* Controller Busy */
192 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
193 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
194 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
195 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
196 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
197};
198
199static u8 mgmt_status(u8 hci_status)
200{
201 if (hci_status < ARRAY_SIZE(mgmt_status_table))
202 return mgmt_status_table[hci_status];
203
204 return MGMT_STATUS_FAILED;
205}
206
Szymon Janc4e51eae2011-02-25 19:05:48 +0100207static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200208{
209 struct sk_buff *skb;
210 struct mgmt_hdr *hdr;
211 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300212 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200213
Szymon Janc34eb5252011-02-28 14:10:08 +0100214 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215
216 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
217 if (!skb)
218 return -ENOMEM;
219
220 hdr = (void *) skb_put(skb, sizeof(*hdr));
221
222 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100223 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200224 hdr->len = cpu_to_le16(sizeof(*ev));
225
226 ev = (void *) skb_put(skb, sizeof(*ev));
227 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200228 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200229
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300230 err = sock_queue_rcv_skb(sk, skb);
231 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200232 kfree_skb(skb);
233
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300234 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200235}
236
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200237static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300238 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200239{
240 struct sk_buff *skb;
241 struct mgmt_hdr *hdr;
242 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300243 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200244
245 BT_DBG("sock %p", sk);
246
Johan Hedberga38528f2011-01-22 06:46:43 +0200247 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200248 if (!skb)
249 return -ENOMEM;
250
251 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200252
Johan Hedberg02d98122010-12-13 21:07:04 +0200253 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100254 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200255 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200256
Johan Hedberga38528f2011-01-22 06:46:43 +0200257 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200258 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200259 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100260
261 if (rp)
262 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200263
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300264 err = sock_queue_rcv_skb(sk, skb);
265 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200266 kfree_skb(skb);
267
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100268 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200269}
270
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300271static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
272 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200273{
274 struct mgmt_rp_read_version rp;
275
276 BT_DBG("sock %p", sk);
277
278 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200279 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200280
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200281 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300282 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200283}
284
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300285static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
286 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200287{
288 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200289 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
290 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200291 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200292 size_t rp_size;
293 int i, err;
294
295 BT_DBG("sock %p", sk);
296
297 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
298
299 rp = kmalloc(rp_size, GFP_KERNEL);
300 if (!rp)
301 return -ENOMEM;
302
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200303 rp->num_commands = __constant_cpu_to_le16(num_commands);
304 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200305
306 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
307 put_unaligned_le16(mgmt_commands[i], opcode);
308
309 for (i = 0; i < num_events; i++, opcode++)
310 put_unaligned_le16(mgmt_events[i], opcode);
311
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200312 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300313 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200314 kfree(rp);
315
316 return err;
317}
318
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300319static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
320 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200321{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 struct mgmt_rp_read_index_list *rp;
323 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200324 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200325 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200326 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200327 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328
329 BT_DBG("sock %p", sk);
330
331 read_lock(&hci_dev_list_lock);
332
333 count = 0;
334 list_for_each(p, &hci_dev_list) {
335 count++;
336 }
337
Johan Hedberga38528f2011-01-22 06:46:43 +0200338 rp_len = sizeof(*rp) + (2 * count);
339 rp = kmalloc(rp_len, GFP_ATOMIC);
340 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100341 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200342 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100343 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200344
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200345 rp->num_controllers = cpu_to_le16(count);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200346
347 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200348 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200349 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200350 continue;
351
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200352 rp->index[i++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200353 BT_DBG("Added hci%u", d->id);
354 }
355
356 read_unlock(&hci_dev_list_lock);
357
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200358 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300359 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360
Johan Hedberga38528f2011-01-22 06:46:43 +0200361 kfree(rp);
362
363 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364}
365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200367{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200368 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200369
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200370 settings |= MGMT_SETTING_POWERED;
371 settings |= MGMT_SETTING_CONNECTABLE;
372 settings |= MGMT_SETTING_FAST_CONNECTABLE;
373 settings |= MGMT_SETTING_DISCOVERABLE;
374 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200375
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200376 if (hdev->features[6] & LMP_SIMPLE_PAIR)
377 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200378
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200379 if (!(hdev->features[4] & LMP_NO_BREDR)) {
380 settings |= MGMT_SETTING_BREDR;
381 settings |= MGMT_SETTING_LINK_SECURITY;
382 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200383
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100384 if (enable_hs)
385 settings |= MGMT_SETTING_HS;
386
387 if (enable_le) {
388 if (hdev->features[4] & LMP_LE)
389 settings |= MGMT_SETTING_LE;
390 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200391
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200392 return settings;
393}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200394
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200395static u32 get_current_settings(struct hci_dev *hdev)
396{
397 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200398
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200399 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100400 settings |= MGMT_SETTING_POWERED;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_CONNECTABLE;
404
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200405 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_DISCOVERABLE;
407
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200408 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_PAIRABLE;
410
411 if (!(hdev->features[4] & LMP_NO_BREDR))
412 settings |= MGMT_SETTING_BREDR;
413
Johan Hedberg06199cf2012-02-22 16:37:11 +0200414 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200416
Johan Hedberg47990ea2012-02-22 11:58:37 +0200417 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200419
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200420 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200421 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200422
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200423 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
424 settings |= MGMT_SETTING_HS;
425
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200426 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200427}
428
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300429#define PNP_INFO_SVCLASS_ID 0x1200
430
431static u8 bluetooth_base_uuid[] = {
432 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
433 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
434};
435
436static u16 get_uuid16(u8 *uuid128)
437{
438 u32 val;
439 int i;
440
441 for (i = 0; i < 12; i++) {
442 if (bluetooth_base_uuid[i] != uuid128[i])
443 return 0;
444 }
445
446 memcpy(&val, &uuid128[12], 4);
447
448 val = le32_to_cpu(val);
449 if (val > 0xffff)
450 return 0;
451
452 return (u16) val;
453}
454
455static void create_eir(struct hci_dev *hdev, u8 *data)
456{
457 u8 *ptr = data;
458 u16 eir_len = 0;
459 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
460 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200461 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300462 size_t name_len;
463
464 name_len = strlen(hdev->dev_name);
465
466 if (name_len > 0) {
467 /* EIR Data type */
468 if (name_len > 48) {
469 name_len = 48;
470 ptr[1] = EIR_NAME_SHORT;
471 } else
472 ptr[1] = EIR_NAME_COMPLETE;
473
474 /* EIR Data length */
475 ptr[0] = name_len + 1;
476
477 memcpy(ptr + 2, hdev->dev_name, name_len);
478
479 eir_len += (name_len + 2);
480 ptr += (name_len + 2);
481 }
482
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700483 if (hdev->inq_tx_power) {
484 ptr[0] = 2;
485 ptr[1] = EIR_TX_POWER;
486 ptr[2] = (u8) hdev->inq_tx_power;
487
488 eir_len += 3;
489 ptr += 3;
490 }
491
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700492 if (hdev->devid_source > 0) {
493 ptr[0] = 9;
494 ptr[1] = EIR_DEVICE_ID;
495
496 put_unaligned_le16(hdev->devid_source, ptr + 2);
497 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
498 put_unaligned_le16(hdev->devid_product, ptr + 6);
499 put_unaligned_le16(hdev->devid_version, ptr + 8);
500
501 eir_len += 10;
502 ptr += 10;
503 }
504
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300505 memset(uuid16_list, 0, sizeof(uuid16_list));
506
507 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200508 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300509 u16 uuid16;
510
511 uuid16 = get_uuid16(uuid->uuid);
512 if (uuid16 == 0)
513 return;
514
515 if (uuid16 < 0x1100)
516 continue;
517
518 if (uuid16 == PNP_INFO_SVCLASS_ID)
519 continue;
520
521 /* Stop if not enough space to put next UUID */
522 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
523 truncated = 1;
524 break;
525 }
526
527 /* Check for duplicates */
528 for (i = 0; uuid16_list[i] != 0; i++)
529 if (uuid16_list[i] == uuid16)
530 break;
531
532 if (uuid16_list[i] == 0) {
533 uuid16_list[i] = uuid16;
534 eir_len += sizeof(u16);
535 }
536 }
537
538 if (uuid16_list[0] != 0) {
539 u8 *length = ptr;
540
541 /* EIR Data type */
542 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
543
544 ptr += 2;
545 eir_len += 2;
546
547 for (i = 0; uuid16_list[i] != 0; i++) {
548 *ptr++ = (uuid16_list[i] & 0x00ff);
549 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
550 }
551
552 /* EIR Data length */
553 *length = (i * sizeof(u16)) + 1;
554 }
555}
556
557static int update_eir(struct hci_dev *hdev)
558{
559 struct hci_cp_write_eir cp;
560
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200561 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200562 return 0;
563
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300564 if (!(hdev->features[6] & LMP_EXT_INQ))
565 return 0;
566
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200567 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300568 return 0;
569
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200570 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300571 return 0;
572
573 memset(&cp, 0, sizeof(cp));
574
575 create_eir(hdev, cp.data);
576
577 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
578 return 0;
579
580 memcpy(hdev->eir, cp.data, sizeof(cp.data));
581
582 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
583}
584
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200585static u8 get_service_classes(struct hci_dev *hdev)
586{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300587 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200588 u8 val = 0;
589
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300590 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200591 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200592
593 return val;
594}
595
596static int update_class(struct hci_dev *hdev)
597{
598 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200599 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200600
601 BT_DBG("%s", hdev->name);
602
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200603 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200604 return 0;
605
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200606 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200607 return 0;
608
609 cod[0] = hdev->minor_class;
610 cod[1] = hdev->major_class;
611 cod[2] = get_service_classes(hdev);
612
613 if (memcmp(cod, hdev->dev_class, 3) == 0)
614 return 0;
615
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200616 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
617 if (err == 0)
618 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
619
620 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200621}
622
Johan Hedberg7d785252011-12-15 00:47:39 +0200623static void service_cache_off(struct work_struct *work)
624{
625 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300626 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200627
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200628 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200629 return;
630
631 hci_dev_lock(hdev);
632
633 update_eir(hdev);
634 update_class(hdev);
635
636 hci_dev_unlock(hdev);
637}
638
Johan Hedberg6a919082012-02-28 06:17:26 +0200639static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200640{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200641 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200642 return;
643
Johan Hedberg4f87da82012-03-02 19:55:56 +0200644 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200645
Johan Hedberg4f87da82012-03-02 19:55:56 +0200646 /* Non-mgmt controlled devices get this bit set
647 * implicitly so that pairing works for them, however
648 * for mgmt we require user-space to explicitly enable
649 * it
650 */
651 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200652}
653
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200654static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300655 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200656{
657 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200658
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200659 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200660
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300661 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200662
Johan Hedberg03811012010-12-08 00:21:06 +0200663 memset(&rp, 0, sizeof(rp));
664
Johan Hedberg03811012010-12-08 00:21:06 +0200665 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200666
667 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200668 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200669
670 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
671 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
672
673 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200674
675 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200676 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200677
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300678 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200679
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200680 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300681 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200682}
683
684static void mgmt_pending_free(struct pending_cmd *cmd)
685{
686 sock_put(cmd->sk);
687 kfree(cmd->param);
688 kfree(cmd);
689}
690
691static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300692 struct hci_dev *hdev, void *data,
693 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200694{
695 struct pending_cmd *cmd;
696
697 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
698 if (!cmd)
699 return NULL;
700
701 cmd->opcode = opcode;
702 cmd->index = hdev->id;
703
704 cmd->param = kmalloc(len, GFP_ATOMIC);
705 if (!cmd->param) {
706 kfree(cmd);
707 return NULL;
708 }
709
710 if (data)
711 memcpy(cmd->param, data, len);
712
713 cmd->sk = sk;
714 sock_hold(sk);
715
716 list_add(&cmd->list, &hdev->mgmt_pending);
717
718 return cmd;
719}
720
721static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300722 void (*cb)(struct pending_cmd *cmd, void *data),
723 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200724{
725 struct list_head *p, *n;
726
727 list_for_each_safe(p, n, &hdev->mgmt_pending) {
728 struct pending_cmd *cmd;
729
730 cmd = list_entry(p, struct pending_cmd, list);
731
732 if (opcode > 0 && cmd->opcode != opcode)
733 continue;
734
735 cb(cmd, data);
736 }
737}
738
739static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
740{
741 struct pending_cmd *cmd;
742
743 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
744 if (cmd->opcode == opcode)
745 return cmd;
746 }
747
748 return NULL;
749}
750
751static void mgmt_pending_remove(struct pending_cmd *cmd)
752{
753 list_del(&cmd->list);
754 mgmt_pending_free(cmd);
755}
756
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200757static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200758{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200759 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200760
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200761 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300762 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200763}
764
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200765static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300766 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200767{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300768 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200769 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200770 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200771
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200772 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200773
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300774 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200775
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100776 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
777 cancel_delayed_work(&hdev->power_off);
778
779 if (cp->val) {
780 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
781 mgmt_powered(hdev, 1);
782 goto failed;
783 }
784 }
785
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200786 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200787 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 goto failed;
789 }
790
791 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200792 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300793 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200794 goto failed;
795 }
796
797 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
798 if (!cmd) {
799 err = -ENOMEM;
800 goto failed;
801 }
802
803 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200804 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200805 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200806 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200807
808 err = 0;
809
810failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300811 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200812 return err;
813}
814
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300815static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
816 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200817{
818 struct sk_buff *skb;
819 struct mgmt_hdr *hdr;
820
821 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
822 if (!skb)
823 return -ENOMEM;
824
825 hdr = (void *) skb_put(skb, sizeof(*hdr));
826 hdr->opcode = cpu_to_le16(event);
827 if (hdev)
828 hdr->index = cpu_to_le16(hdev->id);
829 else
830 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
831 hdr->len = cpu_to_le16(data_len);
832
833 if (data)
834 memcpy(skb_put(skb, data_len), data, data_len);
835
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100836 /* Time stamp */
837 __net_timestamp(skb);
838
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200839 hci_send_to_control(skb, skip_sk);
840 kfree_skb(skb);
841
842 return 0;
843}
844
845static int new_settings(struct hci_dev *hdev, struct sock *skip)
846{
847 __le32 ev;
848
849 ev = cpu_to_le32(get_current_settings(hdev));
850
851 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
852}
853
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200854static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300855 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200856{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300857 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200858 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200859 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200860 u8 scan;
861 int err;
862
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200863 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200864
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700865 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100866 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200867 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300868 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200869
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300870 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200871
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200872 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200873 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300874 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200875 goto failed;
876 }
877
878 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
879 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200880 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300881 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200882 goto failed;
883 }
884
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200885 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200886 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300887 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200888 goto failed;
889 }
890
891 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200892 bool changed = false;
893
894 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
895 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
896 changed = true;
897 }
898
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200899 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200900 if (err < 0)
901 goto failed;
902
903 if (changed)
904 err = new_settings(hdev, sk);
905
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200906 goto failed;
907 }
908
909 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100910 if (hdev->discov_timeout > 0) {
911 cancel_delayed_work(&hdev->discov_off);
912 hdev->discov_timeout = 0;
913 }
914
915 if (cp->val && timeout > 0) {
916 hdev->discov_timeout = timeout;
917 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
918 msecs_to_jiffies(hdev->discov_timeout * 1000));
919 }
920
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200921 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200922 goto failed;
923 }
924
925 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
926 if (!cmd) {
927 err = -ENOMEM;
928 goto failed;
929 }
930
931 scan = SCAN_PAGE;
932
933 if (cp->val)
934 scan |= SCAN_INQUIRY;
935 else
936 cancel_delayed_work(&hdev->discov_off);
937
938 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
939 if (err < 0)
940 mgmt_pending_remove(cmd);
941
Johan Hedberg03811012010-12-08 00:21:06 +0200942 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200943 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200944
945failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300946 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200947 return err;
948}
949
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200950static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300951 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200952{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300953 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200954 struct pending_cmd *cmd;
955 u8 scan;
956 int err;
957
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200958 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200959
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300960 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200961
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200962 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200963 bool changed = false;
964
965 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
966 changed = true;
967
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200968 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200969 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200970 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200971 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
972 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
973 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200974
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200975 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200976 if (err < 0)
977 goto failed;
978
979 if (changed)
980 err = new_settings(hdev, sk);
981
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200982 goto failed;
983 }
984
985 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
986 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200987 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300988 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200989 goto failed;
990 }
991
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200992 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200993 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200994 goto failed;
995 }
996
997 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
998 if (!cmd) {
999 err = -ENOMEM;
1000 goto failed;
1001 }
1002
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001003 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001004 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001005 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 scan = 0;
1007
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001008 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1009 hdev->discov_timeout > 0)
1010 cancel_delayed_work(&hdev->discov_off);
1011 }
1012
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001013 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1014 if (err < 0)
1015 mgmt_pending_remove(cmd);
1016
1017failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001018 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001019 return err;
1020}
1021
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001022static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001023 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001024{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001025 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001026 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001027
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001028 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001029
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001030 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001031
1032 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001033 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001035 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001037 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001038 if (err < 0)
1039 goto failed;
1040
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001041 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001042
1043failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001044 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001045 return err;
1046}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001047
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001048static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1049 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001050{
1051 struct mgmt_mode *cp = data;
1052 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001053 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001054 int err;
1055
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001056 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001057
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001058 hci_dev_lock(hdev);
1059
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001060 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001061 bool changed = false;
1062
1063 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1064 &hdev->dev_flags)) {
1065 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1066 changed = true;
1067 }
1068
1069 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1070 if (err < 0)
1071 goto failed;
1072
1073 if (changed)
1074 err = new_settings(hdev, sk);
1075
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001076 goto failed;
1077 }
1078
1079 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001080 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001081 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001082 goto failed;
1083 }
1084
1085 val = !!cp->val;
1086
1087 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1088 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1089 goto failed;
1090 }
1091
1092 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1093 if (!cmd) {
1094 err = -ENOMEM;
1095 goto failed;
1096 }
1097
1098 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1099 if (err < 0) {
1100 mgmt_pending_remove(cmd);
1101 goto failed;
1102 }
1103
1104failed:
1105 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001106 return err;
1107}
1108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001109static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001110{
1111 struct mgmt_mode *cp = data;
1112 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001113 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001114 int err;
1115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001116 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001117
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001118 hci_dev_lock(hdev);
1119
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001120 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001121 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001122 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001123 goto failed;
1124 }
1125
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001126 val = !!cp->val;
1127
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001128 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001129 bool changed = false;
1130
1131 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1132 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1133 changed = true;
1134 }
1135
1136 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1137 if (err < 0)
1138 goto failed;
1139
1140 if (changed)
1141 err = new_settings(hdev, sk);
1142
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001143 goto failed;
1144 }
1145
1146 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001147 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1148 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001149 goto failed;
1150 }
1151
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001152 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1153 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1154 goto failed;
1155 }
1156
1157 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1158 if (!cmd) {
1159 err = -ENOMEM;
1160 goto failed;
1161 }
1162
1163 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1164 if (err < 0) {
1165 mgmt_pending_remove(cmd);
1166 goto failed;
1167 }
1168
1169failed:
1170 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001171 return err;
1172}
1173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001174static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001175{
1176 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001179
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001180 if (!enable_hs)
1181 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001182 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001183
1184 if (cp->val)
1185 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1186 else
1187 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1188
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001189 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001190}
1191
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001192static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001193{
1194 struct mgmt_mode *cp = data;
1195 struct hci_cp_write_le_host_supported hci_cp;
1196 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001197 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001198 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001200 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001201
Johan Hedberg1de028c2012-02-29 19:55:35 -08001202 hci_dev_lock(hdev);
1203
Johan Hedberg06199cf2012-02-22 16:37:11 +02001204 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001205 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001206 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001207 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001208 }
1209
1210 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001211 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001212
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001213 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001214 bool changed = false;
1215
1216 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1217 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1218 changed = true;
1219 }
1220
1221 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1222 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001223 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001224
1225 if (changed)
1226 err = new_settings(hdev, sk);
1227
Johan Hedberg1de028c2012-02-29 19:55:35 -08001228 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001229 }
1230
1231 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001232 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001233 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001234 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001235 }
1236
1237 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1238 if (!cmd) {
1239 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001240 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001241 }
1242
1243 memset(&hci_cp, 0, sizeof(hci_cp));
1244
1245 if (val) {
1246 hci_cp.le = val;
1247 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1248 }
1249
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001250 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1251 &hci_cp);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001252 if (err < 0) {
1253 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001254 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001255 }
1256
Johan Hedberg1de028c2012-02-29 19:55:35 -08001257unlock:
1258 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001259 return err;
1260}
1261
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001262static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001263{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001264 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001265 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001266 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001267 int err;
1268
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001269 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001270
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001271 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001272
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001273 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001274 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001275 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001276 goto failed;
1277 }
1278
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001279 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1280 if (!uuid) {
1281 err = -ENOMEM;
1282 goto failed;
1283 }
1284
1285 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001286 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001287
1288 list_add(&uuid->list, &hdev->uuids);
1289
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001290 err = update_class(hdev);
1291 if (err < 0)
1292 goto failed;
1293
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001294 err = update_eir(hdev);
1295 if (err < 0)
1296 goto failed;
1297
Johan Hedberg90e70452012-02-23 23:09:40 +02001298 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001299 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001300 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001301 goto failed;
1302 }
1303
1304 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1305 if (!cmd) {
1306 err = -ENOMEM;
1307 goto failed;
1308 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001309
1310failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001311 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001312 return err;
1313}
1314
Johan Hedberg24b78d02012-02-23 23:24:30 +02001315static bool enable_service_cache(struct hci_dev *hdev)
1316{
1317 if (!hdev_is_powered(hdev))
1318 return false;
1319
1320 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001321 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001322 return true;
1323 }
1324
1325 return false;
1326}
1327
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001328static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1329 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001330{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001331 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001332 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001333 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001334 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 +02001335 int err, found;
1336
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001337 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001339 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001340
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001341 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001342 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001343 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001344 goto unlock;
1345 }
1346
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001347 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1348 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001349
Johan Hedberg24b78d02012-02-23 23:24:30 +02001350 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001351 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001352 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001353 goto unlock;
1354 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001355
Johan Hedberg9246a862012-02-23 21:33:16 +02001356 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001357 }
1358
1359 found = 0;
1360
1361 list_for_each_safe(p, n, &hdev->uuids) {
1362 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1363
1364 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1365 continue;
1366
1367 list_del(&match->list);
1368 found++;
1369 }
1370
1371 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001372 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001373 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001374 goto unlock;
1375 }
1376
Johan Hedberg9246a862012-02-23 21:33:16 +02001377update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001378 err = update_class(hdev);
1379 if (err < 0)
1380 goto unlock;
1381
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001382 err = update_eir(hdev);
1383 if (err < 0)
1384 goto unlock;
1385
Johan Hedberg90e70452012-02-23 23:09:40 +02001386 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001387 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001388 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001389 goto unlock;
1390 }
1391
1392 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1393 if (!cmd) {
1394 err = -ENOMEM;
1395 goto unlock;
1396 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001397
1398unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001399 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001400 return err;
1401}
1402
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001403static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001404 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001405{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001406 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001407 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001408 int err;
1409
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001410 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001411
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001412 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001413
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001414 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001415 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001416 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001417 goto unlock;
1418 }
1419
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001420 hdev->major_class = cp->major;
1421 hdev->minor_class = cp->minor;
1422
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001423 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001424 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001425 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001426 goto unlock;
1427 }
1428
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001429 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001430 hci_dev_unlock(hdev);
1431 cancel_delayed_work_sync(&hdev->service_cache);
1432 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001433 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001434 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001435
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001436 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001437 if (err < 0)
1438 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001439
Johan Hedberg90e70452012-02-23 23:09:40 +02001440 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001441 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001442 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001443 goto unlock;
1444 }
1445
1446 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1447 if (!cmd) {
1448 err = -ENOMEM;
1449 goto unlock;
1450 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001451
Johan Hedbergb5235a62012-02-21 14:32:24 +02001452unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001453 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001454 return err;
1455}
1456
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001457static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1458 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001459{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001460 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001461 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001462 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001463
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001464 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001465
Johan Hedberg86742e12011-11-07 23:13:38 +02001466 expected_len = sizeof(*cp) + key_count *
1467 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001468 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001469 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001470 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001471 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001472 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001473 }
1474
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001475 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001476 key_count);
1477
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001478 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001479
1480 hci_link_keys_clear(hdev);
1481
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001482 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001483
1484 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001485 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001486 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001487 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001488
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001489 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001490 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001491
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001492 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001493 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001494 }
1495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001496 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001497
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001498 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001499
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001500 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001501}
1502
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001503static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001504 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001505{
1506 struct mgmt_ev_device_unpaired ev;
1507
1508 bacpy(&ev.addr.bdaddr, bdaddr);
1509 ev.addr.type = addr_type;
1510
1511 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001512 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001513}
1514
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001515static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001516 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001517{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001518 struct mgmt_cp_unpair_device *cp = data;
1519 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001520 struct hci_cp_disconnect dc;
1521 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001522 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001523 int err;
1524
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001525 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001526
Johan Hedberga8a1d192011-11-10 15:54:38 +02001527 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001528 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1529 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001530
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001531 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001532 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001533 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001534 goto unlock;
1535 }
1536
Johan Hedberg124f6e32012-02-09 13:50:12 +02001537 if (cp->addr.type == MGMT_ADDR_BREDR)
1538 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1539 else
1540 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001541
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001542 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001543 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001544 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001545 goto unlock;
1546 }
1547
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001548 if (cp->disconnect) {
1549 if (cp->addr.type == MGMT_ADDR_BREDR)
1550 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1551 &cp->addr.bdaddr);
1552 else
1553 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1554 &cp->addr.bdaddr);
1555 } else {
1556 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001557 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001558
Johan Hedberga8a1d192011-11-10 15:54:38 +02001559 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001560 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001561 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001562 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001563 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001564 }
1565
Johan Hedberg124f6e32012-02-09 13:50:12 +02001566 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001567 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001568 if (!cmd) {
1569 err = -ENOMEM;
1570 goto unlock;
1571 }
1572
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001573 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001574 dc.reason = 0x13; /* Remote User Terminated Connection */
1575 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1576 if (err < 0)
1577 mgmt_pending_remove(cmd);
1578
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001579unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001580 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001581 return err;
1582}
1583
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001584static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001585 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001586{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001587 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001588 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001589 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001590 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001591 int err;
1592
1593 BT_DBG("");
1594
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001595 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001596
1597 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001598 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001599 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001600 goto failed;
1601 }
1602
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001603 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001604 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001605 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001606 goto failed;
1607 }
1608
Johan Hedberg88c3df12012-02-09 14:27:38 +02001609 if (cp->addr.type == MGMT_ADDR_BREDR)
1610 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1611 else
1612 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001613
Johan Hedberg8962ee72011-01-20 12:40:27 +02001614 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001615 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001616 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001617 goto failed;
1618 }
1619
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001620 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001621 if (!cmd) {
1622 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001623 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001624 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001625
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001626 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001627 dc.reason = 0x13; /* Remote User Terminated Connection */
1628
1629 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1630 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001631 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001632
1633failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001634 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001635 return err;
1636}
1637
Johan Hedberg48264f02011-11-09 13:58:58 +02001638static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001639{
1640 switch (link_type) {
1641 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001642 switch (addr_type) {
1643 case ADDR_LE_DEV_PUBLIC:
1644 return MGMT_ADDR_LE_PUBLIC;
1645 case ADDR_LE_DEV_RANDOM:
1646 return MGMT_ADDR_LE_RANDOM;
1647 default:
1648 return MGMT_ADDR_INVALID;
1649 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001650 case ACL_LINK:
1651 return MGMT_ADDR_BREDR;
1652 default:
1653 return MGMT_ADDR_INVALID;
1654 }
1655}
1656
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001657static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1658 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001659{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001660 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001661 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001662 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001663 int err;
1664 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001665
1666 BT_DBG("");
1667
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001668 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001669
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001670 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001671 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001672 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001673 goto unlock;
1674 }
1675
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001676 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001677 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1678 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001679 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001680 }
1681
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001682 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001683 rp = kmalloc(rp_len, GFP_ATOMIC);
1684 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001685 err = -ENOMEM;
1686 goto unlock;
1687 }
1688
Johan Hedberg2784eb42011-01-21 13:56:35 +02001689 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001690 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001691 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1692 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001693 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001694 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001695 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1696 continue;
1697 i++;
1698 }
1699
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001700 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001701
Johan Hedberg4c659c32011-11-07 23:13:39 +02001702 /* Recalculate length in case of filtered SCO connections, etc */
1703 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001704
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001705 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001706 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001707
Johan Hedberga38528f2011-01-22 06:46:43 +02001708 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001709
1710unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001711 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001712 return err;
1713}
1714
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001715static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001716 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001717{
1718 struct pending_cmd *cmd;
1719 int err;
1720
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001721 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001722 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001723 if (!cmd)
1724 return -ENOMEM;
1725
Johan Hedbergd8457692012-02-17 14:24:57 +02001726 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001727 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001728 if (err < 0)
1729 mgmt_pending_remove(cmd);
1730
1731 return err;
1732}
1733
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001734static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001735 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001736{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001737 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001738 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001739 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001740 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001741 int err;
1742
1743 BT_DBG("");
1744
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001745 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001746
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001747 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001748 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001749 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001750 goto failed;
1751 }
1752
Johan Hedbergd8457692012-02-17 14:24:57 +02001753 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001754 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001755 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001756 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001757 goto failed;
1758 }
1759
1760 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001761 struct mgmt_cp_pin_code_neg_reply ncp;
1762
1763 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001764
1765 BT_ERR("PIN code is not 16 bytes long");
1766
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001767 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001768 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001769 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001770 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001771
1772 goto failed;
1773 }
1774
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001775 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001776 if (!cmd) {
1777 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001778 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001779 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001780
Johan Hedbergd8457692012-02-17 14:24:57 +02001781 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001782 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001783 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001784
1785 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1786 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001787 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001788
1789failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001790 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001791 return err;
1792}
1793
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001794static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001795 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001796{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001797 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001798 int err;
1799
1800 BT_DBG("");
1801
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001802 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001803
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001804 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001805 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001806 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001807 goto failed;
1808 }
1809
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001810 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001811
1812failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001813 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001814 return err;
1815}
1816
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001817static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1818 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001819{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001820 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001821
1822 BT_DBG("");
1823
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001824 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001825
1826 hdev->io_capability = cp->io_capability;
1827
1828 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001829 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001830
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001831 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001832
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001833 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1834 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001835}
1836
Johan Hedberge9a416b2011-02-19 12:05:56 -03001837static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1838{
1839 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001840 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001841
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001842 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001843 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1844 continue;
1845
Johan Hedberge9a416b2011-02-19 12:05:56 -03001846 if (cmd->user_data != conn)
1847 continue;
1848
1849 return cmd;
1850 }
1851
1852 return NULL;
1853}
1854
1855static void pairing_complete(struct pending_cmd *cmd, u8 status)
1856{
1857 struct mgmt_rp_pair_device rp;
1858 struct hci_conn *conn = cmd->user_data;
1859
Johan Hedbergba4e5642011-11-11 00:07:34 +02001860 bacpy(&rp.addr.bdaddr, &conn->dst);
1861 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001862
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001863 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001864 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001865
1866 /* So we don't get further callbacks for this connection */
1867 conn->connect_cfm_cb = NULL;
1868 conn->security_cfm_cb = NULL;
1869 conn->disconn_cfm_cb = NULL;
1870
1871 hci_conn_put(conn);
1872
Johan Hedberga664b5b2011-02-19 12:06:02 -03001873 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001874}
1875
1876static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1877{
1878 struct pending_cmd *cmd;
1879
1880 BT_DBG("status %u", status);
1881
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001882 cmd = find_pairing(conn);
1883 if (!cmd)
1884 BT_DBG("Unable to find a pending command");
1885 else
Johan Hedberge2113262012-02-18 15:20:03 +02001886 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001887}
1888
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001889static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001890 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001891{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001892 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001893 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001894 struct pending_cmd *cmd;
1895 u8 sec_level, auth_type;
1896 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001897 int err;
1898
1899 BT_DBG("");
1900
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001901 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001902
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001903 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001904 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001905 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001906 goto unlock;
1907 }
1908
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001909 sec_level = BT_SECURITY_MEDIUM;
1910 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001911 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001912 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001913 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001914
Johan Hedbergba4e5642011-11-11 00:07:34 +02001915 if (cp->addr.type == MGMT_ADDR_BREDR)
1916 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001917 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001918 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001919 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001920 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001921
Johan Hedberg1425acb2011-11-11 00:07:35 +02001922 memset(&rp, 0, sizeof(rp));
1923 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1924 rp.addr.type = cp->addr.type;
1925
Ville Tervo30e76272011-02-22 16:10:53 -03001926 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001927 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001928 MGMT_STATUS_CONNECT_FAILED, &rp,
1929 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001930 goto unlock;
1931 }
1932
1933 if (conn->connect_cfm_cb) {
1934 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001935 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001936 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001937 goto unlock;
1938 }
1939
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001940 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001941 if (!cmd) {
1942 err = -ENOMEM;
1943 hci_conn_put(conn);
1944 goto unlock;
1945 }
1946
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001947 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001948 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001949 conn->connect_cfm_cb = pairing_complete_cb;
1950
Johan Hedberge9a416b2011-02-19 12:05:56 -03001951 conn->security_cfm_cb = pairing_complete_cb;
1952 conn->disconn_cfm_cb = pairing_complete_cb;
1953 conn->io_capability = cp->io_cap;
1954 cmd->user_data = conn;
1955
1956 if (conn->state == BT_CONNECTED &&
1957 hci_conn_security(conn, sec_level, auth_type))
1958 pairing_complete(cmd, 0);
1959
1960 err = 0;
1961
1962unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001963 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001964 return err;
1965}
1966
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001967static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1968 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001969{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001970 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001971 struct pending_cmd *cmd;
1972 struct hci_conn *conn;
1973 int err;
1974
1975 BT_DBG("");
1976
Johan Hedberg28424702012-02-02 04:02:29 +02001977 hci_dev_lock(hdev);
1978
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001979 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001980 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001981 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001982 goto unlock;
1983 }
1984
Johan Hedberg28424702012-02-02 04:02:29 +02001985 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1986 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001987 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001988 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001989 goto unlock;
1990 }
1991
1992 conn = cmd->user_data;
1993
1994 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001995 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001996 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001997 goto unlock;
1998 }
1999
2000 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2001
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002002 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002003 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002004unlock:
2005 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002006 return err;
2007}
2008
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002009static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002010 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2011 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002012{
Johan Hedberga5c29682011-02-19 12:05:57 -03002013 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002014 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002015 int err;
2016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002017 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002018
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002019 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002020 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002021 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002022 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002023 }
2024
Johan Hedberg272d90d2012-02-09 15:26:12 +02002025 if (type == MGMT_ADDR_BREDR)
2026 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2027 else
Brian Gix47c15e22011-11-16 13:53:14 -08002028 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002029
Johan Hedberg272d90d2012-02-09 15:26:12 +02002030 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002031 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002032 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002033 goto done;
2034 }
2035
2036 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002037 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002038 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002039
Brian Gix5fe57d92011-12-21 16:12:13 -08002040 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002041 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002042 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002043 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002044 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002045 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002046
Brian Gix47c15e22011-11-16 13:53:14 -08002047 goto done;
2048 }
2049
Brian Gix0df4c182011-11-16 13:53:13 -08002050 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002051 if (!cmd) {
2052 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002053 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002054 }
2055
Brian Gix0df4c182011-11-16 13:53:13 -08002056 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002057 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2058 struct hci_cp_user_passkey_reply cp;
2059
2060 bacpy(&cp.bdaddr, bdaddr);
2061 cp.passkey = passkey;
2062 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2063 } else
2064 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2065
Johan Hedberga664b5b2011-02-19 12:06:02 -03002066 if (err < 0)
2067 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002068
Brian Gix0df4c182011-11-16 13:53:13 -08002069done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002070 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002071 return err;
2072}
2073
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002074static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2075 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002076{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002077 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002078
2079 BT_DBG("");
2080
2081 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002082 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002083 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002084
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002085 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002086 MGMT_OP_USER_CONFIRM_REPLY,
2087 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002088}
2089
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002090static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002091 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002092{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002093 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002094
2095 BT_DBG("");
2096
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002097 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002098 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2099 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002100}
2101
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002102static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2103 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002104{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002105 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002106
2107 BT_DBG("");
2108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002109 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002110 MGMT_OP_USER_PASSKEY_REPLY,
2111 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002112}
2113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002114static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002115 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002116{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002117 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002118
2119 BT_DBG("");
2120
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002121 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002122 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2123 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002124}
2125
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002126static int update_name(struct hci_dev *hdev, const char *name)
2127{
2128 struct hci_cp_write_local_name cp;
2129
2130 memcpy(cp.name, name, sizeof(cp.name));
2131
2132 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2133}
2134
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002135static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002136 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002137{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002138 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002139 struct pending_cmd *cmd;
2140 int err;
2141
2142 BT_DBG("");
2143
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002144 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002145
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002146 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002147
Johan Hedbergb5235a62012-02-21 14:32:24 +02002148 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002149 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002150
2151 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002152 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002153 if (err < 0)
2154 goto failed;
2155
2156 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002157 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002158
Johan Hedbergb5235a62012-02-21 14:32:24 +02002159 goto failed;
2160 }
2161
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002162 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002163 if (!cmd) {
2164 err = -ENOMEM;
2165 goto failed;
2166 }
2167
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002168 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002169 if (err < 0)
2170 mgmt_pending_remove(cmd);
2171
2172failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002173 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002174 return err;
2175}
2176
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002177static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002178 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002179{
Szymon Jancc35938b2011-03-22 13:12:21 +01002180 struct pending_cmd *cmd;
2181 int err;
2182
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002183 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002184
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002185 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002186
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002187 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002188 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002189 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002190 goto unlock;
2191 }
2192
2193 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002194 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002195 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002196 goto unlock;
2197 }
2198
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002199 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002200 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002201 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002202 goto unlock;
2203 }
2204
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002205 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002206 if (!cmd) {
2207 err = -ENOMEM;
2208 goto unlock;
2209 }
2210
2211 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2212 if (err < 0)
2213 mgmt_pending_remove(cmd);
2214
2215unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002216 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002217 return err;
2218}
2219
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002220static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002221 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002222{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002223 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002224 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002225 int err;
2226
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002227 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002228
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002229 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002230
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002231 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002232 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002233 MGMT_STATUS_NOT_POWERED, &cp->addr,
2234 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002235 goto unlock;
2236 }
2237
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002238 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002239 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002240 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002241 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002242 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002243 status = 0;
2244
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002245 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002246 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002247
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002248unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002249 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002250 return err;
2251}
2252
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002253static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002254 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002255{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002256 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002257 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002258 int err;
2259
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002260 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002261
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002262 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002263
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002264 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002266 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2267 MGMT_STATUS_NOT_POWERED, &cp->addr,
2268 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002269 goto unlock;
2270 }
2271
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002272 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002273 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002274 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002275 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002276 status = 0;
2277
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002278 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002279 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002280
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002281unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002282 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002283 return err;
2284}
2285
Andre Guedes5e0452c2012-02-17 20:39:38 -03002286int mgmt_interleaved_discovery(struct hci_dev *hdev)
2287{
2288 int err;
2289
2290 BT_DBG("%s", hdev->name);
2291
2292 hci_dev_lock(hdev);
2293
2294 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2295 if (err < 0)
2296 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2297
2298 hci_dev_unlock(hdev);
2299
2300 return err;
2301}
2302
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002303static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002304 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002305{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002306 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002307 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002308 int err;
2309
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002310 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002311
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002312 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002313
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002314 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002315 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002316 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002317 goto failed;
2318 }
2319
Johan Hedbergff9ef572012-01-04 14:23:45 +02002320 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002321 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002322 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002323 goto failed;
2324 }
2325
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002326 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002327 if (!cmd) {
2328 err = -ENOMEM;
2329 goto failed;
2330 }
2331
Andre Guedes4aab14e2012-02-17 20:39:36 -03002332 hdev->discovery.type = cp->type;
2333
2334 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002335 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002336 if (lmp_bredr_capable(hdev))
2337 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2338 else
2339 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002340 break;
2341
2342 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002343 if (lmp_host_le_capable(hdev))
2344 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002345 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002346 else
2347 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002348 break;
2349
Andre Guedes5e0452c2012-02-17 20:39:38 -03002350 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002351 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2352 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002353 LE_SCAN_WIN,
2354 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002355 else
2356 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002357 break;
2358
Andre Guedesf39799f2012-02-17 20:39:35 -03002359 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002360 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002361 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002362
Johan Hedberg14a53662011-04-27 10:29:56 -04002363 if (err < 0)
2364 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002365 else
2366 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002367
2368failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002369 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002370 return err;
2371}
2372
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002373static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002374 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002375{
Johan Hedbergd9306502012-02-20 23:25:18 +02002376 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002377 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002378 struct hci_cp_remote_name_req_cancel cp;
2379 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002380 int err;
2381
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002382 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002383
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002384 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002385
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002386 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002387 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002388 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2389 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002390 goto unlock;
2391 }
2392
2393 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002394 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002395 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2396 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002397 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002398 }
2399
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002400 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002401 if (!cmd) {
2402 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002403 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002404 }
2405
Andre Guedes343f9352012-02-17 20:39:37 -03002406 if (hdev->discovery.state == DISCOVERY_FINDING) {
Andre Guedesc9ecc482012-03-15 16:52:08 -03002407 if (test_bit(HCI_INQUIRY, &hdev->flags))
2408 err = hci_cancel_inquiry(hdev);
2409 else
2410 err = hci_cancel_le_scan(hdev);
2411
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002412 if (err < 0)
2413 mgmt_pending_remove(cmd);
2414 else
2415 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2416 goto unlock;
2417 }
2418
2419 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2420 if (!e) {
2421 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002422 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002423 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002424 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2425 goto unlock;
2426 }
2427
2428 bacpy(&cp.bdaddr, &e->data.bdaddr);
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002429 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2430 &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002431 if (err < 0)
2432 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002433 else
2434 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002435
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002436unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002437 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002438 return err;
2439}
2440
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002441static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002442 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002443{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002444 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002445 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002446 int err;
2447
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002448 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002449
Johan Hedberg561aafb2012-01-04 13:31:59 +02002450 hci_dev_lock(hdev);
2451
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002452 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002453 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002454 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002455 goto failed;
2456 }
2457
Johan Hedberga198e7b2012-02-17 14:27:06 +02002458 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002459 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002460 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002461 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002462 goto failed;
2463 }
2464
2465 if (cp->name_known) {
2466 e->name_state = NAME_KNOWN;
2467 list_del(&e->list);
2468 } else {
2469 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002470 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002471 }
2472
2473 err = 0;
2474
2475failed:
2476 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002477 return err;
2478}
2479
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002480static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002481 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002482{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002483 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002484 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002485 int err;
2486
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002487 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002488
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002489 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002490
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002491 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002492 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002493 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002494 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002495 status = 0;
2496
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002497 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002498 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002499
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002500 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002501
2502 return err;
2503}
2504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002505static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002506 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002507{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002508 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002509 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002510 int err;
2511
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002512 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002513
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002514 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002515
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002516 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002517 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002518 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002519 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002520 status = 0;
2521
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002522 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002523 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002524
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002525 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002526
2527 return err;
2528}
2529
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002530static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2531 u16 len)
2532{
2533 struct mgmt_cp_set_device_id *cp = data;
2534 int err;
2535
2536 BT_DBG("%s", hdev->name);
2537
2538 hci_dev_lock(hdev);
2539
2540 hdev->devid_source = __le16_to_cpu(cp->source);
2541 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2542 hdev->devid_product = __le16_to_cpu(cp->product);
2543 hdev->devid_version = __le16_to_cpu(cp->version);
2544
2545 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2546
2547 update_eir(hdev);
2548
2549 hci_dev_unlock(hdev);
2550
2551 return err;
2552}
2553
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002554static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002555 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002556{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002557 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002558 struct hci_cp_write_page_scan_activity acp;
2559 u8 type;
2560 int err;
2561
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002562 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002563
Johan Hedberg5400c042012-02-21 16:40:33 +02002564 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002565 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002566 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002567
2568 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002569 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002570 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002571
2572 hci_dev_lock(hdev);
2573
Johan Hedbergf7c68692011-12-15 00:47:36 +02002574 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002575 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002576
2577 /* 22.5 msec page scan interval */
2578 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002579 } else {
2580 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002581
2582 /* default 1.28 sec page scan */
2583 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002584 }
2585
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002586 /* default 11.25 msec page scan window */
2587 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002588
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002589 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2590 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002591 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002592 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002593 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002594 goto done;
2595 }
2596
2597 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2598 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002599 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002600 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002601 goto done;
2602 }
2603
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002604 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002605 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002606done:
2607 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002608 return err;
2609}
2610
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002611static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002612 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002613{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002614 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2615 u16 key_count, expected_len;
2616 int i;
2617
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002618 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002619
2620 expected_len = sizeof(*cp) + key_count *
2621 sizeof(struct mgmt_ltk_info);
2622 if (expected_len != len) {
2623 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2624 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002625 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002626 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002627 }
2628
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002629 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002630
2631 hci_dev_lock(hdev);
2632
2633 hci_smp_ltks_clear(hdev);
2634
2635 for (i = 0; i < key_count; i++) {
2636 struct mgmt_ltk_info *key = &cp->keys[i];
2637 u8 type;
2638
2639 if (key->master)
2640 type = HCI_SMP_LTK;
2641 else
2642 type = HCI_SMP_LTK_SLAVE;
2643
2644 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002645 type, 0, key->authenticated, key->val,
2646 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002647 }
2648
2649 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002650
2651 return 0;
2652}
2653
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002654static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002655 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2656 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002657 bool var_len;
2658 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002659} mgmt_handlers[] = {
2660 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002661 { read_version, false, MGMT_READ_VERSION_SIZE },
2662 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2663 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2664 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2665 { set_powered, false, MGMT_SETTING_SIZE },
2666 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2667 { set_connectable, false, MGMT_SETTING_SIZE },
2668 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2669 { set_pairable, false, MGMT_SETTING_SIZE },
2670 { set_link_security, false, MGMT_SETTING_SIZE },
2671 { set_ssp, false, MGMT_SETTING_SIZE },
2672 { set_hs, false, MGMT_SETTING_SIZE },
2673 { set_le, false, MGMT_SETTING_SIZE },
2674 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2675 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2676 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2677 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2678 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2679 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2680 { disconnect, false, MGMT_DISCONNECT_SIZE },
2681 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2682 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2683 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2684 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2685 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2686 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2687 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2688 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2689 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2690 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2691 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2692 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2693 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2694 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2695 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2696 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2697 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2698 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2699 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002700 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002701};
2702
2703
Johan Hedberg03811012010-12-08 00:21:06 +02002704int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2705{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002706 void *buf;
2707 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002708 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002709 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002710 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002711 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002712 int err;
2713
2714 BT_DBG("got %zu bytes", msglen);
2715
2716 if (msglen < sizeof(*hdr))
2717 return -EINVAL;
2718
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002719 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002720 if (!buf)
2721 return -ENOMEM;
2722
2723 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2724 err = -EFAULT;
2725 goto done;
2726 }
2727
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002728 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002729 opcode = __le16_to_cpu(hdr->opcode);
2730 index = __le16_to_cpu(hdr->index);
2731 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002732
2733 if (len != msglen - sizeof(*hdr)) {
2734 err = -EINVAL;
2735 goto done;
2736 }
2737
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002738 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002739 hdev = hci_dev_get(index);
2740 if (!hdev) {
2741 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002742 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002743 goto done;
2744 }
2745 }
2746
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002747 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2748 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002749 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002750 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002751 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002752 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002753 }
2754
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002755 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2756 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2757 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002758 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002759 goto done;
2760 }
2761
Johan Hedbergbe22b542012-03-01 22:24:41 +02002762 handler = &mgmt_handlers[opcode];
2763
2764 if ((handler->var_len && len < handler->data_len) ||
2765 (!handler->var_len && len != handler->data_len)) {
2766 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002767 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002768 goto done;
2769 }
2770
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002771 if (hdev)
2772 mgmt_init_hdev(sk, hdev);
2773
2774 cp = buf + sizeof(*hdr);
2775
Johan Hedbergbe22b542012-03-01 22:24:41 +02002776 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002777 if (err < 0)
2778 goto done;
2779
Johan Hedberg03811012010-12-08 00:21:06 +02002780 err = msglen;
2781
2782done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002783 if (hdev)
2784 hci_dev_put(hdev);
2785
Johan Hedberg03811012010-12-08 00:21:06 +02002786 kfree(buf);
2787 return err;
2788}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002789
Johan Hedbergb24752f2011-11-03 14:40:33 +02002790static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2791{
2792 u8 *status = data;
2793
2794 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2795 mgmt_pending_remove(cmd);
2796}
2797
Johan Hedberg744cf192011-11-08 20:40:14 +02002798int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002799{
Johan Hedberg744cf192011-11-08 20:40:14 +02002800 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002801}
2802
Johan Hedberg744cf192011-11-08 20:40:14 +02002803int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002804{
Johan Hedberg5f159032012-03-02 03:13:19 +02002805 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002806
Johan Hedberg744cf192011-11-08 20:40:14 +02002807 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002808
Johan Hedberg744cf192011-11-08 20:40:14 +02002809 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002810}
2811
Johan Hedberg73f22f62010-12-29 16:00:25 +02002812struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002813 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002814 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002815 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002816};
2817
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002818static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002819{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002820 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002821
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002822 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002823
2824 list_del(&cmd->list);
2825
2826 if (match->sk == NULL) {
2827 match->sk = cmd->sk;
2828 sock_hold(match->sk);
2829 }
2830
2831 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002832}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002833
Johan Hedberg744cf192011-11-08 20:40:14 +02002834int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002835{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002836 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002837 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002838
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002839 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2840 return 0;
2841
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002842 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002843
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002844 if (powered) {
2845 u8 scan = 0;
2846
2847 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2848 scan |= SCAN_PAGE;
2849 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2850 scan |= SCAN_INQUIRY;
2851
2852 if (scan)
2853 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002854
2855 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002856 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002857 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002858 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002859 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002860 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002861 }
2862
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002863 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002864
2865 if (match.sk)
2866 sock_put(match.sk);
2867
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002868 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002869}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002870
Johan Hedberg744cf192011-11-08 20:40:14 +02002871int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002872{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002873 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002874 bool changed = false;
2875 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002876
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002877 if (discoverable) {
2878 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2879 changed = true;
2880 } else {
2881 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2882 changed = true;
2883 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002884
Johan Hedberged9b5f22012-02-21 20:47:06 +02002885 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002886 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002887
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002888 if (changed)
2889 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002890
Johan Hedberg73f22f62010-12-29 16:00:25 +02002891 if (match.sk)
2892 sock_put(match.sk);
2893
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002894 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002895}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002896
Johan Hedberg744cf192011-11-08 20:40:14 +02002897int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002898{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002899 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002900 bool changed = false;
2901 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002902
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002903 if (connectable) {
2904 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2905 changed = true;
2906 } else {
2907 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2908 changed = true;
2909 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002910
Johan Hedberged9b5f22012-02-21 20:47:06 +02002911 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002912 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002913
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002914 if (changed)
2915 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002916
2917 if (match.sk)
2918 sock_put(match.sk);
2919
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002920 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002921}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002922
Johan Hedberg744cf192011-11-08 20:40:14 +02002923int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002924{
Johan Hedbergca69b792011-11-11 18:10:00 +02002925 u8 mgmt_err = mgmt_status(status);
2926
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002927 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002928 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002929 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002930
2931 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002932 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002933 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002934
2935 return 0;
2936}
2937
Vishal Agarwal745c0ce2012-04-13 17:43:22 +05302938int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002939{
Johan Hedberg86742e12011-11-07 23:13:38 +02002940 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002941
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002942 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002943
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002944 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002945 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2946 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002947 ev.key.type = key->type;
2948 memcpy(ev.key.val, key->val, 16);
2949 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002950
Johan Hedberg744cf192011-11-08 20:40:14 +02002951 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002952}
Johan Hedbergf7520542011-01-20 12:34:39 +02002953
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002954int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2955{
2956 struct mgmt_ev_new_long_term_key ev;
2957
2958 memset(&ev, 0, sizeof(ev));
2959
2960 ev.store_hint = persistent;
2961 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2962 ev.key.addr.type = key->bdaddr_type;
2963 ev.key.authenticated = key->authenticated;
2964 ev.key.enc_size = key->enc_size;
2965 ev.key.ediv = key->ediv;
2966
2967 if (key->type == HCI_SMP_LTK)
2968 ev.key.master = 1;
2969
2970 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2971 memcpy(ev.key.val, key->val, sizeof(key->val));
2972
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002973 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2974 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002975}
2976
Johan Hedbergafc747a2012-01-15 18:11:07 +02002977int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002978 u8 addr_type, u32 flags, u8 *name, u8 name_len,
2979 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002980{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002981 char buf[512];
2982 struct mgmt_ev_device_connected *ev = (void *) buf;
2983 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002984
Johan Hedbergb644ba32012-01-17 21:48:47 +02002985 bacpy(&ev->addr.bdaddr, bdaddr);
2986 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002987
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002988 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002989
Johan Hedbergb644ba32012-01-17 21:48:47 +02002990 if (name_len > 0)
2991 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002992 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002993
2994 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08002995 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002996 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002997
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002998 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002999
3000 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003001 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003002}
3003
Johan Hedberg8962ee72011-01-20 12:40:27 +02003004static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3005{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003006 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003007 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003008 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003009
Johan Hedberg88c3df12012-02-09 14:27:38 +02003010 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3011 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003012
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003013 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003014 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003015
3016 *sk = cmd->sk;
3017 sock_hold(*sk);
3018
Johan Hedberga664b5b2011-02-19 12:06:02 -03003019 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003020}
3021
Johan Hedberg124f6e32012-02-09 13:50:12 +02003022static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003023{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003024 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003025 struct mgmt_cp_unpair_device *cp = cmd->param;
3026 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003027
3028 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003029 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3030 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003031
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003032 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3033
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003034 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003035
3036 mgmt_pending_remove(cmd);
3037}
3038
Johan Hedbergafc747a2012-01-15 18:11:07 +02003039int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003040 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003041{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003042 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003043 struct sock *sk = NULL;
3044 int err;
3045
Johan Hedberg744cf192011-11-08 20:40:14 +02003046 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003047
Johan Hedbergf7520542011-01-20 12:34:39 +02003048 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003049 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003050
Johan Hedbergafc747a2012-01-15 18:11:07 +02003051 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003052 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003053
3054 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003055 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003056
Johan Hedberg124f6e32012-02-09 13:50:12 +02003057 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003058 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003059
Johan Hedberg8962ee72011-01-20 12:40:27 +02003060 return err;
3061}
3062
Johan Hedberg88c3df12012-02-09 14:27:38 +02003063int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003064 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003065{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003066 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003067 struct pending_cmd *cmd;
3068 int err;
3069
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003070 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003071 if (!cmd)
3072 return -ENOENT;
3073
Johan Hedberg88c3df12012-02-09 14:27:38 +02003074 bacpy(&rp.addr.bdaddr, bdaddr);
3075 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003076
Johan Hedberg88c3df12012-02-09 14:27:38 +02003077 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003078 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003079
Johan Hedberga664b5b2011-02-19 12:06:02 -03003080 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003081
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003082 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3083 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003084 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003085}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003086
Johan Hedberg48264f02011-11-09 13:58:58 +02003087int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003088 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003089{
3090 struct mgmt_ev_connect_failed ev;
3091
Johan Hedberg4c659c32011-11-07 23:13:39 +02003092 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003093 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003094 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003095
Johan Hedberg744cf192011-11-08 20:40:14 +02003096 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003097}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003098
Johan Hedberg744cf192011-11-08 20:40:14 +02003099int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003100{
3101 struct mgmt_ev_pin_code_request ev;
3102
Johan Hedbergd8457692012-02-17 14:24:57 +02003103 bacpy(&ev.addr.bdaddr, bdaddr);
3104 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003105 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003106
Johan Hedberg744cf192011-11-08 20:40:14 +02003107 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003108 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003109}
3110
Johan Hedberg744cf192011-11-08 20:40:14 +02003111int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003112 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003113{
3114 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003115 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003116 int err;
3117
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003118 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003119 if (!cmd)
3120 return -ENOENT;
3121
Johan Hedbergd8457692012-02-17 14:24:57 +02003122 bacpy(&rp.addr.bdaddr, bdaddr);
3123 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003124
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003125 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003126 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003127
Johan Hedberga664b5b2011-02-19 12:06:02 -03003128 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003129
3130 return err;
3131}
3132
Johan Hedberg744cf192011-11-08 20:40:14 +02003133int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003134 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003135{
3136 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003137 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003138 int err;
3139
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003140 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003141 if (!cmd)
3142 return -ENOENT;
3143
Johan Hedbergd8457692012-02-17 14:24:57 +02003144 bacpy(&rp.addr.bdaddr, bdaddr);
3145 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003146
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003147 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003148 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003149
Johan Hedberga664b5b2011-02-19 12:06:02 -03003150 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003151
3152 return err;
3153}
Johan Hedberga5c29682011-02-19 12:05:57 -03003154
Johan Hedberg744cf192011-11-08 20:40:14 +02003155int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003156 u8 link_type, u8 addr_type, __le32 value,
3157 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003158{
3159 struct mgmt_ev_user_confirm_request ev;
3160
Johan Hedberg744cf192011-11-08 20:40:14 +02003161 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003162
Johan Hedberg272d90d2012-02-09 15:26:12 +02003163 bacpy(&ev.addr.bdaddr, bdaddr);
3164 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003165 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003166 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003167
Johan Hedberg744cf192011-11-08 20:40:14 +02003168 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003169 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003170}
3171
Johan Hedberg272d90d2012-02-09 15:26:12 +02003172int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3173 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003174{
3175 struct mgmt_ev_user_passkey_request ev;
3176
3177 BT_DBG("%s", hdev->name);
3178
Johan Hedberg272d90d2012-02-09 15:26:12 +02003179 bacpy(&ev.addr.bdaddr, bdaddr);
3180 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003181
3182 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003183 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003184}
3185
Brian Gix0df4c182011-11-16 13:53:13 -08003186static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003187 u8 link_type, u8 addr_type, u8 status,
3188 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003189{
3190 struct pending_cmd *cmd;
3191 struct mgmt_rp_user_confirm_reply rp;
3192 int err;
3193
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003194 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003195 if (!cmd)
3196 return -ENOENT;
3197
Johan Hedberg272d90d2012-02-09 15:26:12 +02003198 bacpy(&rp.addr.bdaddr, bdaddr);
3199 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003200 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003201 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003202
Johan Hedberga664b5b2011-02-19 12:06:02 -03003203 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003204
3205 return err;
3206}
3207
Johan Hedberg744cf192011-11-08 20:40:14 +02003208int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003209 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003210{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003211 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003212 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003213}
3214
Johan Hedberg272d90d2012-02-09 15:26:12 +02003215int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003216 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003217{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003218 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003219 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003220}
Johan Hedberg2a611692011-02-19 12:06:00 -03003221
Brian Gix604086b2011-11-23 08:28:33 -08003222int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003223 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003224{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003225 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003226 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003227}
3228
Johan Hedberg272d90d2012-02-09 15:26:12 +02003229int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003230 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003231{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003232 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003233 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003234}
3235
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003236int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003237 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003238{
3239 struct mgmt_ev_auth_failed ev;
3240
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003241 bacpy(&ev.addr.bdaddr, bdaddr);
3242 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003243 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003244
Johan Hedberg744cf192011-11-08 20:40:14 +02003245 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003246}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003247
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003248int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3249{
3250 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003251 bool changed = false;
3252 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003253
3254 if (status) {
3255 u8 mgmt_err = mgmt_status(status);
3256 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003257 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003258 return 0;
3259 }
3260
Johan Hedberg47990ea2012-02-22 11:58:37 +02003261 if (test_bit(HCI_AUTH, &hdev->flags)) {
3262 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3263 changed = true;
3264 } else {
3265 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3266 changed = true;
3267 }
3268
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003269 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003270 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003271
Johan Hedberg47990ea2012-02-22 11:58:37 +02003272 if (changed)
3273 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003274
3275 if (match.sk)
3276 sock_put(match.sk);
3277
3278 return err;
3279}
3280
Johan Hedbergcacaf522012-02-21 00:52:42 +02003281static int clear_eir(struct hci_dev *hdev)
3282{
3283 struct hci_cp_write_eir cp;
3284
3285 if (!(hdev->features[6] & LMP_EXT_INQ))
3286 return 0;
3287
Johan Hedbergc80da272012-02-22 15:38:48 +02003288 memset(hdev->eir, 0, sizeof(hdev->eir));
3289
Johan Hedbergcacaf522012-02-21 00:52:42 +02003290 memset(&cp, 0, sizeof(cp));
3291
3292 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3293}
3294
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003295int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003296{
3297 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003298 bool changed = false;
3299 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003300
3301 if (status) {
3302 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003303
3304 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003305 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003306 err = new_settings(hdev, NULL);
3307
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003308 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3309 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003310
3311 return err;
3312 }
3313
3314 if (enable) {
3315 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3316 changed = true;
3317 } else {
3318 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3319 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003320 }
3321
3322 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3323
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003324 if (changed)
3325 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003326
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003327 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003328 sock_put(match.sk);
3329
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003330 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3331 update_eir(hdev);
3332 else
3333 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003334
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003335 return err;
3336}
3337
Johan Hedberg90e70452012-02-23 23:09:40 +02003338static void class_rsp(struct pending_cmd *cmd, void *data)
3339{
3340 struct cmd_lookup *match = data;
3341
3342 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003343 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003344
3345 list_del(&cmd->list);
3346
3347 if (match->sk == NULL) {
3348 match->sk = cmd->sk;
3349 sock_hold(match->sk);
3350 }
3351
3352 mgmt_pending_free(cmd);
3353}
3354
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003355int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003356 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003357{
Johan Hedberg90e70452012-02-23 23:09:40 +02003358 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3359 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003360
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003361 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3362
Johan Hedberg90e70452012-02-23 23:09:40 +02003363 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3364 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3365 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3366
3367 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003368 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3369 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003370
3371 if (match.sk)
3372 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003373
3374 return err;
3375}
3376
Johan Hedberg744cf192011-11-08 20:40:14 +02003377int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003378{
3379 struct pending_cmd *cmd;
3380 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003381 bool changed = false;
3382 int err = 0;
3383
3384 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3385 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3386 changed = true;
3387 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003388
3389 memset(&ev, 0, sizeof(ev));
3390 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003391 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003392
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003393 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003394 if (!cmd)
3395 goto send_event;
3396
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003397 /* Always assume that either the short or the complete name has
3398 * changed if there was a pending mgmt command */
3399 changed = true;
3400
Johan Hedbergb312b1612011-03-16 14:29:37 +02003401 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003402 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003403 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003404 goto failed;
3405 }
3406
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003407 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003408 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003409 if (err < 0)
3410 goto failed;
3411
3412send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003413 if (changed)
3414 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003415 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003416
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003417 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003418
3419failed:
3420 if (cmd)
3421 mgmt_pending_remove(cmd);
3422 return err;
3423}
Szymon Jancc35938b2011-03-22 13:12:21 +01003424
Johan Hedberg744cf192011-11-08 20:40:14 +02003425int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003426 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003427{
3428 struct pending_cmd *cmd;
3429 int err;
3430
Johan Hedberg744cf192011-11-08 20:40:14 +02003431 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003432
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003433 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003434 if (!cmd)
3435 return -ENOENT;
3436
3437 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003438 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3439 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003440 } else {
3441 struct mgmt_rp_read_local_oob_data rp;
3442
3443 memcpy(rp.hash, hash, sizeof(rp.hash));
3444 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3445
Johan Hedberg744cf192011-11-08 20:40:14 +02003446 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003447 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3448 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003449 }
3450
3451 mgmt_pending_remove(cmd);
3452
3453 return err;
3454}
Johan Hedberge17acd42011-03-30 23:57:16 +03003455
Johan Hedberg06199cf2012-02-22 16:37:11 +02003456int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3457{
3458 struct cmd_lookup match = { NULL, hdev };
3459 bool changed = false;
3460 int err = 0;
3461
3462 if (status) {
3463 u8 mgmt_err = mgmt_status(status);
3464
3465 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003466 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003467 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003468
Szymon Jancd97dcb62012-03-16 16:02:56 +01003469 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3470 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003471
3472 return err;
3473 }
3474
3475 if (enable) {
3476 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3477 changed = true;
3478 } else {
3479 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3480 changed = true;
3481 }
3482
3483 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3484
3485 if (changed)
3486 err = new_settings(hdev, match.sk);
3487
3488 if (match.sk)
3489 sock_put(match.sk);
3490
3491 return err;
3492}
3493
Johan Hedberg48264f02011-11-09 13:58:58 +02003494int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003495 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3496 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003497{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003498 char buf[512];
3499 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003500 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003501
Johan Hedberg1dc06092012-01-15 21:01:23 +02003502 /* Leave 5 bytes for a potential CoD field */
3503 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003504 return -EINVAL;
3505
Johan Hedberg1dc06092012-01-15 21:01:23 +02003506 memset(buf, 0, sizeof(buf));
3507
Johan Hedberge319d2e2012-01-15 19:51:59 +02003508 bacpy(&ev->addr.bdaddr, bdaddr);
3509 ev->addr.type = link_to_mgmt(link_type, addr_type);
3510 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003511 if (cfm_name)
3512 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003513 if (!ssp)
3514 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003515
Johan Hedberg1dc06092012-01-15 21:01:23 +02003516 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003517 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003518
Johan Hedberg1dc06092012-01-15 21:01:23 +02003519 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3520 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003521 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003522
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003523 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003524
3525 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003526
Johan Hedberge319d2e2012-01-15 19:51:59 +02003527 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003528}
Johan Hedberga88a9652011-03-30 13:18:12 +03003529
Johan Hedbergb644ba32012-01-17 21:48:47 +02003530int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003531 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003532{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003533 struct mgmt_ev_device_found *ev;
3534 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3535 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003536
Johan Hedbergb644ba32012-01-17 21:48:47 +02003537 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003538
Johan Hedbergb644ba32012-01-17 21:48:47 +02003539 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003540
Johan Hedbergb644ba32012-01-17 21:48:47 +02003541 bacpy(&ev->addr.bdaddr, bdaddr);
3542 ev->addr.type = link_to_mgmt(link_type, addr_type);
3543 ev->rssi = rssi;
3544
3545 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003546 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003547
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003548 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003549
Johan Hedberg053c7e02012-02-04 00:06:00 +02003550 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003551 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003552}
Johan Hedberg314b2382011-04-27 10:29:57 -04003553
Andre Guedes7a135102011-11-09 17:14:25 -03003554int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003555{
3556 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003557 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003558 int err;
3559
Andre Guedes203159d2012-02-13 15:41:01 -03003560 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3561
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003562 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003563 if (!cmd)
3564 return -ENOENT;
3565
Johan Hedbergf808e162012-02-19 12:52:07 +02003566 type = hdev->discovery.type;
3567
3568 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003569 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003570 mgmt_pending_remove(cmd);
3571
3572 return err;
3573}
3574
Andre Guedese6d465c2011-11-09 17:14:26 -03003575int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3576{
3577 struct pending_cmd *cmd;
3578 int err;
3579
3580 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3581 if (!cmd)
3582 return -ENOENT;
3583
Johan Hedbergd9306502012-02-20 23:25:18 +02003584 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003585 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003586 mgmt_pending_remove(cmd);
3587
3588 return err;
3589}
Johan Hedberg314b2382011-04-27 10:29:57 -04003590
Johan Hedberg744cf192011-11-08 20:40:14 +02003591int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003592{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003593 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003594 struct pending_cmd *cmd;
3595
Andre Guedes343fb142011-11-22 17:14:19 -03003596 BT_DBG("%s discovering %u", hdev->name, discovering);
3597
Johan Hedberg164a6e72011-11-01 17:06:44 +02003598 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003599 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003600 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003601 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003602
3603 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003604 u8 type = hdev->discovery.type;
3605
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003606 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3607 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003608 mgmt_pending_remove(cmd);
3609 }
3610
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003611 memset(&ev, 0, sizeof(ev));
3612 ev.type = hdev->discovery.type;
3613 ev.discovering = discovering;
3614
3615 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003616}
Antti Julku5e762442011-08-25 16:48:02 +03003617
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003618int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003619{
3620 struct pending_cmd *cmd;
3621 struct mgmt_ev_device_blocked ev;
3622
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003623 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003624
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003625 bacpy(&ev.addr.bdaddr, bdaddr);
3626 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003627
Johan Hedberg744cf192011-11-08 20:40:14 +02003628 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003629 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003630}
3631
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003632int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003633{
3634 struct pending_cmd *cmd;
3635 struct mgmt_ev_device_unblocked ev;
3636
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003637 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003638
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003639 bacpy(&ev.addr.bdaddr, bdaddr);
3640 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003641
Johan Hedberg744cf192011-11-08 20:40:14 +02003642 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003643 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003644}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003645
3646module_param(enable_hs, bool, 0644);
3647MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3648
3649module_param(enable_le, bool, 0644);
3650MODULE_PARM_DESC(enable_le, "Enable Low Energy support");