blob: 5e80c6db6ae75d3a2bd1278bb3f168dc73f57740 [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
Marcel Holtmann053262d2012-03-27 18:49:02 +020041#define MGMT_REVISION 1
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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200232 kfree_skb(skb);
233
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300234 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200235}
236
Johan Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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
Andrei Emeltchenko3e9fb6d2012-03-20 10:32:25 +0200446 val = get_unaligned_le32(&uuid128[12]);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300447 if (val > 0xffff)
448 return 0;
449
450 return (u16) val;
451}
452
453static void create_eir(struct hci_dev *hdev, u8 *data)
454{
455 u8 *ptr = data;
456 u16 eir_len = 0;
457 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
458 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200459 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300460 size_t name_len;
461
462 name_len = strlen(hdev->dev_name);
463
464 if (name_len > 0) {
465 /* EIR Data type */
466 if (name_len > 48) {
467 name_len = 48;
468 ptr[1] = EIR_NAME_SHORT;
469 } else
470 ptr[1] = EIR_NAME_COMPLETE;
471
472 /* EIR Data length */
473 ptr[0] = name_len + 1;
474
475 memcpy(ptr + 2, hdev->dev_name, name_len);
476
477 eir_len += (name_len + 2);
478 ptr += (name_len + 2);
479 }
480
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700481 if (hdev->inq_tx_power) {
482 ptr[0] = 2;
483 ptr[1] = EIR_TX_POWER;
484 ptr[2] = (u8) hdev->inq_tx_power;
485
486 eir_len += 3;
487 ptr += 3;
488 }
489
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700490 if (hdev->devid_source > 0) {
491 ptr[0] = 9;
492 ptr[1] = EIR_DEVICE_ID;
493
494 put_unaligned_le16(hdev->devid_source, ptr + 2);
495 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
496 put_unaligned_le16(hdev->devid_product, ptr + 6);
497 put_unaligned_le16(hdev->devid_version, ptr + 8);
498
499 eir_len += 10;
500 ptr += 10;
501 }
502
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300503 memset(uuid16_list, 0, sizeof(uuid16_list));
504
505 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200506 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300507 u16 uuid16;
508
509 uuid16 = get_uuid16(uuid->uuid);
510 if (uuid16 == 0)
511 return;
512
513 if (uuid16 < 0x1100)
514 continue;
515
516 if (uuid16 == PNP_INFO_SVCLASS_ID)
517 continue;
518
519 /* Stop if not enough space to put next UUID */
520 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
521 truncated = 1;
522 break;
523 }
524
525 /* Check for duplicates */
526 for (i = 0; uuid16_list[i] != 0; i++)
527 if (uuid16_list[i] == uuid16)
528 break;
529
530 if (uuid16_list[i] == 0) {
531 uuid16_list[i] = uuid16;
532 eir_len += sizeof(u16);
533 }
534 }
535
536 if (uuid16_list[0] != 0) {
537 u8 *length = ptr;
538
539 /* EIR Data type */
540 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
541
542 ptr += 2;
543 eir_len += 2;
544
545 for (i = 0; uuid16_list[i] != 0; i++) {
546 *ptr++ = (uuid16_list[i] & 0x00ff);
547 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
548 }
549
550 /* EIR Data length */
551 *length = (i * sizeof(u16)) + 1;
552 }
553}
554
555static int update_eir(struct hci_dev *hdev)
556{
557 struct hci_cp_write_eir cp;
558
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200559 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200560 return 0;
561
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300562 if (!(hdev->features[6] & LMP_EXT_INQ))
563 return 0;
564
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200565 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300566 return 0;
567
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200568 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300569 return 0;
570
571 memset(&cp, 0, sizeof(cp));
572
573 create_eir(hdev, cp.data);
574
575 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
576 return 0;
577
578 memcpy(hdev->eir, cp.data, sizeof(cp.data));
579
580 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
581}
582
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200583static u8 get_service_classes(struct hci_dev *hdev)
584{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300585 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200586 u8 val = 0;
587
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300588 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200589 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200590
591 return val;
592}
593
594static int update_class(struct hci_dev *hdev)
595{
596 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200597 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200598
599 BT_DBG("%s", hdev->name);
600
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200601 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200602 return 0;
603
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200604 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200605 return 0;
606
607 cod[0] = hdev->minor_class;
608 cod[1] = hdev->major_class;
609 cod[2] = get_service_classes(hdev);
610
611 if (memcmp(cod, hdev->dev_class, 3) == 0)
612 return 0;
613
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200614 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
615 if (err == 0)
616 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
617
618 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200619}
620
Johan Hedberg7d785252011-12-15 00:47:39 +0200621static void service_cache_off(struct work_struct *work)
622{
623 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300624 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200625
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200626 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200627 return;
628
629 hci_dev_lock(hdev);
630
631 update_eir(hdev);
632 update_class(hdev);
633
634 hci_dev_unlock(hdev);
635}
636
Johan Hedberg6a919082012-02-28 06:17:26 +0200637static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200638{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200639 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200640 return;
641
Johan Hedberg4f87da82012-03-02 19:55:56 +0200642 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200643
Johan Hedberg4f87da82012-03-02 19:55:56 +0200644 /* Non-mgmt controlled devices get this bit set
645 * implicitly so that pairing works for them, however
646 * for mgmt we require user-space to explicitly enable
647 * it
648 */
649 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200650}
651
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200652static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300653 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200654{
655 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200656
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200657 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200658
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300659 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200660
Johan Hedberg03811012010-12-08 00:21:06 +0200661 memset(&rp, 0, sizeof(rp));
662
Johan Hedberg03811012010-12-08 00:21:06 +0200663 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200664
665 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200666 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200667
668 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
669 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
670
671 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200672
673 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200674 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200675
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300676 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200677
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200678 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300679 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200680}
681
682static void mgmt_pending_free(struct pending_cmd *cmd)
683{
684 sock_put(cmd->sk);
685 kfree(cmd->param);
686 kfree(cmd);
687}
688
689static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300690 struct hci_dev *hdev, void *data,
691 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200692{
693 struct pending_cmd *cmd;
694
695 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
696 if (!cmd)
697 return NULL;
698
699 cmd->opcode = opcode;
700 cmd->index = hdev->id;
701
702 cmd->param = kmalloc(len, GFP_ATOMIC);
703 if (!cmd->param) {
704 kfree(cmd);
705 return NULL;
706 }
707
708 if (data)
709 memcpy(cmd->param, data, len);
710
711 cmd->sk = sk;
712 sock_hold(sk);
713
714 list_add(&cmd->list, &hdev->mgmt_pending);
715
716 return cmd;
717}
718
719static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300720 void (*cb)(struct pending_cmd *cmd, void *data),
721 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200722{
723 struct list_head *p, *n;
724
725 list_for_each_safe(p, n, &hdev->mgmt_pending) {
726 struct pending_cmd *cmd;
727
728 cmd = list_entry(p, struct pending_cmd, list);
729
730 if (opcode > 0 && cmd->opcode != opcode)
731 continue;
732
733 cb(cmd, data);
734 }
735}
736
737static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
738{
739 struct pending_cmd *cmd;
740
741 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
742 if (cmd->opcode == opcode)
743 return cmd;
744 }
745
746 return NULL;
747}
748
749static void mgmt_pending_remove(struct pending_cmd *cmd)
750{
751 list_del(&cmd->list);
752 mgmt_pending_free(cmd);
753}
754
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200755static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200756{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200757 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200758
Johan Hedbergaee9b212012-02-18 15:07:59 +0200759 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300760 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200761}
762
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200763static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300764 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200765{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300766 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200767 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200768 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200769
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200770 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200771
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300772 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200773
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100774 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
775 cancel_delayed_work(&hdev->power_off);
776
777 if (cp->val) {
778 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
779 mgmt_powered(hdev, 1);
780 goto failed;
781 }
782 }
783
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200784 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200785 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200786 goto failed;
787 }
788
789 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200790 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300791 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200792 goto failed;
793 }
794
795 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
796 if (!cmd) {
797 err = -ENOMEM;
798 goto failed;
799 }
800
801 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200802 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200803 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200804 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200805
806 err = 0;
807
808failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300809 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200810 return err;
811}
812
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300813static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
814 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200815{
816 struct sk_buff *skb;
817 struct mgmt_hdr *hdr;
818
819 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
820 if (!skb)
821 return -ENOMEM;
822
823 hdr = (void *) skb_put(skb, sizeof(*hdr));
824 hdr->opcode = cpu_to_le16(event);
825 if (hdev)
826 hdr->index = cpu_to_le16(hdev->id);
827 else
828 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
829 hdr->len = cpu_to_le16(data_len);
830
831 if (data)
832 memcpy(skb_put(skb, data_len), data, data_len);
833
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100834 /* Time stamp */
835 __net_timestamp(skb);
836
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200837 hci_send_to_control(skb, skip_sk);
838 kfree_skb(skb);
839
840 return 0;
841}
842
843static int new_settings(struct hci_dev *hdev, struct sock *skip)
844{
845 __le32 ev;
846
847 ev = cpu_to_le32(get_current_settings(hdev));
848
849 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
850}
851
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200852static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300853 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200854{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300855 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200856 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200857 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200858 u8 scan;
859 int err;
860
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200861 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200862
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700863 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100864 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200865 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300866 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200867
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300868 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200869
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200870 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200871 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300872 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200873 goto failed;
874 }
875
876 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
877 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200878 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300879 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200880 goto failed;
881 }
882
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200883 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200884 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300885 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200886 goto failed;
887 }
888
889 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200890 bool changed = false;
891
892 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
893 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
894 changed = true;
895 }
896
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200897 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200898 if (err < 0)
899 goto failed;
900
901 if (changed)
902 err = new_settings(hdev, sk);
903
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200904 goto failed;
905 }
906
907 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100908 if (hdev->discov_timeout > 0) {
909 cancel_delayed_work(&hdev->discov_off);
910 hdev->discov_timeout = 0;
911 }
912
913 if (cp->val && timeout > 0) {
914 hdev->discov_timeout = timeout;
915 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
916 msecs_to_jiffies(hdev->discov_timeout * 1000));
917 }
918
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200919 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200920 goto failed;
921 }
922
923 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
924 if (!cmd) {
925 err = -ENOMEM;
926 goto failed;
927 }
928
929 scan = SCAN_PAGE;
930
931 if (cp->val)
932 scan |= SCAN_INQUIRY;
933 else
934 cancel_delayed_work(&hdev->discov_off);
935
936 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
937 if (err < 0)
938 mgmt_pending_remove(cmd);
939
Johan Hedberg03811012010-12-08 00:21:06 +0200940 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200941 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200942
943failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300944 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200945 return err;
946}
947
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200948static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300949 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200950{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300951 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200952 struct pending_cmd *cmd;
953 u8 scan;
954 int err;
955
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200956 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200957
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300958 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200959
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200960 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200961 bool changed = false;
962
963 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
964 changed = true;
965
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200966 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200967 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200968 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200969 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
970 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
971 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200972
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200973 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200974 if (err < 0)
975 goto failed;
976
977 if (changed)
978 err = new_settings(hdev, sk);
979
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200980 goto failed;
981 }
982
983 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
984 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200985 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300986 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200987 goto failed;
988 }
989
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200990 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200991 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200992 goto failed;
993 }
994
995 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
996 if (!cmd) {
997 err = -ENOMEM;
998 goto failed;
999 }
1000
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001001 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001002 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001003 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001004 scan = 0;
1005
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001006 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1007 hdev->discov_timeout > 0)
1008 cancel_delayed_work(&hdev->discov_off);
1009 }
1010
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001011 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1012 if (err < 0)
1013 mgmt_pending_remove(cmd);
1014
1015failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001016 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001017 return err;
1018}
1019
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001020static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001021 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001022{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001023 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001024 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001025
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001026 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001027
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001028 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001029
1030 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001031 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001033 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001035 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036 if (err < 0)
1037 goto failed;
1038
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001039 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
1041failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001042 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001043 return err;
1044}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001045
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001046static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1047 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001048{
1049 struct mgmt_mode *cp = data;
1050 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001051 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001052 int err;
1053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001054 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001055
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001056 hci_dev_lock(hdev);
1057
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001058 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001059 bool changed = false;
1060
1061 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1062 &hdev->dev_flags)) {
1063 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1064 changed = true;
1065 }
1066
1067 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1068 if (err < 0)
1069 goto failed;
1070
1071 if (changed)
1072 err = new_settings(hdev, sk);
1073
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001074 goto failed;
1075 }
1076
1077 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001078 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001079 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001080 goto failed;
1081 }
1082
1083 val = !!cp->val;
1084
1085 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1086 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1087 goto failed;
1088 }
1089
1090 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1091 if (!cmd) {
1092 err = -ENOMEM;
1093 goto failed;
1094 }
1095
1096 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1097 if (err < 0) {
1098 mgmt_pending_remove(cmd);
1099 goto failed;
1100 }
1101
1102failed:
1103 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001104 return err;
1105}
1106
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001107static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001108{
1109 struct mgmt_mode *cp = data;
1110 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001111 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001112 int err;
1113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001114 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001115
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001116 hci_dev_lock(hdev);
1117
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001118 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001119 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001120 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001121 goto failed;
1122 }
1123
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001124 val = !!cp->val;
1125
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001126 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001127 bool changed = false;
1128
1129 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1130 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1131 changed = true;
1132 }
1133
1134 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1135 if (err < 0)
1136 goto failed;
1137
1138 if (changed)
1139 err = new_settings(hdev, sk);
1140
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001141 goto failed;
1142 }
1143
1144 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001145 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1146 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001147 goto failed;
1148 }
1149
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001150 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1151 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1152 goto failed;
1153 }
1154
1155 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1156 if (!cmd) {
1157 err = -ENOMEM;
1158 goto failed;
1159 }
1160
1161 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1162 if (err < 0) {
1163 mgmt_pending_remove(cmd);
1164 goto failed;
1165 }
1166
1167failed:
1168 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001169 return err;
1170}
1171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001172static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001173{
1174 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001175
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001176 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178 if (!enable_hs)
1179 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001180 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001181
1182 if (cp->val)
1183 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1184 else
1185 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001187 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001188}
1189
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001190static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001191{
1192 struct mgmt_mode *cp = data;
1193 struct hci_cp_write_le_host_supported hci_cp;
1194 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001195 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001196 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001198 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001199
Johan Hedberg1de028c2012-02-29 19:55:35 -08001200 hci_dev_lock(hdev);
1201
Johan Hedberg06199cf2012-02-22 16:37:11 +02001202 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001203 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001204 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001205 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001206 }
1207
1208 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001209 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001210
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001211 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001212 bool changed = false;
1213
1214 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1215 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1216 changed = true;
1217 }
1218
1219 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1220 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001221 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001222
1223 if (changed)
1224 err = new_settings(hdev, sk);
1225
Johan Hedberg1de028c2012-02-29 19:55:35 -08001226 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001227 }
1228
1229 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001230 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001231 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001232 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001233 }
1234
1235 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1236 if (!cmd) {
1237 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001238 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001239 }
1240
1241 memset(&hci_cp, 0, sizeof(hci_cp));
1242
1243 if (val) {
1244 hci_cp.le = val;
1245 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1246 }
1247
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001248 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1249 &hci_cp);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001250 if (err < 0) {
1251 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001252 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001253 }
1254
Johan Hedberg1de028c2012-02-29 19:55:35 -08001255unlock:
1256 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001257 return err;
1258}
1259
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001260static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001261{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001262 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001263 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001264 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001265 int err;
1266
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001267 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001268
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001269 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001270
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001271 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001272 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001273 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001274 goto failed;
1275 }
1276
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001277 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1278 if (!uuid) {
1279 err = -ENOMEM;
1280 goto failed;
1281 }
1282
1283 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001284 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001285
1286 list_add(&uuid->list, &hdev->uuids);
1287
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001288 err = update_class(hdev);
1289 if (err < 0)
1290 goto failed;
1291
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001292 err = update_eir(hdev);
1293 if (err < 0)
1294 goto failed;
1295
Johan Hedberg90e70452012-02-23 23:09:40 +02001296 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001297 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001298 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001299 goto failed;
1300 }
1301
1302 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1303 if (!cmd) {
1304 err = -ENOMEM;
1305 goto failed;
1306 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001307
1308failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001309 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001310 return err;
1311}
1312
Johan Hedberg24b78d02012-02-23 23:24:30 +02001313static bool enable_service_cache(struct hci_dev *hdev)
1314{
1315 if (!hdev_is_powered(hdev))
1316 return false;
1317
1318 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001319 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001320 return true;
1321 }
1322
1323 return false;
1324}
1325
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001326static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1327 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001328{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001329 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001330 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001331 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001332 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 +02001333 int err, found;
1334
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001335 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001336
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001337 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001339 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001340 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001341 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001342 goto unlock;
1343 }
1344
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001345 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1346 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001347
Johan Hedberg24b78d02012-02-23 23:24:30 +02001348 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001349 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001350 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001351 goto unlock;
1352 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001353
Johan Hedberg9246a862012-02-23 21:33:16 +02001354 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001355 }
1356
1357 found = 0;
1358
1359 list_for_each_safe(p, n, &hdev->uuids) {
1360 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1361
1362 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1363 continue;
1364
1365 list_del(&match->list);
1366 found++;
1367 }
1368
1369 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001370 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001371 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001372 goto unlock;
1373 }
1374
Johan Hedberg9246a862012-02-23 21:33:16 +02001375update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001376 err = update_class(hdev);
1377 if (err < 0)
1378 goto unlock;
1379
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001380 err = update_eir(hdev);
1381 if (err < 0)
1382 goto unlock;
1383
Johan Hedberg90e70452012-02-23 23:09:40 +02001384 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001385 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001386 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001387 goto unlock;
1388 }
1389
1390 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1391 if (!cmd) {
1392 err = -ENOMEM;
1393 goto unlock;
1394 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001395
1396unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001397 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001398 return err;
1399}
1400
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001401static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001402 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001403{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001404 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001405 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001406 int err;
1407
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001408 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001409
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001410 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001411
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001412 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001413 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001414 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001415 goto unlock;
1416 }
1417
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001418 hdev->major_class = cp->major;
1419 hdev->minor_class = cp->minor;
1420
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001421 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001422 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001423 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001424 goto unlock;
1425 }
1426
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001427 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001428 hci_dev_unlock(hdev);
1429 cancel_delayed_work_sync(&hdev->service_cache);
1430 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001431 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001432 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001433
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001434 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001435 if (err < 0)
1436 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001437
Johan Hedberg90e70452012-02-23 23:09:40 +02001438 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001439 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001440 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001441 goto unlock;
1442 }
1443
1444 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1445 if (!cmd) {
1446 err = -ENOMEM;
1447 goto unlock;
1448 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001449
Johan Hedbergb5235a62012-02-21 14:32:24 +02001450unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001451 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001452 return err;
1453}
1454
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001455static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1456 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001457{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001458 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001459 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001460 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001461
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001462 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001463
Johan Hedberg86742e12011-11-07 23:13:38 +02001464 expected_len = sizeof(*cp) + key_count *
1465 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001466 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001467 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001468 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001469 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001470 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001471 }
1472
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001473 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001474 key_count);
1475
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001476 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001477
1478 hci_link_keys_clear(hdev);
1479
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001480 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001481
1482 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001483 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001484 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001485 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001486
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001487 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001488 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001489
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001490 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001491 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001492 }
1493
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001494 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001495
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001496 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001497
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001498 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001499}
1500
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001501static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001502 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001503{
1504 struct mgmt_ev_device_unpaired ev;
1505
1506 bacpy(&ev.addr.bdaddr, bdaddr);
1507 ev.addr.type = addr_type;
1508
1509 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001510 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001511}
1512
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001513static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001514 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001515{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001516 struct mgmt_cp_unpair_device *cp = data;
1517 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001518 struct hci_cp_disconnect dc;
1519 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001520 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001521 int err;
1522
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001523 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001524
Johan Hedberga8a1d192011-11-10 15:54:38 +02001525 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001526 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1527 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001528
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001529 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001530 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001531 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001532 goto unlock;
1533 }
1534
Johan Hedberg124f6e32012-02-09 13:50:12 +02001535 if (cp->addr.type == MGMT_ADDR_BREDR)
1536 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1537 else
1538 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001539
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001540 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001541 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001542 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001543 goto unlock;
1544 }
1545
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001546 if (cp->disconnect) {
1547 if (cp->addr.type == MGMT_ADDR_BREDR)
1548 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1549 &cp->addr.bdaddr);
1550 else
1551 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1552 &cp->addr.bdaddr);
1553 } else {
1554 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001555 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001556
Johan Hedberga8a1d192011-11-10 15:54:38 +02001557 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001558 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001559 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001560 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001561 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001562 }
1563
Johan Hedberg124f6e32012-02-09 13:50:12 +02001564 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001565 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001566 if (!cmd) {
1567 err = -ENOMEM;
1568 goto unlock;
1569 }
1570
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001571 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001572 dc.reason = 0x13; /* Remote User Terminated Connection */
1573 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1574 if (err < 0)
1575 mgmt_pending_remove(cmd);
1576
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001577unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001578 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001579 return err;
1580}
1581
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001582static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001583 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001584{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001585 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001586 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001587 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001588 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001589 int err;
1590
1591 BT_DBG("");
1592
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001593 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001594
1595 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001596 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001597 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001598 goto failed;
1599 }
1600
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001601 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001602 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001603 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001604 goto failed;
1605 }
1606
Johan Hedberg88c3df12012-02-09 14:27:38 +02001607 if (cp->addr.type == MGMT_ADDR_BREDR)
1608 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1609 else
1610 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001611
Johan Hedberg8962ee72011-01-20 12:40:27 +02001612 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001613 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001614 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001615 goto failed;
1616 }
1617
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001618 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001619 if (!cmd) {
1620 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001621 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001622 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001623
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001624 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001625 dc.reason = 0x13; /* Remote User Terminated Connection */
1626
1627 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1628 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001629 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001630
1631failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001632 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001633 return err;
1634}
1635
Johan Hedberg48264f02011-11-09 13:58:58 +02001636static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001637{
1638 switch (link_type) {
1639 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001640 switch (addr_type) {
1641 case ADDR_LE_DEV_PUBLIC:
1642 return MGMT_ADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001643
Johan Hedberg48264f02011-11-09 13:58:58 +02001644 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001645 /* Fallback to LE Random address type */
1646 return MGMT_ADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001647 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001648
Johan Hedberg4c659c32011-11-07 23:13:39 +02001649 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001650 /* Fallback to BR/EDR type */
1651 return MGMT_ADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001652 }
1653}
1654
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001655static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1656 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001657{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001658 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001659 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001660 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001661 int err;
1662 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001663
1664 BT_DBG("");
1665
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001666 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001667
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001668 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001669 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001670 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001671 goto unlock;
1672 }
1673
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001674 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001675 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1676 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001677 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001678 }
1679
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001680 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001681 rp = kmalloc(rp_len, GFP_ATOMIC);
1682 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001683 err = -ENOMEM;
1684 goto unlock;
1685 }
1686
Johan Hedberg2784eb42011-01-21 13:56:35 +02001687 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001688 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001689 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1690 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001691 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001692 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001693 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001694 continue;
1695 i++;
1696 }
1697
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001698 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001699
Johan Hedberg4c659c32011-11-07 23:13:39 +02001700 /* Recalculate length in case of filtered SCO connections, etc */
1701 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001702
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001703 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001704 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001705
Johan Hedberga38528f2011-01-22 06:46:43 +02001706 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001707
1708unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001709 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001710 return err;
1711}
1712
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001713static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001714 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001715{
1716 struct pending_cmd *cmd;
1717 int err;
1718
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001719 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001720 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001721 if (!cmd)
1722 return -ENOMEM;
1723
Johan Hedbergd8457692012-02-17 14:24:57 +02001724 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001725 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001726 if (err < 0)
1727 mgmt_pending_remove(cmd);
1728
1729 return err;
1730}
1731
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001732static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001733 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001734{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001735 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001736 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001737 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001738 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001739 int err;
1740
1741 BT_DBG("");
1742
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001743 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001744
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001745 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001746 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001747 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001748 goto failed;
1749 }
1750
Johan Hedbergd8457692012-02-17 14:24:57 +02001751 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001752 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001753 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001754 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001755 goto failed;
1756 }
1757
1758 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001759 struct mgmt_cp_pin_code_neg_reply ncp;
1760
1761 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001762
1763 BT_ERR("PIN code is not 16 bytes long");
1764
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001765 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001766 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001767 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001768 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001769
1770 goto failed;
1771 }
1772
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001773 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001774 if (!cmd) {
1775 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001776 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001777 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001778
Johan Hedbergd8457692012-02-17 14:24:57 +02001779 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001780 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001781 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001782
1783 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1784 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001785 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001786
1787failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001788 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001789 return err;
1790}
1791
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001792static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001793 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001794{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001795 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001796 int err;
1797
1798 BT_DBG("");
1799
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001800 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001801
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001802 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001803 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001804 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001805 goto failed;
1806 }
1807
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001808 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001809
1810failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001811 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001812 return err;
1813}
1814
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001815static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1816 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001817{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001818 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001819
1820 BT_DBG("");
1821
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001822 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001823
1824 hdev->io_capability = cp->io_capability;
1825
1826 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001827 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001828
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001829 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001830
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001831 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1832 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001833}
1834
Johan Hedberge9a416b2011-02-19 12:05:56 -03001835static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1836{
1837 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001838 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001839
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001840 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001841 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1842 continue;
1843
Johan Hedberge9a416b2011-02-19 12:05:56 -03001844 if (cmd->user_data != conn)
1845 continue;
1846
1847 return cmd;
1848 }
1849
1850 return NULL;
1851}
1852
1853static void pairing_complete(struct pending_cmd *cmd, u8 status)
1854{
1855 struct mgmt_rp_pair_device rp;
1856 struct hci_conn *conn = cmd->user_data;
1857
Johan Hedbergba4e5642011-11-11 00:07:34 +02001858 bacpy(&rp.addr.bdaddr, &conn->dst);
1859 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001860
Johan Hedbergaee9b212012-02-18 15:07:59 +02001861 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001862 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001863
1864 /* So we don't get further callbacks for this connection */
1865 conn->connect_cfm_cb = NULL;
1866 conn->security_cfm_cb = NULL;
1867 conn->disconn_cfm_cb = NULL;
1868
1869 hci_conn_put(conn);
1870
Johan Hedberga664b5b2011-02-19 12:06:02 -03001871 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001872}
1873
1874static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1875{
1876 struct pending_cmd *cmd;
1877
1878 BT_DBG("status %u", status);
1879
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001880 cmd = find_pairing(conn);
1881 if (!cmd)
1882 BT_DBG("Unable to find a pending command");
1883 else
Johan Hedberge2113262012-02-18 15:20:03 +02001884 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001885}
1886
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001887static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001888 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001889{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001890 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001891 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001892 struct pending_cmd *cmd;
1893 u8 sec_level, auth_type;
1894 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001895 int err;
1896
1897 BT_DBG("");
1898
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001899 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001900
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001901 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001902 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001903 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001904 goto unlock;
1905 }
1906
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001907 sec_level = BT_SECURITY_MEDIUM;
1908 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001909 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001910 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001911 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001912
Johan Hedbergba4e5642011-11-11 00:07:34 +02001913 if (cp->addr.type == MGMT_ADDR_BREDR)
1914 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001915 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001916 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001917 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001918 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001919
Johan Hedberg1425acb2011-11-11 00:07:35 +02001920 memset(&rp, 0, sizeof(rp));
1921 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1922 rp.addr.type = cp->addr.type;
1923
Ville Tervo30e76272011-02-22 16:10:53 -03001924 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001925 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001926 MGMT_STATUS_CONNECT_FAILED, &rp,
1927 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001928 goto unlock;
1929 }
1930
1931 if (conn->connect_cfm_cb) {
1932 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001933 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001934 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001935 goto unlock;
1936 }
1937
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001938 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001939 if (!cmd) {
1940 err = -ENOMEM;
1941 hci_conn_put(conn);
1942 goto unlock;
1943 }
1944
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001945 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001946 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001947 conn->connect_cfm_cb = pairing_complete_cb;
1948
Johan Hedberge9a416b2011-02-19 12:05:56 -03001949 conn->security_cfm_cb = pairing_complete_cb;
1950 conn->disconn_cfm_cb = pairing_complete_cb;
1951 conn->io_capability = cp->io_cap;
1952 cmd->user_data = conn;
1953
1954 if (conn->state == BT_CONNECTED &&
1955 hci_conn_security(conn, sec_level, auth_type))
1956 pairing_complete(cmd, 0);
1957
1958 err = 0;
1959
1960unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001961 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001962 return err;
1963}
1964
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001965static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1966 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001967{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001968 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001969 struct pending_cmd *cmd;
1970 struct hci_conn *conn;
1971 int err;
1972
1973 BT_DBG("");
1974
Johan Hedberg28424702012-02-02 04:02:29 +02001975 hci_dev_lock(hdev);
1976
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001977 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001978 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001979 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001980 goto unlock;
1981 }
1982
Johan Hedberg28424702012-02-02 04:02:29 +02001983 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1984 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001985 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001986 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001987 goto unlock;
1988 }
1989
1990 conn = cmd->user_data;
1991
1992 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001993 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001994 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001995 goto unlock;
1996 }
1997
1998 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1999
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002000 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002001 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002002unlock:
2003 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002004 return err;
2005}
2006
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002007static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002008 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2009 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002010{
Johan Hedberga5c29682011-02-19 12:05:57 -03002011 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002012 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002013 int err;
2014
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002015 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002016
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002017 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002018 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002019 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002020 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002021 }
2022
Johan Hedberg272d90d2012-02-09 15:26:12 +02002023 if (type == MGMT_ADDR_BREDR)
2024 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2025 else
Brian Gix47c15e22011-11-16 13:53:14 -08002026 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002027
Johan Hedberg272d90d2012-02-09 15:26:12 +02002028 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002029 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002030 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002031 goto done;
2032 }
2033
2034 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002035 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002036 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002037
Brian Gix5fe57d92011-12-21 16:12:13 -08002038 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002039 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002040 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002041 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002042 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002043 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002044
Brian Gix47c15e22011-11-16 13:53:14 -08002045 goto done;
2046 }
2047
Brian Gix0df4c182011-11-16 13:53:13 -08002048 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002049 if (!cmd) {
2050 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002051 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002052 }
2053
Brian Gix0df4c182011-11-16 13:53:13 -08002054 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002055 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2056 struct hci_cp_user_passkey_reply cp;
2057
2058 bacpy(&cp.bdaddr, bdaddr);
2059 cp.passkey = passkey;
2060 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2061 } else
2062 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2063
Johan Hedberga664b5b2011-02-19 12:06:02 -03002064 if (err < 0)
2065 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002066
Brian Gix0df4c182011-11-16 13:53:13 -08002067done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002068 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002069 return err;
2070}
2071
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002072static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2073 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002074{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002075 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002076
2077 BT_DBG("");
2078
2079 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002080 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002081 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002082
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002083 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002084 MGMT_OP_USER_CONFIRM_REPLY,
2085 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002086}
2087
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002088static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002089 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002090{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002091 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002092
2093 BT_DBG("");
2094
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002095 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002096 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2097 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002098}
2099
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002100static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2101 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002102{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002103 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002104
2105 BT_DBG("");
2106
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002107 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002108 MGMT_OP_USER_PASSKEY_REPLY,
2109 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002110}
2111
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002112static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002113 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002114{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002115 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002116
2117 BT_DBG("");
2118
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002119 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002120 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2121 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002122}
2123
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002124static int update_name(struct hci_dev *hdev, const char *name)
2125{
2126 struct hci_cp_write_local_name cp;
2127
2128 memcpy(cp.name, name, sizeof(cp.name));
2129
2130 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2131}
2132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002133static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002134 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002135{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002136 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002137 struct pending_cmd *cmd;
2138 int err;
2139
2140 BT_DBG("");
2141
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002142 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002143
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002144 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002145
Johan Hedbergb5235a62012-02-21 14:32:24 +02002146 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002147 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002148
2149 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002150 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002151 if (err < 0)
2152 goto failed;
2153
2154 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002155 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002156
Johan Hedbergb5235a62012-02-21 14:32:24 +02002157 goto failed;
2158 }
2159
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002160 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002161 if (!cmd) {
2162 err = -ENOMEM;
2163 goto failed;
2164 }
2165
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002166 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002167 if (err < 0)
2168 mgmt_pending_remove(cmd);
2169
2170failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002171 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002172 return err;
2173}
2174
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002175static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002176 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002177{
Szymon Jancc35938b2011-03-22 13:12:21 +01002178 struct pending_cmd *cmd;
2179 int err;
2180
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002181 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002182
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002183 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002184
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002185 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002186 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002187 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002188 goto unlock;
2189 }
2190
2191 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002192 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002193 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002194 goto unlock;
2195 }
2196
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002197 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002198 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002199 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002200 goto unlock;
2201 }
2202
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002203 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002204 if (!cmd) {
2205 err = -ENOMEM;
2206 goto unlock;
2207 }
2208
2209 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2210 if (err < 0)
2211 mgmt_pending_remove(cmd);
2212
2213unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002214 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002215 return err;
2216}
2217
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002218static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002219 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002220{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002221 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002222 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002223 int err;
2224
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002225 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002226
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002227 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002228
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002229 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002230 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002231 MGMT_STATUS_NOT_POWERED, &cp->addr,
2232 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002233 goto unlock;
2234 }
2235
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002236 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002237 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002238 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002239 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002240 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002241 status = 0;
2242
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002243 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002244 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002245
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002246unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002247 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002248 return err;
2249}
2250
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002251static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002252 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002253{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002254 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002255 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002256 int err;
2257
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002258 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002259
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002260 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002261
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002262 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002263 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002264 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2265 MGMT_STATUS_NOT_POWERED, &cp->addr,
2266 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002267 goto unlock;
2268 }
2269
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002270 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002271 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002272 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002273 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002274 status = 0;
2275
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002276 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002277 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002278
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002279unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002280 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002281 return err;
2282}
2283
Andre Guedes5e0452c2012-02-17 20:39:38 -03002284int mgmt_interleaved_discovery(struct hci_dev *hdev)
2285{
2286 int err;
2287
2288 BT_DBG("%s", hdev->name);
2289
2290 hci_dev_lock(hdev);
2291
2292 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2293 if (err < 0)
2294 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2295
2296 hci_dev_unlock(hdev);
2297
2298 return err;
2299}
2300
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002301static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002302 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002303{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002304 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002305 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002306 int err;
2307
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002308 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002309
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002310 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002311
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002312 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002313 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002314 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002315 goto failed;
2316 }
2317
Andre Guedes642be6c2012-03-21 00:03:37 -03002318 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2319 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2320 MGMT_STATUS_BUSY);
2321 goto failed;
2322 }
2323
Johan Hedbergff9ef572012-01-04 14:23:45 +02002324 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002325 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002326 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002327 goto failed;
2328 }
2329
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002330 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002331 if (!cmd) {
2332 err = -ENOMEM;
2333 goto failed;
2334 }
2335
Andre Guedes4aab14e2012-02-17 20:39:36 -03002336 hdev->discovery.type = cp->type;
2337
2338 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002339 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002340 if (lmp_bredr_capable(hdev))
2341 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2342 else
2343 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002344 break;
2345
2346 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002347 if (lmp_host_le_capable(hdev))
2348 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002349 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002350 else
2351 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002352 break;
2353
Andre Guedes5e0452c2012-02-17 20:39:38 -03002354 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002355 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2356 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002357 LE_SCAN_WIN,
2358 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002359 else
2360 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002361 break;
2362
Andre Guedesf39799f2012-02-17 20:39:35 -03002363 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002364 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002365 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002366
Johan Hedberg14a53662011-04-27 10:29:56 -04002367 if (err < 0)
2368 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002369 else
2370 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002371
2372failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002373 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002374 return err;
2375}
2376
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002377static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002378 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002379{
Johan Hedbergd9306502012-02-20 23:25:18 +02002380 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002381 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002382 struct hci_cp_remote_name_req_cancel cp;
2383 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002384 int err;
2385
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002386 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002387
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002388 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002389
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002390 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002391 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002392 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2393 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002394 goto unlock;
2395 }
2396
2397 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002398 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002399 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2400 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002401 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002402 }
2403
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002404 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002405 if (!cmd) {
2406 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002407 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002408 }
2409
Andre Guedese0d9727e2012-03-20 15:15:36 -03002410 switch (hdev->discovery.state) {
2411 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002412 if (test_bit(HCI_INQUIRY, &hdev->flags))
2413 err = hci_cancel_inquiry(hdev);
2414 else
2415 err = hci_cancel_le_scan(hdev);
2416
Andre Guedese0d9727e2012-03-20 15:15:36 -03002417 break;
2418
2419 case DISCOVERY_RESOLVING:
2420 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
2421 NAME_PENDING);
2422 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002423 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002424 err = cmd_complete(sk, hdev->id,
2425 MGMT_OP_STOP_DISCOVERY, 0,
2426 &mgmt_cp->type,
2427 sizeof(mgmt_cp->type));
2428 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2429 goto unlock;
2430 }
2431
2432 bacpy(&cp.bdaddr, &e->data.bdaddr);
2433 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2434 sizeof(cp), &cp);
2435
2436 break;
2437
2438 default:
2439 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2440 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002441 }
2442
Johan Hedberg14a53662011-04-27 10:29:56 -04002443 if (err < 0)
2444 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002445 else
2446 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002447
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002448unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002449 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002450 return err;
2451}
2452
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002453static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002454 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002455{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002456 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002457 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002458 int err;
2459
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002460 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002461
Johan Hedberg561aafb2012-01-04 13:31:59 +02002462 hci_dev_lock(hdev);
2463
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002464 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002465 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002466 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002467 goto failed;
2468 }
2469
Johan Hedberga198e7b2012-02-17 14:27:06 +02002470 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002471 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002472 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002473 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002474 goto failed;
2475 }
2476
2477 if (cp->name_known) {
2478 e->name_state = NAME_KNOWN;
2479 list_del(&e->list);
2480 } else {
2481 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002482 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002483 }
2484
2485 err = 0;
2486
2487failed:
2488 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002489 return err;
2490}
2491
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002492static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002493 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002494{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002495 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002496 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002497 int err;
2498
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002499 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002500
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002501 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002502
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002503 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002504 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002505 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002506 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002507 status = 0;
2508
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002509 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002510 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002511
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002512 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002513
2514 return err;
2515}
2516
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002517static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002518 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002519{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002520 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002521 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002522 int err;
2523
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002524 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002525
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002526 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002527
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002528 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002529 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002530 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002531 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002532 status = 0;
2533
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002534 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002535 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002536
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002537 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002538
2539 return err;
2540}
2541
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002542static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2543 u16 len)
2544{
2545 struct mgmt_cp_set_device_id *cp = data;
2546 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002547 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002548
2549 BT_DBG("%s", hdev->name);
2550
Szymon Jancc72d4b82012-03-16 16:02:57 +01002551 source = __le16_to_cpu(cp->source);
2552
2553 if (source > 0x0002)
2554 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2555 MGMT_STATUS_INVALID_PARAMS);
2556
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002557 hci_dev_lock(hdev);
2558
Szymon Jancc72d4b82012-03-16 16:02:57 +01002559 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002560 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2561 hdev->devid_product = __le16_to_cpu(cp->product);
2562 hdev->devid_version = __le16_to_cpu(cp->version);
2563
2564 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2565
2566 update_eir(hdev);
2567
2568 hci_dev_unlock(hdev);
2569
2570 return err;
2571}
2572
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002573static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002574 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002575{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002576 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002577 struct hci_cp_write_page_scan_activity acp;
2578 u8 type;
2579 int err;
2580
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002581 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002582
Johan Hedberg5400c042012-02-21 16:40:33 +02002583 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002584 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002585 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002586
2587 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002588 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002589 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002590
2591 hci_dev_lock(hdev);
2592
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002593 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002594 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002595
2596 /* 22.5 msec page scan interval */
2597 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002598 } else {
2599 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002600
2601 /* default 1.28 sec page scan */
2602 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002603 }
2604
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002605 /* default 11.25 msec page scan window */
2606 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002607
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002608 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2609 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002610 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002611 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002612 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002613 goto done;
2614 }
2615
2616 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2617 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002618 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002619 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002620 goto done;
2621 }
2622
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002623 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002624 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002625done:
2626 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002627 return err;
2628}
2629
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002630static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002631 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002632{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002633 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2634 u16 key_count, expected_len;
2635 int i;
2636
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002637 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002638
2639 expected_len = sizeof(*cp) + key_count *
2640 sizeof(struct mgmt_ltk_info);
2641 if (expected_len != len) {
2642 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2643 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002644 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002645 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002646 }
2647
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002648 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002649
2650 hci_dev_lock(hdev);
2651
2652 hci_smp_ltks_clear(hdev);
2653
2654 for (i = 0; i < key_count; i++) {
2655 struct mgmt_ltk_info *key = &cp->keys[i];
2656 u8 type;
2657
2658 if (key->master)
2659 type = HCI_SMP_LTK;
2660 else
2661 type = HCI_SMP_LTK_SLAVE;
2662
2663 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002664 type, 0, key->authenticated, key->val,
2665 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002666 }
2667
2668 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002669
2670 return 0;
2671}
2672
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002673static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002674 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2675 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002676 bool var_len;
2677 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002678} mgmt_handlers[] = {
2679 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002680 { read_version, false, MGMT_READ_VERSION_SIZE },
2681 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2682 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2683 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2684 { set_powered, false, MGMT_SETTING_SIZE },
2685 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2686 { set_connectable, false, MGMT_SETTING_SIZE },
2687 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2688 { set_pairable, false, MGMT_SETTING_SIZE },
2689 { set_link_security, false, MGMT_SETTING_SIZE },
2690 { set_ssp, false, MGMT_SETTING_SIZE },
2691 { set_hs, false, MGMT_SETTING_SIZE },
2692 { set_le, false, MGMT_SETTING_SIZE },
2693 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2694 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2695 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2696 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2697 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2698 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2699 { disconnect, false, MGMT_DISCONNECT_SIZE },
2700 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2701 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2702 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2703 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2704 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2705 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2706 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2707 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2708 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2709 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2710 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2711 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2712 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2713 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2714 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2715 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2716 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2717 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2718 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002719 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002720};
2721
2722
Johan Hedberg03811012010-12-08 00:21:06 +02002723int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2724{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002725 void *buf;
2726 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002727 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002728 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002729 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002730 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002731 int err;
2732
2733 BT_DBG("got %zu bytes", msglen);
2734
2735 if (msglen < sizeof(*hdr))
2736 return -EINVAL;
2737
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002738 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002739 if (!buf)
2740 return -ENOMEM;
2741
2742 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2743 err = -EFAULT;
2744 goto done;
2745 }
2746
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002747 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002748 opcode = __le16_to_cpu(hdr->opcode);
2749 index = __le16_to_cpu(hdr->index);
2750 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002751
2752 if (len != msglen - sizeof(*hdr)) {
2753 err = -EINVAL;
2754 goto done;
2755 }
2756
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002757 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002758 hdev = hci_dev_get(index);
2759 if (!hdev) {
2760 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002761 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002762 goto done;
2763 }
2764 }
2765
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002766 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2767 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002768 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002769 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002770 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002771 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002772 }
2773
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002774 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2775 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2776 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002777 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002778 goto done;
2779 }
2780
Johan Hedbergbe22b542012-03-01 22:24:41 +02002781 handler = &mgmt_handlers[opcode];
2782
2783 if ((handler->var_len && len < handler->data_len) ||
2784 (!handler->var_len && len != handler->data_len)) {
2785 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002786 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002787 goto done;
2788 }
2789
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002790 if (hdev)
2791 mgmt_init_hdev(sk, hdev);
2792
2793 cp = buf + sizeof(*hdr);
2794
Johan Hedbergbe22b542012-03-01 22:24:41 +02002795 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002796 if (err < 0)
2797 goto done;
2798
Johan Hedberg03811012010-12-08 00:21:06 +02002799 err = msglen;
2800
2801done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002802 if (hdev)
2803 hci_dev_put(hdev);
2804
Johan Hedberg03811012010-12-08 00:21:06 +02002805 kfree(buf);
2806 return err;
2807}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002808
Johan Hedbergb24752f2011-11-03 14:40:33 +02002809static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2810{
2811 u8 *status = data;
2812
2813 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2814 mgmt_pending_remove(cmd);
2815}
2816
Johan Hedberg744cf192011-11-08 20:40:14 +02002817int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002818{
Johan Hedberg744cf192011-11-08 20:40:14 +02002819 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002820}
2821
Johan Hedberg744cf192011-11-08 20:40:14 +02002822int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002823{
Johan Hedberg5f159032012-03-02 03:13:19 +02002824 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002825
Johan Hedberg744cf192011-11-08 20:40:14 +02002826 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002827
Johan Hedberg744cf192011-11-08 20:40:14 +02002828 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002829}
2830
Johan Hedberg73f22f62010-12-29 16:00:25 +02002831struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002832 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002833 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002834 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002835};
2836
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002837static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002838{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002839 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002840
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002841 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002842
2843 list_del(&cmd->list);
2844
2845 if (match->sk == NULL) {
2846 match->sk = cmd->sk;
2847 sock_hold(match->sk);
2848 }
2849
2850 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002851}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002852
Johan Hedberg744cf192011-11-08 20:40:14 +02002853int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002854{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002855 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002856 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002857
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002858 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2859 return 0;
2860
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002861 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002862
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002863 if (powered) {
2864 u8 scan = 0;
2865
2866 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2867 scan |= SCAN_PAGE;
2868 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2869 scan |= SCAN_INQUIRY;
2870
2871 if (scan)
2872 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002873
2874 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002875 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002876 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002877 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002878 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002879 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002880 }
2881
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002882 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002883
2884 if (match.sk)
2885 sock_put(match.sk);
2886
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002887 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002888}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002889
Johan Hedberg744cf192011-11-08 20:40:14 +02002890int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002891{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002892 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002893 bool changed = false;
2894 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002895
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002896 if (discoverable) {
2897 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2898 changed = true;
2899 } else {
2900 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2901 changed = true;
2902 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002903
Johan Hedberged9b5f22012-02-21 20:47:06 +02002904 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002905 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002906
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002907 if (changed)
2908 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002909
Johan Hedberg73f22f62010-12-29 16:00:25 +02002910 if (match.sk)
2911 sock_put(match.sk);
2912
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002913 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002914}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002915
Johan Hedberg744cf192011-11-08 20:40:14 +02002916int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002917{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002918 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002919 bool changed = false;
2920 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002921
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002922 if (connectable) {
2923 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2924 changed = true;
2925 } else {
2926 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2927 changed = true;
2928 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002929
Johan Hedberged9b5f22012-02-21 20:47:06 +02002930 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002931 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002932
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002933 if (changed)
2934 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002935
2936 if (match.sk)
2937 sock_put(match.sk);
2938
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002939 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002940}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002941
Johan Hedberg744cf192011-11-08 20:40:14 +02002942int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002943{
Johan Hedbergca69b792011-11-11 18:10:00 +02002944 u8 mgmt_err = mgmt_status(status);
2945
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002946 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002947 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002948 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002949
2950 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002951 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002952 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002953
2954 return 0;
2955}
2956
Vishal Agarwal745c0ce2012-04-13 17:43:22 +05302957int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002958{
Johan Hedberg86742e12011-11-07 23:13:38 +02002959 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002960
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002961 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002962
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002963 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002964 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2965 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002966 ev.key.type = key->type;
2967 memcpy(ev.key.val, key->val, 16);
2968 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002969
Johan Hedberg744cf192011-11-08 20:40:14 +02002970 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002971}
Johan Hedbergf7520542011-01-20 12:34:39 +02002972
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002973int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2974{
2975 struct mgmt_ev_new_long_term_key ev;
2976
2977 memset(&ev, 0, sizeof(ev));
2978
2979 ev.store_hint = persistent;
2980 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Hemant Guptaeb19aaa2012-03-30 17:23:35 +05302981 ev.key.addr.type = link_to_mgmt(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002982 ev.key.authenticated = key->authenticated;
2983 ev.key.enc_size = key->enc_size;
2984 ev.key.ediv = key->ediv;
2985
2986 if (key->type == HCI_SMP_LTK)
2987 ev.key.master = 1;
2988
2989 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2990 memcpy(ev.key.val, key->val, sizeof(key->val));
2991
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002992 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2993 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002994}
2995
Johan Hedbergafc747a2012-01-15 18:11:07 +02002996int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002997 u8 addr_type, u32 flags, u8 *name, u8 name_len,
2998 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002999{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003000 char buf[512];
3001 struct mgmt_ev_device_connected *ev = (void *) buf;
3002 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003003
Johan Hedbergb644ba32012-01-17 21:48:47 +02003004 bacpy(&ev->addr.bdaddr, bdaddr);
3005 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003006
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003007 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003008
Johan Hedbergb644ba32012-01-17 21:48:47 +02003009 if (name_len > 0)
3010 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003011 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003012
3013 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003014 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003015 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003016
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003017 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003018
3019 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003020 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003021}
3022
Johan Hedberg8962ee72011-01-20 12:40:27 +02003023static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3024{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003025 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003026 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003027 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003028
Johan Hedberg88c3df12012-02-09 14:27:38 +02003029 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3030 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003031
Johan Hedbergaee9b212012-02-18 15:07:59 +02003032 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003033 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003034
3035 *sk = cmd->sk;
3036 sock_hold(*sk);
3037
Johan Hedberga664b5b2011-02-19 12:06:02 -03003038 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003039}
3040
Johan Hedberg124f6e32012-02-09 13:50:12 +02003041static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003042{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003043 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003044 struct mgmt_cp_unpair_device *cp = cmd->param;
3045 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003046
3047 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003048 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3049 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003050
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003051 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3052
Johan Hedbergaee9b212012-02-18 15:07:59 +02003053 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003054
3055 mgmt_pending_remove(cmd);
3056}
3057
Johan Hedbergafc747a2012-01-15 18:11:07 +02003058int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003059 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003060{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003061 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003062 struct sock *sk = NULL;
3063 int err;
3064
Johan Hedberg744cf192011-11-08 20:40:14 +02003065 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003066
Johan Hedbergf7520542011-01-20 12:34:39 +02003067 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003068 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003069
Johan Hedbergafc747a2012-01-15 18:11:07 +02003070 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003071 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003072
3073 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003074 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003075
Johan Hedberg124f6e32012-02-09 13:50:12 +02003076 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003077 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003078
Johan Hedberg8962ee72011-01-20 12:40:27 +02003079 return err;
3080}
3081
Johan Hedberg88c3df12012-02-09 14:27:38 +02003082int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003083 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003084{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003085 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003086 struct pending_cmd *cmd;
3087 int err;
3088
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003089 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003090 if (!cmd)
3091 return -ENOENT;
3092
Johan Hedberg88c3df12012-02-09 14:27:38 +02003093 bacpy(&rp.addr.bdaddr, bdaddr);
3094 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003095
Johan Hedberg88c3df12012-02-09 14:27:38 +02003096 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003097 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003098
Johan Hedberga664b5b2011-02-19 12:06:02 -03003099 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003100
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003101 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3102 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003103 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003104}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003105
Johan Hedberg48264f02011-11-09 13:58:58 +02003106int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003107 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003108{
3109 struct mgmt_ev_connect_failed ev;
3110
Johan Hedberg4c659c32011-11-07 23:13:39 +02003111 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003112 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003113 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003114
Johan Hedberg744cf192011-11-08 20:40:14 +02003115 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003116}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003117
Johan Hedberg744cf192011-11-08 20:40:14 +02003118int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003119{
3120 struct mgmt_ev_pin_code_request ev;
3121
Johan Hedbergd8457692012-02-17 14:24:57 +02003122 bacpy(&ev.addr.bdaddr, bdaddr);
3123 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003124 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003125
Johan Hedberg744cf192011-11-08 20:40:14 +02003126 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003127 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003128}
3129
Johan Hedberg744cf192011-11-08 20:40:14 +02003130int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003131 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003132{
3133 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003134 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003135 int err;
3136
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003137 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003138 if (!cmd)
3139 return -ENOENT;
3140
Johan Hedbergd8457692012-02-17 14:24:57 +02003141 bacpy(&rp.addr.bdaddr, bdaddr);
3142 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003143
Johan Hedbergaee9b212012-02-18 15:07:59 +02003144 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003145 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003146
Johan Hedberga664b5b2011-02-19 12:06:02 -03003147 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003148
3149 return err;
3150}
3151
Johan Hedberg744cf192011-11-08 20:40:14 +02003152int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003153 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003154{
3155 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003156 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003157 int err;
3158
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003159 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003160 if (!cmd)
3161 return -ENOENT;
3162
Johan Hedbergd8457692012-02-17 14:24:57 +02003163 bacpy(&rp.addr.bdaddr, bdaddr);
3164 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003165
Johan Hedbergaee9b212012-02-18 15:07:59 +02003166 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003167 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003168
Johan Hedberga664b5b2011-02-19 12:06:02 -03003169 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003170
3171 return err;
3172}
Johan Hedberga5c29682011-02-19 12:05:57 -03003173
Johan Hedberg744cf192011-11-08 20:40:14 +02003174int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003175 u8 link_type, u8 addr_type, __le32 value,
3176 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003177{
3178 struct mgmt_ev_user_confirm_request ev;
3179
Johan Hedberg744cf192011-11-08 20:40:14 +02003180 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003181
Johan Hedberg272d90d2012-02-09 15:26:12 +02003182 bacpy(&ev.addr.bdaddr, bdaddr);
3183 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003184 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003185 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003186
Johan Hedberg744cf192011-11-08 20:40:14 +02003187 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003188 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003189}
3190
Johan Hedberg272d90d2012-02-09 15:26:12 +02003191int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3192 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003193{
3194 struct mgmt_ev_user_passkey_request ev;
3195
3196 BT_DBG("%s", hdev->name);
3197
Johan Hedberg272d90d2012-02-09 15:26:12 +02003198 bacpy(&ev.addr.bdaddr, bdaddr);
3199 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003200
3201 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003202 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003203}
3204
Brian Gix0df4c182011-11-16 13:53:13 -08003205static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003206 u8 link_type, u8 addr_type, u8 status,
3207 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003208{
3209 struct pending_cmd *cmd;
3210 struct mgmt_rp_user_confirm_reply rp;
3211 int err;
3212
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003213 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003214 if (!cmd)
3215 return -ENOENT;
3216
Johan Hedberg272d90d2012-02-09 15:26:12 +02003217 bacpy(&rp.addr.bdaddr, bdaddr);
3218 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003219 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003220 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003221
Johan Hedberga664b5b2011-02-19 12:06:02 -03003222 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003223
3224 return err;
3225}
3226
Johan Hedberg744cf192011-11-08 20:40:14 +02003227int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003228 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003229{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003230 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003231 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003232}
3233
Johan Hedberg272d90d2012-02-09 15:26:12 +02003234int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003235 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003236{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003237 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003238 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003239}
Johan Hedberg2a611692011-02-19 12:06:00 -03003240
Brian Gix604086b2011-11-23 08:28:33 -08003241int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003242 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003243{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003244 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003245 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003246}
3247
Johan Hedberg272d90d2012-02-09 15:26:12 +02003248int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003249 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003250{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003251 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003252 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003253}
3254
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003255int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003256 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003257{
3258 struct mgmt_ev_auth_failed ev;
3259
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003260 bacpy(&ev.addr.bdaddr, bdaddr);
3261 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003262 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003263
Johan Hedberg744cf192011-11-08 20:40:14 +02003264 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003265}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003266
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003267int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3268{
3269 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003270 bool changed = false;
3271 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003272
3273 if (status) {
3274 u8 mgmt_err = mgmt_status(status);
3275 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003276 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003277 return 0;
3278 }
3279
Johan Hedberg47990ea2012-02-22 11:58:37 +02003280 if (test_bit(HCI_AUTH, &hdev->flags)) {
3281 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3282 changed = true;
3283 } else {
3284 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3285 changed = true;
3286 }
3287
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003288 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003289 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003290
Johan Hedberg47990ea2012-02-22 11:58:37 +02003291 if (changed)
3292 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003293
3294 if (match.sk)
3295 sock_put(match.sk);
3296
3297 return err;
3298}
3299
Johan Hedbergcacaf522012-02-21 00:52:42 +02003300static int clear_eir(struct hci_dev *hdev)
3301{
3302 struct hci_cp_write_eir cp;
3303
3304 if (!(hdev->features[6] & LMP_EXT_INQ))
3305 return 0;
3306
Johan Hedbergc80da272012-02-22 15:38:48 +02003307 memset(hdev->eir, 0, sizeof(hdev->eir));
3308
Johan Hedbergcacaf522012-02-21 00:52:42 +02003309 memset(&cp, 0, sizeof(cp));
3310
3311 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3312}
3313
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003314int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003315{
3316 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003317 bool changed = false;
3318 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003319
3320 if (status) {
3321 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003322
3323 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003324 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003325 err = new_settings(hdev, NULL);
3326
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003327 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3328 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003329
3330 return err;
3331 }
3332
3333 if (enable) {
3334 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3335 changed = true;
3336 } else {
3337 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3338 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003339 }
3340
3341 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3342
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003343 if (changed)
3344 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003345
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003346 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003347 sock_put(match.sk);
3348
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003349 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3350 update_eir(hdev);
3351 else
3352 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003353
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003354 return err;
3355}
3356
Johan Hedberg90e70452012-02-23 23:09:40 +02003357static void class_rsp(struct pending_cmd *cmd, void *data)
3358{
3359 struct cmd_lookup *match = data;
3360
3361 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003362 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003363
3364 list_del(&cmd->list);
3365
3366 if (match->sk == NULL) {
3367 match->sk = cmd->sk;
3368 sock_hold(match->sk);
3369 }
3370
3371 mgmt_pending_free(cmd);
3372}
3373
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003374int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003375 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003376{
Johan Hedberg90e70452012-02-23 23:09:40 +02003377 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3378 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003379
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003380 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3381
Johan Hedberg90e70452012-02-23 23:09:40 +02003382 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3383 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3384 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3385
3386 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003387 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3388 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003389
3390 if (match.sk)
3391 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003392
3393 return err;
3394}
3395
Johan Hedberg744cf192011-11-08 20:40:14 +02003396int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003397{
3398 struct pending_cmd *cmd;
3399 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003400 bool changed = false;
3401 int err = 0;
3402
3403 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3404 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3405 changed = true;
3406 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003407
3408 memset(&ev, 0, sizeof(ev));
3409 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003410 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003411
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003412 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003413 if (!cmd)
3414 goto send_event;
3415
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003416 /* Always assume that either the short or the complete name has
3417 * changed if there was a pending mgmt command */
3418 changed = true;
3419
Johan Hedbergb312b1612011-03-16 14:29:37 +02003420 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003421 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003422 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003423 goto failed;
3424 }
3425
Johan Hedbergaee9b212012-02-18 15:07:59 +02003426 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003427 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003428 if (err < 0)
3429 goto failed;
3430
3431send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003432 if (changed)
3433 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003434 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003435
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003436 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003437
3438failed:
3439 if (cmd)
3440 mgmt_pending_remove(cmd);
3441 return err;
3442}
Szymon Jancc35938b2011-03-22 13:12:21 +01003443
Johan Hedberg744cf192011-11-08 20:40:14 +02003444int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003445 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003446{
3447 struct pending_cmd *cmd;
3448 int err;
3449
Johan Hedberg744cf192011-11-08 20:40:14 +02003450 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003451
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003452 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003453 if (!cmd)
3454 return -ENOENT;
3455
3456 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003457 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3458 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003459 } else {
3460 struct mgmt_rp_read_local_oob_data rp;
3461
3462 memcpy(rp.hash, hash, sizeof(rp.hash));
3463 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3464
Johan Hedberg744cf192011-11-08 20:40:14 +02003465 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003466 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3467 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003468 }
3469
3470 mgmt_pending_remove(cmd);
3471
3472 return err;
3473}
Johan Hedberge17acd42011-03-30 23:57:16 +03003474
Johan Hedberg06199cf2012-02-22 16:37:11 +02003475int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3476{
3477 struct cmd_lookup match = { NULL, hdev };
3478 bool changed = false;
3479 int err = 0;
3480
3481 if (status) {
3482 u8 mgmt_err = mgmt_status(status);
3483
3484 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003485 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003486 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003487
Szymon Jancd97dcb62012-03-16 16:02:56 +01003488 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3489 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003490
3491 return err;
3492 }
3493
3494 if (enable) {
3495 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3496 changed = true;
3497 } else {
3498 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3499 changed = true;
3500 }
3501
3502 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3503
3504 if (changed)
3505 err = new_settings(hdev, match.sk);
3506
3507 if (match.sk)
3508 sock_put(match.sk);
3509
3510 return err;
3511}
3512
Johan Hedberg48264f02011-11-09 13:58:58 +02003513int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003514 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3515 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003516{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003517 char buf[512];
3518 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003519 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003520
Johan Hedberg1dc06092012-01-15 21:01:23 +02003521 /* Leave 5 bytes for a potential CoD field */
3522 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003523 return -EINVAL;
3524
Johan Hedberg1dc06092012-01-15 21:01:23 +02003525 memset(buf, 0, sizeof(buf));
3526
Johan Hedberge319d2e2012-01-15 19:51:59 +02003527 bacpy(&ev->addr.bdaddr, bdaddr);
3528 ev->addr.type = link_to_mgmt(link_type, addr_type);
3529 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003530 if (cfm_name)
3531 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003532 if (!ssp)
3533 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003534
Johan Hedberg1dc06092012-01-15 21:01:23 +02003535 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003536 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003537
Johan Hedberg1dc06092012-01-15 21:01:23 +02003538 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3539 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003540 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003541
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003542 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003543
3544 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003545
Johan Hedberge319d2e2012-01-15 19:51:59 +02003546 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003547}
Johan Hedberga88a9652011-03-30 13:18:12 +03003548
Johan Hedbergb644ba32012-01-17 21:48:47 +02003549int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003550 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003551{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003552 struct mgmt_ev_device_found *ev;
3553 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3554 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003555
Johan Hedbergb644ba32012-01-17 21:48:47 +02003556 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003557
Johan Hedbergb644ba32012-01-17 21:48:47 +02003558 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003559
Johan Hedbergb644ba32012-01-17 21:48:47 +02003560 bacpy(&ev->addr.bdaddr, bdaddr);
3561 ev->addr.type = link_to_mgmt(link_type, addr_type);
3562 ev->rssi = rssi;
3563
3564 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003565 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003566
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003567 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003568
Johan Hedberg053c7e02012-02-04 00:06:00 +02003569 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003570 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003571}
Johan Hedberg314b2382011-04-27 10:29:57 -04003572
Andre Guedes7a135102011-11-09 17:14:25 -03003573int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003574{
3575 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003576 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003577 int err;
3578
Andre Guedes203159d2012-02-13 15:41:01 -03003579 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3580
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003581 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003582 if (!cmd)
3583 return -ENOENT;
3584
Johan Hedbergf808e162012-02-19 12:52:07 +02003585 type = hdev->discovery.type;
3586
3587 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003588 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003589 mgmt_pending_remove(cmd);
3590
3591 return err;
3592}
3593
Andre Guedese6d465c2011-11-09 17:14:26 -03003594int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3595{
3596 struct pending_cmd *cmd;
3597 int err;
3598
3599 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3600 if (!cmd)
3601 return -ENOENT;
3602
Johan Hedbergd9306502012-02-20 23:25:18 +02003603 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003604 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003605 mgmt_pending_remove(cmd);
3606
3607 return err;
3608}
Johan Hedberg314b2382011-04-27 10:29:57 -04003609
Johan Hedberg744cf192011-11-08 20:40:14 +02003610int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003611{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003612 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003613 struct pending_cmd *cmd;
3614
Andre Guedes343fb142011-11-22 17:14:19 -03003615 BT_DBG("%s discovering %u", hdev->name, discovering);
3616
Johan Hedberg164a6e72011-11-01 17:06:44 +02003617 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003618 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003619 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003620 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003621
3622 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003623 u8 type = hdev->discovery.type;
3624
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003625 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3626 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003627 mgmt_pending_remove(cmd);
3628 }
3629
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003630 memset(&ev, 0, sizeof(ev));
3631 ev.type = hdev->discovery.type;
3632 ev.discovering = discovering;
3633
3634 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003635}
Antti Julku5e762442011-08-25 16:48:02 +03003636
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003637int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003638{
3639 struct pending_cmd *cmd;
3640 struct mgmt_ev_device_blocked ev;
3641
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003642 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003643
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003644 bacpy(&ev.addr.bdaddr, bdaddr);
3645 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003646
Johan Hedberg744cf192011-11-08 20:40:14 +02003647 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003648 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003649}
3650
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003651int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003652{
3653 struct pending_cmd *cmd;
3654 struct mgmt_ev_device_unblocked ev;
3655
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003656 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003657
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003658 bacpy(&ev.addr.bdaddr, bdaddr);
3659 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003660
Johan Hedberg744cf192011-11-08 20:40:14 +02003661 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003662 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003663}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003664
3665module_param(enable_hs, bool, 0644);
3666MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3667
3668module_param(enable_le, bool, 0644);
3669MODULE_PARM_DESC(enable_le, "Enable Low Energy support");