blob: 194a0426a3e51eb81137211cb15350fe4597e1cf [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
41#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020082};
83
84static const u16 mgmt_events[] = {
85 MGMT_EV_CONTROLLER_ERROR,
86 MGMT_EV_INDEX_ADDED,
87 MGMT_EV_INDEX_REMOVED,
88 MGMT_EV_NEW_SETTINGS,
89 MGMT_EV_CLASS_OF_DEV_CHANGED,
90 MGMT_EV_LOCAL_NAME_CHANGED,
91 MGMT_EV_NEW_LINK_KEY,
92 MGMT_EV_NEW_LONG_TERM_KEY,
93 MGMT_EV_DEVICE_CONNECTED,
94 MGMT_EV_DEVICE_DISCONNECTED,
95 MGMT_EV_CONNECT_FAILED,
96 MGMT_EV_PIN_CODE_REQUEST,
97 MGMT_EV_USER_CONFIRM_REQUEST,
98 MGMT_EV_USER_PASSKEY_REQUEST,
99 MGMT_EV_AUTH_FAILED,
100 MGMT_EV_DEVICE_FOUND,
101 MGMT_EV_DISCOVERING,
102 MGMT_EV_DEVICE_BLOCKED,
103 MGMT_EV_DEVICE_UNBLOCKED,
104 MGMT_EV_DEVICE_UNPAIRED,
105};
106
Andre Guedes3fd24152012-02-03 17:48:01 -0300107/*
108 * These LE scan and inquiry parameters were chosen according to LE General
109 * Discovery Procedure specification.
110 */
111#define LE_SCAN_TYPE 0x01
112#define LE_SCAN_WIN 0x12
113#define LE_SCAN_INT 0x12
114#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300115#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300116
Andre Guedese8777522012-02-03 17:48:02 -0300117#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300118#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300119
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800120#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200121
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200122#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
123 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
124
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200125struct pending_cmd {
126 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200127 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200128 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100129 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200130 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300131 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200132};
133
Johan Hedbergca69b792011-11-11 18:10:00 +0200134/* HCI to MGMT error code conversion table */
135static u8 mgmt_status_table[] = {
136 MGMT_STATUS_SUCCESS,
137 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
138 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
139 MGMT_STATUS_FAILED, /* Hardware Failure */
140 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
141 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
142 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
143 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
144 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
146 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
147 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
148 MGMT_STATUS_BUSY, /* Command Disallowed */
149 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
150 MGMT_STATUS_REJECTED, /* Rejected Security */
151 MGMT_STATUS_REJECTED, /* Rejected Personal */
152 MGMT_STATUS_TIMEOUT, /* Host Timeout */
153 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
154 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
155 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
156 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
157 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
158 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
159 MGMT_STATUS_BUSY, /* Repeated Attempts */
160 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
161 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
162 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
163 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
164 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
165 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
166 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
167 MGMT_STATUS_FAILED, /* Unspecified Error */
168 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
169 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
170 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
171 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
172 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
173 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
174 MGMT_STATUS_FAILED, /* Unit Link Key Used */
175 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
176 MGMT_STATUS_TIMEOUT, /* Instant Passed */
177 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
178 MGMT_STATUS_FAILED, /* Transaction Collision */
179 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
180 MGMT_STATUS_REJECTED, /* QoS Rejected */
181 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
182 MGMT_STATUS_REJECTED, /* Insufficient Security */
183 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
184 MGMT_STATUS_BUSY, /* Role Switch Pending */
185 MGMT_STATUS_FAILED, /* Slot Violation */
186 MGMT_STATUS_FAILED, /* Role Switch Failed */
187 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
188 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
189 MGMT_STATUS_BUSY, /* Host Busy Pairing */
190 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
191 MGMT_STATUS_BUSY, /* Controller Busy */
192 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
193 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
194 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
195 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
196 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
197};
198
199static u8 mgmt_status(u8 hci_status)
200{
201 if (hci_status < ARRAY_SIZE(mgmt_status_table))
202 return mgmt_status_table[hci_status];
203
204 return MGMT_STATUS_FAILED;
205}
206
Szymon Janc4e51eae2011-02-25 19:05:48 +0100207static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200208{
209 struct sk_buff *skb;
210 struct mgmt_hdr *hdr;
211 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300212 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200213
Szymon Janc34eb5252011-02-28 14:10:08 +0100214 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215
216 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
217 if (!skb)
218 return -ENOMEM;
219
220 hdr = (void *) skb_put(skb, sizeof(*hdr));
221
222 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100223 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200224 hdr->len = cpu_to_le16(sizeof(*ev));
225
226 ev = (void *) skb_put(skb, sizeof(*ev));
227 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200228 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200229
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300230 err = sock_queue_rcv_skb(sk, skb);
231 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200232 kfree_skb(skb);
233
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300234 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200235}
236
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200237static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300238 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200239{
240 struct sk_buff *skb;
241 struct mgmt_hdr *hdr;
242 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300243 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200244
245 BT_DBG("sock %p", sk);
246
Johan Hedberga38528f2011-01-22 06:46:43 +0200247 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200248 if (!skb)
249 return -ENOMEM;
250
251 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200252
Johan Hedberg02d98122010-12-13 21:07:04 +0200253 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100254 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200255 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200256
Johan Hedberga38528f2011-01-22 06:46:43 +0200257 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200258 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200259 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100260
261 if (rp)
262 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200263
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300264 err = sock_queue_rcv_skb(sk, skb);
265 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200266 kfree_skb(skb);
267
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100268 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200269}
270
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300271static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
272 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200273{
274 struct mgmt_rp_read_version rp;
275
276 BT_DBG("sock %p", sk);
277
278 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200279 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200280
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200281 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300282 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200283}
284
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300285static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
286 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200287{
288 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200289 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
290 const u16 num_events = ARRAY_SIZE(mgmt_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200291 u16 *opcode;
292 size_t rp_size;
293 int i, err;
294
295 BT_DBG("sock %p", sk);
296
297 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
298
299 rp = kmalloc(rp_size, GFP_KERNEL);
300 if (!rp)
301 return -ENOMEM;
302
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200303 rp->num_commands = __constant_cpu_to_le16(num_commands);
304 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200305
306 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
307 put_unaligned_le16(mgmt_commands[i], opcode);
308
309 for (i = 0; i < num_events; i++, opcode++)
310 put_unaligned_le16(mgmt_events[i], opcode);
311
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200312 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300313 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200314 kfree(rp);
315
316 return err;
317}
318
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300319static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
320 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200321{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 struct mgmt_rp_read_index_list *rp;
323 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200324 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200325 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200326 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200327 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328
329 BT_DBG("sock %p", sk);
330
331 read_lock(&hci_dev_list_lock);
332
333 count = 0;
334 list_for_each(p, &hci_dev_list) {
335 count++;
336 }
337
Johan Hedberga38528f2011-01-22 06:46:43 +0200338 rp_len = sizeof(*rp) + (2 * count);
339 rp = kmalloc(rp_len, GFP_ATOMIC);
340 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100341 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200342 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100343 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200344
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200345 rp->num_controllers = cpu_to_le16(count);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200346
347 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200348 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200349 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200350 continue;
351
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200352 rp->index[i++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200353 BT_DBG("Added hci%u", d->id);
354 }
355
356 read_unlock(&hci_dev_list_lock);
357
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200358 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300359 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360
Johan Hedberga38528f2011-01-22 06:46:43 +0200361 kfree(rp);
362
363 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364}
365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200367{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200368 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200369
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200370 settings |= MGMT_SETTING_POWERED;
371 settings |= MGMT_SETTING_CONNECTABLE;
372 settings |= MGMT_SETTING_FAST_CONNECTABLE;
373 settings |= MGMT_SETTING_DISCOVERABLE;
374 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200375
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200376 if (hdev->features[6] & LMP_SIMPLE_PAIR)
377 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200378
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200379 if (!(hdev->features[4] & LMP_NO_BREDR)) {
380 settings |= MGMT_SETTING_BREDR;
381 settings |= MGMT_SETTING_LINK_SECURITY;
382 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200383
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100384 if (enable_hs)
385 settings |= MGMT_SETTING_HS;
386
387 if (enable_le) {
388 if (hdev->features[4] & LMP_LE)
389 settings |= MGMT_SETTING_LE;
390 }
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200391
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200392 return settings;
393}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200394
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200395static u32 get_current_settings(struct hci_dev *hdev)
396{
397 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200398
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200399 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100400 settings |= MGMT_SETTING_POWERED;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_CONNECTABLE;
404
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200405 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_DISCOVERABLE;
407
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200408 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_PAIRABLE;
410
411 if (!(hdev->features[4] & LMP_NO_BREDR))
412 settings |= MGMT_SETTING_BREDR;
413
Johan Hedberg06199cf2012-02-22 16:37:11 +0200414 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200416
Johan Hedberg47990ea2012-02-22 11:58:37 +0200417 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200419
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200420 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200421 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200422
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200423 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
424 settings |= MGMT_SETTING_HS;
425
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200426 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200427}
428
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300429#define PNP_INFO_SVCLASS_ID 0x1200
430
431static u8 bluetooth_base_uuid[] = {
432 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
433 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
434};
435
436static u16 get_uuid16(u8 *uuid128)
437{
438 u32 val;
439 int i;
440
441 for (i = 0; i < 12; i++) {
442 if (bluetooth_base_uuid[i] != uuid128[i])
443 return 0;
444 }
445
446 memcpy(&val, &uuid128[12], 4);
447
448 val = le32_to_cpu(val);
449 if (val > 0xffff)
450 return 0;
451
452 return (u16) val;
453}
454
455static void create_eir(struct hci_dev *hdev, u8 *data)
456{
457 u8 *ptr = data;
458 u16 eir_len = 0;
459 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
460 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200461 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300462 size_t name_len;
463
464 name_len = strlen(hdev->dev_name);
465
466 if (name_len > 0) {
467 /* EIR Data type */
468 if (name_len > 48) {
469 name_len = 48;
470 ptr[1] = EIR_NAME_SHORT;
471 } else
472 ptr[1] = EIR_NAME_COMPLETE;
473
474 /* EIR Data length */
475 ptr[0] = name_len + 1;
476
477 memcpy(ptr + 2, hdev->dev_name, name_len);
478
479 eir_len += (name_len + 2);
480 ptr += (name_len + 2);
481 }
482
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700483 if (hdev->inq_tx_power) {
484 ptr[0] = 2;
485 ptr[1] = EIR_TX_POWER;
486 ptr[2] = (u8) hdev->inq_tx_power;
487
488 eir_len += 3;
489 ptr += 3;
490 }
491
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700492 if (hdev->devid_source > 0) {
493 ptr[0] = 9;
494 ptr[1] = EIR_DEVICE_ID;
495
496 put_unaligned_le16(hdev->devid_source, ptr + 2);
497 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
498 put_unaligned_le16(hdev->devid_product, ptr + 6);
499 put_unaligned_le16(hdev->devid_version, ptr + 8);
500
501 eir_len += 10;
502 ptr += 10;
503 }
504
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300505 memset(uuid16_list, 0, sizeof(uuid16_list));
506
507 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200508 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300509 u16 uuid16;
510
511 uuid16 = get_uuid16(uuid->uuid);
512 if (uuid16 == 0)
513 return;
514
515 if (uuid16 < 0x1100)
516 continue;
517
518 if (uuid16 == PNP_INFO_SVCLASS_ID)
519 continue;
520
521 /* Stop if not enough space to put next UUID */
522 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
523 truncated = 1;
524 break;
525 }
526
527 /* Check for duplicates */
528 for (i = 0; uuid16_list[i] != 0; i++)
529 if (uuid16_list[i] == uuid16)
530 break;
531
532 if (uuid16_list[i] == 0) {
533 uuid16_list[i] = uuid16;
534 eir_len += sizeof(u16);
535 }
536 }
537
538 if (uuid16_list[0] != 0) {
539 u8 *length = ptr;
540
541 /* EIR Data type */
542 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
543
544 ptr += 2;
545 eir_len += 2;
546
547 for (i = 0; uuid16_list[i] != 0; i++) {
548 *ptr++ = (uuid16_list[i] & 0x00ff);
549 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
550 }
551
552 /* EIR Data length */
553 *length = (i * sizeof(u16)) + 1;
554 }
555}
556
557static int update_eir(struct hci_dev *hdev)
558{
559 struct hci_cp_write_eir cp;
560
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200561 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200562 return 0;
563
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300564 if (!(hdev->features[6] & LMP_EXT_INQ))
565 return 0;
566
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200567 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300568 return 0;
569
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200570 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300571 return 0;
572
573 memset(&cp, 0, sizeof(cp));
574
575 create_eir(hdev, cp.data);
576
577 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
578 return 0;
579
580 memcpy(hdev->eir, cp.data, sizeof(cp.data));
581
582 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
583}
584
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200585static u8 get_service_classes(struct hci_dev *hdev)
586{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300587 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200588 u8 val = 0;
589
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300590 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200591 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200592
593 return val;
594}
595
596static int update_class(struct hci_dev *hdev)
597{
598 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200599 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200600
601 BT_DBG("%s", hdev->name);
602
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200603 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200604 return 0;
605
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200606 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200607 return 0;
608
609 cod[0] = hdev->minor_class;
610 cod[1] = hdev->major_class;
611 cod[2] = get_service_classes(hdev);
612
613 if (memcmp(cod, hdev->dev_class, 3) == 0)
614 return 0;
615
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200616 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
617 if (err == 0)
618 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
619
620 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200621}
622
Johan Hedberg7d785252011-12-15 00:47:39 +0200623static void service_cache_off(struct work_struct *work)
624{
625 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300626 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200627
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200628 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200629 return;
630
631 hci_dev_lock(hdev);
632
633 update_eir(hdev);
634 update_class(hdev);
635
636 hci_dev_unlock(hdev);
637}
638
Johan Hedberg6a919082012-02-28 06:17:26 +0200639static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200640{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200641 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200642 return;
643
Johan Hedberg4f87da82012-03-02 19:55:56 +0200644 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200645
Johan Hedberg4f87da82012-03-02 19:55:56 +0200646 /* Non-mgmt controlled devices get this bit set
647 * implicitly so that pairing works for them, however
648 * for mgmt we require user-space to explicitly enable
649 * it
650 */
651 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200652}
653
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200654static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300655 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200656{
657 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200658
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200659 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200660
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300661 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200662
Johan Hedberg03811012010-12-08 00:21:06 +0200663 memset(&rp, 0, sizeof(rp));
664
Johan Hedberg03811012010-12-08 00:21:06 +0200665 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200666
667 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200668 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200669
670 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
671 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
672
673 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200674
675 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200676 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200677
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300678 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200679
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200680 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300681 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200682}
683
684static void mgmt_pending_free(struct pending_cmd *cmd)
685{
686 sock_put(cmd->sk);
687 kfree(cmd->param);
688 kfree(cmd);
689}
690
691static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300692 struct hci_dev *hdev, void *data,
693 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200694{
695 struct pending_cmd *cmd;
696
697 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
698 if (!cmd)
699 return NULL;
700
701 cmd->opcode = opcode;
702 cmd->index = hdev->id;
703
704 cmd->param = kmalloc(len, GFP_ATOMIC);
705 if (!cmd->param) {
706 kfree(cmd);
707 return NULL;
708 }
709
710 if (data)
711 memcpy(cmd->param, data, len);
712
713 cmd->sk = sk;
714 sock_hold(sk);
715
716 list_add(&cmd->list, &hdev->mgmt_pending);
717
718 return cmd;
719}
720
721static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300722 void (*cb)(struct pending_cmd *cmd, void *data),
723 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200724{
725 struct list_head *p, *n;
726
727 list_for_each_safe(p, n, &hdev->mgmt_pending) {
728 struct pending_cmd *cmd;
729
730 cmd = list_entry(p, struct pending_cmd, list);
731
732 if (opcode > 0 && cmd->opcode != opcode)
733 continue;
734
735 cb(cmd, data);
736 }
737}
738
739static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
740{
741 struct pending_cmd *cmd;
742
743 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
744 if (cmd->opcode == opcode)
745 return cmd;
746 }
747
748 return NULL;
749}
750
751static void mgmt_pending_remove(struct pending_cmd *cmd)
752{
753 list_del(&cmd->list);
754 mgmt_pending_free(cmd);
755}
756
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200757static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200758{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200759 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200760
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200761 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300762 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200763}
764
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200765static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300766 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200767{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300768 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200769 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200770 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200771
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200772 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200773
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300774 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200775
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100776 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
777 cancel_delayed_work(&hdev->power_off);
778
779 if (cp->val) {
780 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
781 mgmt_powered(hdev, 1);
782 goto failed;
783 }
784 }
785
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200786 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200787 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 goto failed;
789 }
790
791 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200792 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300793 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200794 goto failed;
795 }
796
797 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
798 if (!cmd) {
799 err = -ENOMEM;
800 goto failed;
801 }
802
803 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200804 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200805 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200806 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200807
808 err = 0;
809
810failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300811 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200812 return err;
813}
814
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300815static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
816 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200817{
818 struct sk_buff *skb;
819 struct mgmt_hdr *hdr;
820
821 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
822 if (!skb)
823 return -ENOMEM;
824
825 hdr = (void *) skb_put(skb, sizeof(*hdr));
826 hdr->opcode = cpu_to_le16(event);
827 if (hdev)
828 hdr->index = cpu_to_le16(hdev->id);
829 else
830 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
831 hdr->len = cpu_to_le16(data_len);
832
833 if (data)
834 memcpy(skb_put(skb, data_len), data, data_len);
835
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100836 /* Time stamp */
837 __net_timestamp(skb);
838
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200839 hci_send_to_control(skb, skip_sk);
840 kfree_skb(skb);
841
842 return 0;
843}
844
845static int new_settings(struct hci_dev *hdev, struct sock *skip)
846{
847 __le32 ev;
848
849 ev = cpu_to_le32(get_current_settings(hdev));
850
851 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
852}
853
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200854static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300855 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200856{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300857 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200858 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200859 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200860 u8 scan;
861 int err;
862
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200863 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200864
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100865 timeout = get_unaligned_le16(&cp->timeout);
866 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200867 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300868 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200869
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300870 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200871
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200872 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200873 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300874 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200875 goto failed;
876 }
877
878 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
879 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200880 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300881 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200882 goto failed;
883 }
884
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200885 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200886 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300887 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200888 goto failed;
889 }
890
891 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200892 bool changed = false;
893
894 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
895 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
896 changed = true;
897 }
898
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200899 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200900 if (err < 0)
901 goto failed;
902
903 if (changed)
904 err = new_settings(hdev, sk);
905
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200906 goto failed;
907 }
908
909 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100910 if (hdev->discov_timeout > 0) {
911 cancel_delayed_work(&hdev->discov_off);
912 hdev->discov_timeout = 0;
913 }
914
915 if (cp->val && timeout > 0) {
916 hdev->discov_timeout = timeout;
917 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
918 msecs_to_jiffies(hdev->discov_timeout * 1000));
919 }
920
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200921 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200922 goto failed;
923 }
924
925 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
926 if (!cmd) {
927 err = -ENOMEM;
928 goto failed;
929 }
930
931 scan = SCAN_PAGE;
932
933 if (cp->val)
934 scan |= SCAN_INQUIRY;
935 else
936 cancel_delayed_work(&hdev->discov_off);
937
938 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
939 if (err < 0)
940 mgmt_pending_remove(cmd);
941
Johan Hedberg03811012010-12-08 00:21:06 +0200942 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200943 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200944
945failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300946 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200947 return err;
948}
949
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200950static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300951 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200952{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300953 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200954 struct pending_cmd *cmd;
955 u8 scan;
956 int err;
957
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200958 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200959
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300960 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200961
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200962 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200963 bool changed = false;
964
965 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
966 changed = true;
967
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200968 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200969 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200970 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200971 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
972 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
973 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200974
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200975 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200976 if (err < 0)
977 goto failed;
978
979 if (changed)
980 err = new_settings(hdev, sk);
981
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200982 goto failed;
983 }
984
985 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
986 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200987 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300988 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200989 goto failed;
990 }
991
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200992 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200993 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200994 goto failed;
995 }
996
997 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
998 if (!cmd) {
999 err = -ENOMEM;
1000 goto failed;
1001 }
1002
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001003 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001004 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001005 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001006 scan = 0;
1007
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001008 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1009 hdev->discov_timeout > 0)
1010 cancel_delayed_work(&hdev->discov_off);
1011 }
1012
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001013 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1014 if (err < 0)
1015 mgmt_pending_remove(cmd);
1016
1017failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001018 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001019 return err;
1020}
1021
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001022static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001023 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001024{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001025 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001026 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001027
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001028 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001029
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001030 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001031
1032 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001033 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001035 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001037 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001038 if (err < 0)
1039 goto failed;
1040
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001041 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001042
1043failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001044 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001045 return err;
1046}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001047
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001048static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1049 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001050{
1051 struct mgmt_mode *cp = data;
1052 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001053 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001054 int err;
1055
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001056 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001057
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001058 hci_dev_lock(hdev);
1059
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001060 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001061 bool changed = false;
1062
1063 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1064 &hdev->dev_flags)) {
1065 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1066 changed = true;
1067 }
1068
1069 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1070 if (err < 0)
1071 goto failed;
1072
1073 if (changed)
1074 err = new_settings(hdev, sk);
1075
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001076 goto failed;
1077 }
1078
1079 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001080 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001081 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001082 goto failed;
1083 }
1084
1085 val = !!cp->val;
1086
1087 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1088 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1089 goto failed;
1090 }
1091
1092 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1093 if (!cmd) {
1094 err = -ENOMEM;
1095 goto failed;
1096 }
1097
1098 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1099 if (err < 0) {
1100 mgmt_pending_remove(cmd);
1101 goto failed;
1102 }
1103
1104failed:
1105 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001106 return err;
1107}
1108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001109static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001110{
1111 struct mgmt_mode *cp = data;
1112 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001113 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001114 int err;
1115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001116 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001117
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001118 hci_dev_lock(hdev);
1119
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001120 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001121 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001122 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001123 goto failed;
1124 }
1125
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001126 val = !!cp->val;
1127
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001128 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001129 bool changed = false;
1130
1131 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1132 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1133 changed = true;
1134 }
1135
1136 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1137 if (err < 0)
1138 goto failed;
1139
1140 if (changed)
1141 err = new_settings(hdev, sk);
1142
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001143 goto failed;
1144 }
1145
1146 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001147 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1148 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001149 goto failed;
1150 }
1151
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001152 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1153 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1154 goto failed;
1155 }
1156
1157 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1158 if (!cmd) {
1159 err = -ENOMEM;
1160 goto failed;
1161 }
1162
1163 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1164 if (err < 0) {
1165 mgmt_pending_remove(cmd);
1166 goto failed;
1167 }
1168
1169failed:
1170 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001171 return err;
1172}
1173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001174static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001175{
1176 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001179
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001180 if (!enable_hs)
1181 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001182 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001183
1184 if (cp->val)
1185 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1186 else
1187 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1188
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001189 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001190}
1191
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001192static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001193{
1194 struct mgmt_mode *cp = data;
1195 struct hci_cp_write_le_host_supported hci_cp;
1196 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001197 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001198 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001199
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001200 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001201
Johan Hedberg1de028c2012-02-29 19:55:35 -08001202 hci_dev_lock(hdev);
1203
Johan Hedberg06199cf2012-02-22 16:37:11 +02001204 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001205 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001206 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001207 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001208 }
1209
1210 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001211 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001212
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001213 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001214 bool changed = false;
1215
1216 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1217 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1218 changed = true;
1219 }
1220
1221 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1222 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001223 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001224
1225 if (changed)
1226 err = new_settings(hdev, sk);
1227
Johan Hedberg1de028c2012-02-29 19:55:35 -08001228 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001229 }
1230
1231 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001232 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001233 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001234 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001235 }
1236
1237 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1238 if (!cmd) {
1239 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001240 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001241 }
1242
1243 memset(&hci_cp, 0, sizeof(hci_cp));
1244
1245 if (val) {
1246 hci_cp.le = val;
1247 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1248 }
1249
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001250 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1251 &hci_cp);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001252 if (err < 0) {
1253 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001254 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001255 }
1256
Johan Hedberg1de028c2012-02-29 19:55:35 -08001257unlock:
1258 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001259 return err;
1260}
1261
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001262static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001263{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001264 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001265 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001266 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001267 int err;
1268
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001269 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001270
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001271 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001272
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001273 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001274 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001275 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001276 goto failed;
1277 }
1278
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001279 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1280 if (!uuid) {
1281 err = -ENOMEM;
1282 goto failed;
1283 }
1284
1285 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001286 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001287
1288 list_add(&uuid->list, &hdev->uuids);
1289
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001290 err = update_class(hdev);
1291 if (err < 0)
1292 goto failed;
1293
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001294 err = update_eir(hdev);
1295 if (err < 0)
1296 goto failed;
1297
Johan Hedberg90e70452012-02-23 23:09:40 +02001298 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001299 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001300 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001301 goto failed;
1302 }
1303
1304 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1305 if (!cmd) {
1306 err = -ENOMEM;
1307 goto failed;
1308 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001309
1310failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001311 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001312 return err;
1313}
1314
Johan Hedberg24b78d02012-02-23 23:24:30 +02001315static bool enable_service_cache(struct hci_dev *hdev)
1316{
1317 if (!hdev_is_powered(hdev))
1318 return false;
1319
1320 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001321 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001322 return true;
1323 }
1324
1325 return false;
1326}
1327
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001328static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1329 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001330{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001331 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001332 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001333 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001334 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001335 int err, found;
1336
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001337 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001339 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001340
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001341 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001342 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001343 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001344 goto unlock;
1345 }
1346
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001347 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1348 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001349
Johan Hedberg24b78d02012-02-23 23:24:30 +02001350 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001351 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001352 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001353 goto unlock;
1354 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001355
Johan Hedberg9246a862012-02-23 21:33:16 +02001356 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001357 }
1358
1359 found = 0;
1360
1361 list_for_each_safe(p, n, &hdev->uuids) {
1362 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1363
1364 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1365 continue;
1366
1367 list_del(&match->list);
1368 found++;
1369 }
1370
1371 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001372 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001373 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001374 goto unlock;
1375 }
1376
Johan Hedberg9246a862012-02-23 21:33:16 +02001377update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001378 err = update_class(hdev);
1379 if (err < 0)
1380 goto unlock;
1381
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001382 err = update_eir(hdev);
1383 if (err < 0)
1384 goto unlock;
1385
Johan Hedberg90e70452012-02-23 23:09:40 +02001386 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001387 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001388 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001389 goto unlock;
1390 }
1391
1392 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1393 if (!cmd) {
1394 err = -ENOMEM;
1395 goto unlock;
1396 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001397
1398unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001399 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001400 return err;
1401}
1402
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001403static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001404 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001405{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001406 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001407 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001408 int err;
1409
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001410 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001411
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001412 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001413
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001414 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001415 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001416 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001417 goto unlock;
1418 }
1419
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001420 hdev->major_class = cp->major;
1421 hdev->minor_class = cp->minor;
1422
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001423 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001424 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001425 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001426 goto unlock;
1427 }
1428
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001429 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001430 hci_dev_unlock(hdev);
1431 cancel_delayed_work_sync(&hdev->service_cache);
1432 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001433 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001434 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001435
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001436 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001437 if (err < 0)
1438 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001439
Johan Hedberg90e70452012-02-23 23:09:40 +02001440 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001441 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001442 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001443 goto unlock;
1444 }
1445
1446 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1447 if (!cmd) {
1448 err = -ENOMEM;
1449 goto unlock;
1450 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001451
Johan Hedbergb5235a62012-02-21 14:32:24 +02001452unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001453 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001454 return err;
1455}
1456
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001457static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1458 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001459{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001460 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001461 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001462 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001463
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001464 key_count = get_unaligned_le16(&cp->key_count);
1465
Johan Hedberg86742e12011-11-07 23:13:38 +02001466 expected_len = sizeof(*cp) + key_count *
1467 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001468 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001469 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001470 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001471 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001472 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001473 }
1474
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001475 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001476 key_count);
1477
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001478 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001479
1480 hci_link_keys_clear(hdev);
1481
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001482 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001483
1484 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001485 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001486 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001487 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001488
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001489 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001490 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001491
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001492 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001493 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001494 }
1495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001496 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001497
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001498 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001499
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001500 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001501}
1502
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001503static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001504 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001505{
1506 struct mgmt_ev_device_unpaired ev;
1507
1508 bacpy(&ev.addr.bdaddr, bdaddr);
1509 ev.addr.type = addr_type;
1510
1511 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001512 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001513}
1514
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001515static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001516 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001517{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001518 struct mgmt_cp_unpair_device *cp = data;
1519 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001520 struct hci_cp_disconnect dc;
1521 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001522 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001523 int err;
1524
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001525 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001526
Johan Hedberga8a1d192011-11-10 15:54:38 +02001527 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001528 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1529 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001530
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001531 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001532 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001533 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001534 goto unlock;
1535 }
1536
Johan Hedberg124f6e32012-02-09 13:50:12 +02001537 if (cp->addr.type == MGMT_ADDR_BREDR)
1538 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1539 else
1540 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001541
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001542 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001543 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001544 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001545 goto unlock;
1546 }
1547
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001548 if (cp->disconnect) {
1549 if (cp->addr.type == MGMT_ADDR_BREDR)
1550 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1551 &cp->addr.bdaddr);
1552 else
1553 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1554 &cp->addr.bdaddr);
1555 } else {
1556 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001557 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001558
Johan Hedberga8a1d192011-11-10 15:54:38 +02001559 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001560 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001561 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001562 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001563 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001564 }
1565
Johan Hedberg124f6e32012-02-09 13:50:12 +02001566 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001567 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001568 if (!cmd) {
1569 err = -ENOMEM;
1570 goto unlock;
1571 }
1572
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001573 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001574 dc.reason = 0x13; /* Remote User Terminated Connection */
1575 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1576 if (err < 0)
1577 mgmt_pending_remove(cmd);
1578
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001579unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001580 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001581 return err;
1582}
1583
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001584static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001585 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001586{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001587 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001588 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001589 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001590 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001591 int err;
1592
1593 BT_DBG("");
1594
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001595 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001596
1597 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001598 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001599 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001600 goto failed;
1601 }
1602
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001603 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001604 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001605 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001606 goto failed;
1607 }
1608
Johan Hedberg88c3df12012-02-09 14:27:38 +02001609 if (cp->addr.type == MGMT_ADDR_BREDR)
1610 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1611 else
1612 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001613
Johan Hedberg8962ee72011-01-20 12:40:27 +02001614 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001615 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001616 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001617 goto failed;
1618 }
1619
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001620 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001621 if (!cmd) {
1622 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001623 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001624 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001625
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001626 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001627 dc.reason = 0x13; /* Remote User Terminated Connection */
1628
1629 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1630 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001631 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001632
1633failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001634 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001635 return err;
1636}
1637
Johan Hedberg48264f02011-11-09 13:58:58 +02001638static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001639{
1640 switch (link_type) {
1641 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001642 switch (addr_type) {
1643 case ADDR_LE_DEV_PUBLIC:
1644 return MGMT_ADDR_LE_PUBLIC;
1645 case ADDR_LE_DEV_RANDOM:
1646 return MGMT_ADDR_LE_RANDOM;
1647 default:
1648 return MGMT_ADDR_INVALID;
1649 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001650 case ACL_LINK:
1651 return MGMT_ADDR_BREDR;
1652 default:
1653 return MGMT_ADDR_INVALID;
1654 }
1655}
1656
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001657static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1658 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001659{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001660 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001661 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001662 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001663 int err;
1664 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001665
1666 BT_DBG("");
1667
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001668 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001669
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001670 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001671 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001672 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001673 goto unlock;
1674 }
1675
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001676 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001677 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1678 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001679 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001680 }
1681
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001682 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001683 rp = kmalloc(rp_len, GFP_ATOMIC);
1684 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001685 err = -ENOMEM;
1686 goto unlock;
1687 }
1688
Johan Hedberg2784eb42011-01-21 13:56:35 +02001689 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001690 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001691 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1692 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001693 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001694 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001695 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1696 continue;
1697 i++;
1698 }
1699
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001700 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001701
Johan Hedberg4c659c32011-11-07 23:13:39 +02001702 /* Recalculate length in case of filtered SCO connections, etc */
1703 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001704
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001705 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001706 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001707
Johan Hedberga38528f2011-01-22 06:46:43 +02001708 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001709
1710unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001711 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001712 return err;
1713}
1714
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001715static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001716 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001717{
1718 struct pending_cmd *cmd;
1719 int err;
1720
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001721 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001722 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001723 if (!cmd)
1724 return -ENOMEM;
1725
Johan Hedbergd8457692012-02-17 14:24:57 +02001726 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001727 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001728 if (err < 0)
1729 mgmt_pending_remove(cmd);
1730
1731 return err;
1732}
1733
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001734static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001735 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001736{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001737 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001738 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001739 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001740 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001741 int err;
1742
1743 BT_DBG("");
1744
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001745 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001746
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001747 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001748 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001749 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001750 goto failed;
1751 }
1752
Johan Hedbergd8457692012-02-17 14:24:57 +02001753 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001754 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001755 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001756 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001757 goto failed;
1758 }
1759
1760 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001761 struct mgmt_cp_pin_code_neg_reply ncp;
1762
1763 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001764
1765 BT_ERR("PIN code is not 16 bytes long");
1766
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001767 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001768 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001769 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001770 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001771
1772 goto failed;
1773 }
1774
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001775 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001776 if (!cmd) {
1777 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001778 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001779 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001780
Johan Hedbergd8457692012-02-17 14:24:57 +02001781 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001782 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001783 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001784
1785 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1786 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001787 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001788
1789failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001790 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001791 return err;
1792}
1793
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001794static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001795 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001796{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001797 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001798 int err;
1799
1800 BT_DBG("");
1801
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001802 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001803
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001804 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001805 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001806 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001807 goto failed;
1808 }
1809
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001810 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001811
1812failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001813 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001814 return err;
1815}
1816
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001817static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1818 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001819{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001820 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001821
1822 BT_DBG("");
1823
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001824 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001825
1826 hdev->io_capability = cp->io_capability;
1827
1828 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001829 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001830
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001831 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001832
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001833 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1834 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001835}
1836
Johan Hedberge9a416b2011-02-19 12:05:56 -03001837static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1838{
1839 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001840 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001841
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001842 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001843 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1844 continue;
1845
Johan Hedberge9a416b2011-02-19 12:05:56 -03001846 if (cmd->user_data != conn)
1847 continue;
1848
1849 return cmd;
1850 }
1851
1852 return NULL;
1853}
1854
1855static void pairing_complete(struct pending_cmd *cmd, u8 status)
1856{
1857 struct mgmt_rp_pair_device rp;
1858 struct hci_conn *conn = cmd->user_data;
1859
Johan Hedbergba4e5642011-11-11 00:07:34 +02001860 bacpy(&rp.addr.bdaddr, &conn->dst);
1861 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001862
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001863 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001864 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001865
1866 /* So we don't get further callbacks for this connection */
1867 conn->connect_cfm_cb = NULL;
1868 conn->security_cfm_cb = NULL;
1869 conn->disconn_cfm_cb = NULL;
1870
1871 hci_conn_put(conn);
1872
Johan Hedberga664b5b2011-02-19 12:06:02 -03001873 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001874}
1875
1876static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1877{
1878 struct pending_cmd *cmd;
1879
1880 BT_DBG("status %u", status);
1881
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001882 cmd = find_pairing(conn);
1883 if (!cmd)
1884 BT_DBG("Unable to find a pending command");
1885 else
Johan Hedberge2113262012-02-18 15:20:03 +02001886 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001887}
1888
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001889static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001890 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001891{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001892 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001893 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001894 struct pending_cmd *cmd;
1895 u8 sec_level, auth_type;
1896 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001897 int err;
1898
1899 BT_DBG("");
1900
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001901 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001902
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001903 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001904 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001905 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001906 goto unlock;
1907 }
1908
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001909 sec_level = BT_SECURITY_MEDIUM;
1910 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001911 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001912 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001913 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001914
Johan Hedbergba4e5642011-11-11 00:07:34 +02001915 if (cp->addr.type == MGMT_ADDR_BREDR)
1916 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001917 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001918 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001919 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001920 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001921
Johan Hedberg1425acb2011-11-11 00:07:35 +02001922 memset(&rp, 0, sizeof(rp));
1923 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1924 rp.addr.type = cp->addr.type;
1925
Ville Tervo30e76272011-02-22 16:10:53 -03001926 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001927 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001928 MGMT_STATUS_CONNECT_FAILED, &rp,
1929 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001930 goto unlock;
1931 }
1932
1933 if (conn->connect_cfm_cb) {
1934 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001935 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001936 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001937 goto unlock;
1938 }
1939
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001940 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001941 if (!cmd) {
1942 err = -ENOMEM;
1943 hci_conn_put(conn);
1944 goto unlock;
1945 }
1946
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001947 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001948 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001949 conn->connect_cfm_cb = pairing_complete_cb;
1950
Johan Hedberge9a416b2011-02-19 12:05:56 -03001951 conn->security_cfm_cb = pairing_complete_cb;
1952 conn->disconn_cfm_cb = pairing_complete_cb;
1953 conn->io_capability = cp->io_cap;
1954 cmd->user_data = conn;
1955
1956 if (conn->state == BT_CONNECTED &&
1957 hci_conn_security(conn, sec_level, auth_type))
1958 pairing_complete(cmd, 0);
1959
1960 err = 0;
1961
1962unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001963 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001964 return err;
1965}
1966
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001967static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1968 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001969{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001970 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001971 struct pending_cmd *cmd;
1972 struct hci_conn *conn;
1973 int err;
1974
1975 BT_DBG("");
1976
Johan Hedberg28424702012-02-02 04:02:29 +02001977 hci_dev_lock(hdev);
1978
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001979 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001980 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001981 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001982 goto unlock;
1983 }
1984
Johan Hedberg28424702012-02-02 04:02:29 +02001985 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1986 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001987 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001988 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001989 goto unlock;
1990 }
1991
1992 conn = cmd->user_data;
1993
1994 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001995 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001996 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001997 goto unlock;
1998 }
1999
2000 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2001
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002002 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002003 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002004unlock:
2005 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002006 return err;
2007}
2008
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002009static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002010 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2011 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002012{
Johan Hedberga5c29682011-02-19 12:05:57 -03002013 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002014 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002015 int err;
2016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002017 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002018
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002019 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002020 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002021 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002022 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002023 }
2024
Johan Hedberg272d90d2012-02-09 15:26:12 +02002025 if (type == MGMT_ADDR_BREDR)
2026 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2027 else
Brian Gix47c15e22011-11-16 13:53:14 -08002028 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002029
Johan Hedberg272d90d2012-02-09 15:26:12 +02002030 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002031 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002032 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002033 goto done;
2034 }
2035
2036 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002037 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002038 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002039
Brian Gix5fe57d92011-12-21 16:12:13 -08002040 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002041 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002042 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002043 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002044 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002045 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002046
Brian Gix47c15e22011-11-16 13:53:14 -08002047 goto done;
2048 }
2049
Brian Gix0df4c182011-11-16 13:53:13 -08002050 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002051 if (!cmd) {
2052 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002053 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002054 }
2055
Brian Gix0df4c182011-11-16 13:53:13 -08002056 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002057 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2058 struct hci_cp_user_passkey_reply cp;
2059
2060 bacpy(&cp.bdaddr, bdaddr);
2061 cp.passkey = passkey;
2062 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2063 } else
2064 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2065
Johan Hedberga664b5b2011-02-19 12:06:02 -03002066 if (err < 0)
2067 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002068
Brian Gix0df4c182011-11-16 13:53:13 -08002069done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002070 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002071 return err;
2072}
2073
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002074static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2075 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002076{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002077 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002078
2079 BT_DBG("");
2080
2081 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002082 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002083 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002084
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002085 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002086 MGMT_OP_USER_CONFIRM_REPLY,
2087 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002088}
2089
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002090static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002091 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002092{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002093 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002094
2095 BT_DBG("");
2096
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002097 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002098 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2099 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002100}
2101
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002102static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2103 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002104{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002105 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002106
2107 BT_DBG("");
2108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002109 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002110 MGMT_OP_USER_PASSKEY_REPLY,
2111 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002112}
2113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002114static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002115 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002116{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002117 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002118
2119 BT_DBG("");
2120
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002121 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002122 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2123 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002124}
2125
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002126static int update_name(struct hci_dev *hdev, const char *name)
2127{
2128 struct hci_cp_write_local_name cp;
2129
2130 memcpy(cp.name, name, sizeof(cp.name));
2131
2132 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2133}
2134
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002135static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002136 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002137{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002138 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002139 struct pending_cmd *cmd;
2140 int err;
2141
2142 BT_DBG("");
2143
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002144 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002145
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002146 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002147
Johan Hedbergb5235a62012-02-21 14:32:24 +02002148 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002149 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002150
2151 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002152 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002153 if (err < 0)
2154 goto failed;
2155
2156 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002157 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002158
Johan Hedbergb5235a62012-02-21 14:32:24 +02002159 goto failed;
2160 }
2161
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002162 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002163 if (!cmd) {
2164 err = -ENOMEM;
2165 goto failed;
2166 }
2167
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002168 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002169 if (err < 0)
2170 mgmt_pending_remove(cmd);
2171
2172failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002173 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002174 return err;
2175}
2176
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002177static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002178 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002179{
Szymon Jancc35938b2011-03-22 13:12:21 +01002180 struct pending_cmd *cmd;
2181 int err;
2182
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002183 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002184
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002185 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002186
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002187 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002188 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002189 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002190 goto unlock;
2191 }
2192
2193 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002194 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002195 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002196 goto unlock;
2197 }
2198
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002199 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002200 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002201 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002202 goto unlock;
2203 }
2204
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002205 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002206 if (!cmd) {
2207 err = -ENOMEM;
2208 goto unlock;
2209 }
2210
2211 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2212 if (err < 0)
2213 mgmt_pending_remove(cmd);
2214
2215unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002216 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002217 return err;
2218}
2219
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002220static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002221 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002222{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002223 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002224 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002225 int err;
2226
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002227 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002228
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002229 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002230
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002231 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002232 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002233 MGMT_STATUS_NOT_POWERED, &cp->addr,
2234 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002235 goto unlock;
2236 }
2237
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002238 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002239 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002240 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002241 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002242 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002243 status = 0;
2244
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002245 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002246 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002247
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002248unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002249 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002250 return err;
2251}
2252
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002253static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002254 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002255{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002256 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002257 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002258 int err;
2259
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002260 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002261
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002262 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002263
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002264 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002266 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2267 MGMT_STATUS_NOT_POWERED, &cp->addr,
2268 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002269 goto unlock;
2270 }
2271
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002272 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002273 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002274 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002275 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002276 status = 0;
2277
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002278 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002279 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002280
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002281unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002282 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002283 return err;
2284}
2285
Andre Guedes5e0452c2012-02-17 20:39:38 -03002286int mgmt_interleaved_discovery(struct hci_dev *hdev)
2287{
2288 int err;
2289
2290 BT_DBG("%s", hdev->name);
2291
2292 hci_dev_lock(hdev);
2293
2294 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2295 if (err < 0)
2296 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2297
2298 hci_dev_unlock(hdev);
2299
2300 return err;
2301}
2302
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002303static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002304 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002305{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002306 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002307 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002308 int err;
2309
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002310 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002311
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002312 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002313
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002314 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002315 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002316 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002317 goto failed;
2318 }
2319
Johan Hedbergff9ef572012-01-04 14:23:45 +02002320 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002321 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002322 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002323 goto failed;
2324 }
2325
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002326 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002327 if (!cmd) {
2328 err = -ENOMEM;
2329 goto failed;
2330 }
2331
Andre Guedes4aab14e2012-02-17 20:39:36 -03002332 hdev->discovery.type = cp->type;
2333
2334 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002335 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002336 if (lmp_bredr_capable(hdev))
2337 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2338 else
2339 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002340 break;
2341
2342 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002343 if (lmp_host_le_capable(hdev))
2344 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002345 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002346 else
2347 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002348 break;
2349
Andre Guedes5e0452c2012-02-17 20:39:38 -03002350 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002351 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2352 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002353 LE_SCAN_WIN,
2354 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002355 else
2356 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002357 break;
2358
Andre Guedesf39799f2012-02-17 20:39:35 -03002359 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002360 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002361 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002362
Johan Hedberg14a53662011-04-27 10:29:56 -04002363 if (err < 0)
2364 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002365 else
2366 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002367
2368failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002369 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002370 return err;
2371}
2372
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002373static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002374 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002375{
Johan Hedbergd9306502012-02-20 23:25:18 +02002376 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002377 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002378 struct hci_cp_remote_name_req_cancel cp;
2379 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002380 int err;
2381
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002382 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002383
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002384 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002385
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002386 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002387 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002388 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2389 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002390 goto unlock;
2391 }
2392
2393 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002394 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002395 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2396 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002397 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002398 }
2399
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002400 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002401 if (!cmd) {
2402 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002403 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002404 }
2405
Andre Guedes343f9352012-02-17 20:39:37 -03002406 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002407 err = hci_cancel_inquiry(hdev);
2408 if (err < 0)
2409 mgmt_pending_remove(cmd);
2410 else
2411 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2412 goto unlock;
2413 }
2414
2415 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2416 if (!e) {
2417 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002418 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002419 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002420 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2421 goto unlock;
2422 }
2423
2424 bacpy(&cp.bdaddr, &e->data.bdaddr);
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002425 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2426 &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002427 if (err < 0)
2428 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002429 else
2430 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002431
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002432unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002433 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002434 return err;
2435}
2436
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002437static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002438 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002439{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002440 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002441 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002442 int err;
2443
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002444 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002445
Johan Hedberg561aafb2012-01-04 13:31:59 +02002446 hci_dev_lock(hdev);
2447
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002448 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002449 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002450 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002451 goto failed;
2452 }
2453
Johan Hedberga198e7b2012-02-17 14:27:06 +02002454 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002455 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002456 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002457 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002458 goto failed;
2459 }
2460
2461 if (cp->name_known) {
2462 e->name_state = NAME_KNOWN;
2463 list_del(&e->list);
2464 } else {
2465 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002466 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002467 }
2468
2469 err = 0;
2470
2471failed:
2472 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002473 return err;
2474}
2475
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002476static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002477 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002478{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002479 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002480 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002481 int err;
2482
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002483 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002484
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002485 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002486
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002487 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002488 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002489 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002490 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002491 status = 0;
2492
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002493 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002494 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002495
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002496 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002497
2498 return err;
2499}
2500
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002501static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002502 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002503{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002504 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002505 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002506 int err;
2507
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002508 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002509
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002510 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002511
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002512 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002513 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002514 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002515 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002516 status = 0;
2517
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002518 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002519 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002520
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002521 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002522
2523 return err;
2524}
2525
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002526static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2527 u16 len)
2528{
2529 struct mgmt_cp_set_device_id *cp = data;
2530 int err;
2531
2532 BT_DBG("%s", hdev->name);
2533
2534 hci_dev_lock(hdev);
2535
2536 hdev->devid_source = __le16_to_cpu(cp->source);
2537 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2538 hdev->devid_product = __le16_to_cpu(cp->product);
2539 hdev->devid_version = __le16_to_cpu(cp->version);
2540
2541 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2542
2543 update_eir(hdev);
2544
2545 hci_dev_unlock(hdev);
2546
2547 return err;
2548}
2549
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002550static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002551 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002552{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002553 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002554 struct hci_cp_write_page_scan_activity acp;
2555 u8 type;
2556 int err;
2557
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002558 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002559
Johan Hedberg5400c042012-02-21 16:40:33 +02002560 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002561 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002562 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002563
2564 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002565 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002566 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002567
2568 hci_dev_lock(hdev);
2569
Johan Hedbergf7c68692011-12-15 00:47:36 +02002570 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002571 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002572
2573 /* 22.5 msec page scan interval */
2574 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002575 } else {
2576 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002577
2578 /* default 1.28 sec page scan */
2579 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002580 }
2581
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002582 /* default 11.25 msec page scan window */
2583 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002584
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002585 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2586 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002587 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002588 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002589 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002590 goto done;
2591 }
2592
2593 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2594 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002595 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002596 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002597 goto done;
2598 }
2599
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002600 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002601 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002602done:
2603 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002604 return err;
2605}
2606
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002607static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002608 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002609{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002610 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2611 u16 key_count, expected_len;
2612 int i;
2613
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002614 key_count = get_unaligned_le16(&cp->key_count);
2615
2616 expected_len = sizeof(*cp) + key_count *
2617 sizeof(struct mgmt_ltk_info);
2618 if (expected_len != len) {
2619 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2620 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002621 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002622 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002623 }
2624
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002625 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002626
2627 hci_dev_lock(hdev);
2628
2629 hci_smp_ltks_clear(hdev);
2630
2631 for (i = 0; i < key_count; i++) {
2632 struct mgmt_ltk_info *key = &cp->keys[i];
2633 u8 type;
2634
2635 if (key->master)
2636 type = HCI_SMP_LTK;
2637 else
2638 type = HCI_SMP_LTK_SLAVE;
2639
2640 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002641 type, 0, key->authenticated, key->val,
2642 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002643 }
2644
2645 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002646
2647 return 0;
2648}
2649
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002650struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002651 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2652 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002653 bool var_len;
2654 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002655} mgmt_handlers[] = {
2656 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002657 { read_version, false, MGMT_READ_VERSION_SIZE },
2658 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2659 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2660 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2661 { set_powered, false, MGMT_SETTING_SIZE },
2662 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2663 { set_connectable, false, MGMT_SETTING_SIZE },
2664 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2665 { set_pairable, false, MGMT_SETTING_SIZE },
2666 { set_link_security, false, MGMT_SETTING_SIZE },
2667 { set_ssp, false, MGMT_SETTING_SIZE },
2668 { set_hs, false, MGMT_SETTING_SIZE },
2669 { set_le, false, MGMT_SETTING_SIZE },
2670 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2671 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2672 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2673 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2674 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2675 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2676 { disconnect, false, MGMT_DISCONNECT_SIZE },
2677 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2678 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2679 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2680 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2681 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2682 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2683 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2684 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2685 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2686 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2687 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2688 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2689 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2690 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2691 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2692 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2693 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2694 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2695 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002696 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002697};
2698
2699
Johan Hedberg03811012010-12-08 00:21:06 +02002700int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2701{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002702 void *buf;
2703 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002704 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002705 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002706 struct hci_dev *hdev = NULL;
Johan Hedbergbe22b542012-03-01 22:24:41 +02002707 struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002708 int err;
2709
2710 BT_DBG("got %zu bytes", msglen);
2711
2712 if (msglen < sizeof(*hdr))
2713 return -EINVAL;
2714
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002715 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002716 if (!buf)
2717 return -ENOMEM;
2718
2719 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2720 err = -EFAULT;
2721 goto done;
2722 }
2723
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002724 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002725 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002726 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002727 len = get_unaligned_le16(&hdr->len);
2728
2729 if (len != msglen - sizeof(*hdr)) {
2730 err = -EINVAL;
2731 goto done;
2732 }
2733
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002734 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002735 hdev = hci_dev_get(index);
2736 if (!hdev) {
2737 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002738 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002739 goto done;
2740 }
2741 }
2742
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002743 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2744 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002745 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002746 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002747 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002748 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002749 }
2750
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002751 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2752 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2753 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002754 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002755 goto done;
2756 }
2757
Johan Hedbergbe22b542012-03-01 22:24:41 +02002758 handler = &mgmt_handlers[opcode];
2759
2760 if ((handler->var_len && len < handler->data_len) ||
2761 (!handler->var_len && len != handler->data_len)) {
2762 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002763 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002764 goto done;
2765 }
2766
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002767 if (hdev)
2768 mgmt_init_hdev(sk, hdev);
2769
2770 cp = buf + sizeof(*hdr);
2771
Johan Hedbergbe22b542012-03-01 22:24:41 +02002772 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002773 if (err < 0)
2774 goto done;
2775
Johan Hedberg03811012010-12-08 00:21:06 +02002776 err = msglen;
2777
2778done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002779 if (hdev)
2780 hci_dev_put(hdev);
2781
Johan Hedberg03811012010-12-08 00:21:06 +02002782 kfree(buf);
2783 return err;
2784}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002785
Johan Hedbergb24752f2011-11-03 14:40:33 +02002786static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2787{
2788 u8 *status = data;
2789
2790 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2791 mgmt_pending_remove(cmd);
2792}
2793
Johan Hedberg744cf192011-11-08 20:40:14 +02002794int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002795{
Johan Hedberg744cf192011-11-08 20:40:14 +02002796 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002797}
2798
Johan Hedberg744cf192011-11-08 20:40:14 +02002799int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002800{
Johan Hedberg5f159032012-03-02 03:13:19 +02002801 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002802
Johan Hedberg744cf192011-11-08 20:40:14 +02002803 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002804
Johan Hedberg744cf192011-11-08 20:40:14 +02002805 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002806}
2807
Johan Hedberg73f22f62010-12-29 16:00:25 +02002808struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002809 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002810 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002811 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002812};
2813
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002814static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002815{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002816 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002817
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002818 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002819
2820 list_del(&cmd->list);
2821
2822 if (match->sk == NULL) {
2823 match->sk = cmd->sk;
2824 sock_hold(match->sk);
2825 }
2826
2827 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002828}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002829
Johan Hedberg744cf192011-11-08 20:40:14 +02002830int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002831{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002832 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002833 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002834
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002835 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2836 return 0;
2837
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002838 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002839
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002840 if (powered) {
2841 u8 scan = 0;
2842
2843 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2844 scan |= SCAN_PAGE;
2845 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2846 scan |= SCAN_INQUIRY;
2847
2848 if (scan)
2849 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002850
2851 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002852 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002853 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002854 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002855 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002856 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002857 }
2858
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002859 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002860
2861 if (match.sk)
2862 sock_put(match.sk);
2863
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002864 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002865}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002866
Johan Hedberg744cf192011-11-08 20:40:14 +02002867int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002868{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002869 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002870 bool changed = false;
2871 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002872
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002873 if (discoverable) {
2874 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2875 changed = true;
2876 } else {
2877 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2878 changed = true;
2879 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002880
Johan Hedberged9b5f22012-02-21 20:47:06 +02002881 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002882 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002883
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002884 if (changed)
2885 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002886
Johan Hedberg73f22f62010-12-29 16:00:25 +02002887 if (match.sk)
2888 sock_put(match.sk);
2889
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002890 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002891}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002892
Johan Hedberg744cf192011-11-08 20:40:14 +02002893int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002894{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002895 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002896 bool changed = false;
2897 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002898
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002899 if (connectable) {
2900 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2901 changed = true;
2902 } else {
2903 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2904 changed = true;
2905 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002906
Johan Hedberged9b5f22012-02-21 20:47:06 +02002907 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002908 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002909
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002910 if (changed)
2911 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002912
2913 if (match.sk)
2914 sock_put(match.sk);
2915
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002916 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002917}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002918
Johan Hedberg744cf192011-11-08 20:40:14 +02002919int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002920{
Johan Hedbergca69b792011-11-11 18:10:00 +02002921 u8 mgmt_err = mgmt_status(status);
2922
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002923 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002924 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002925 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002926
2927 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002928 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002929 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002930
2931 return 0;
2932}
2933
Vishal Agarwal745c0ce2012-04-13 17:43:22 +05302934int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002935{
Johan Hedberg86742e12011-11-07 23:13:38 +02002936 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002937
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002938 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002939
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002940 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002941 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2942 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002943 ev.key.type = key->type;
2944 memcpy(ev.key.val, key->val, 16);
2945 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002946
Johan Hedberg744cf192011-11-08 20:40:14 +02002947 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002948}
Johan Hedbergf7520542011-01-20 12:34:39 +02002949
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002950int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2951{
2952 struct mgmt_ev_new_long_term_key ev;
2953
2954 memset(&ev, 0, sizeof(ev));
2955
2956 ev.store_hint = persistent;
2957 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2958 ev.key.addr.type = key->bdaddr_type;
2959 ev.key.authenticated = key->authenticated;
2960 ev.key.enc_size = key->enc_size;
2961 ev.key.ediv = key->ediv;
2962
2963 if (key->type == HCI_SMP_LTK)
2964 ev.key.master = 1;
2965
2966 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2967 memcpy(ev.key.val, key->val, sizeof(key->val));
2968
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002969 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2970 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002971}
2972
Johan Hedbergafc747a2012-01-15 18:11:07 +02002973int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002974 u8 addr_type, u32 flags, u8 *name, u8 name_len,
2975 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002976{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002977 char buf[512];
2978 struct mgmt_ev_device_connected *ev = (void *) buf;
2979 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002980
Johan Hedbergb644ba32012-01-17 21:48:47 +02002981 bacpy(&ev->addr.bdaddr, bdaddr);
2982 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002983
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002984 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002985
Johan Hedbergb644ba32012-01-17 21:48:47 +02002986 if (name_len > 0)
2987 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002988 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002989
2990 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08002991 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002992 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002993
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02002994 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002995
2996 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002997 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002998}
2999
Johan Hedberg8962ee72011-01-20 12:40:27 +02003000static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3001{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003002 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003003 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003004 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003005
Johan Hedberg88c3df12012-02-09 14:27:38 +02003006 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3007 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003008
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003009 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003010 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003011
3012 *sk = cmd->sk;
3013 sock_hold(*sk);
3014
Johan Hedberga664b5b2011-02-19 12:06:02 -03003015 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003016}
3017
Johan Hedberg124f6e32012-02-09 13:50:12 +02003018static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003019{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003020 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003021 struct mgmt_cp_unpair_device *cp = cmd->param;
3022 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003023
3024 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003025 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3026 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003027
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003028 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3029
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003030 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003031
3032 mgmt_pending_remove(cmd);
3033}
3034
Johan Hedbergafc747a2012-01-15 18:11:07 +02003035int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003037{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003038 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003039 struct sock *sk = NULL;
3040 int err;
3041
Johan Hedberg744cf192011-11-08 20:40:14 +02003042 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003043
Johan Hedbergf7520542011-01-20 12:34:39 +02003044 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003045 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003046
Johan Hedbergafc747a2012-01-15 18:11:07 +02003047 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003048 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003049
3050 if (sk)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003051 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003052
Johan Hedberg124f6e32012-02-09 13:50:12 +02003053 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003054 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003055
Johan Hedberg8962ee72011-01-20 12:40:27 +02003056 return err;
3057}
3058
Johan Hedberg88c3df12012-02-09 14:27:38 +02003059int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003060 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003061{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003062 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003063 struct pending_cmd *cmd;
3064 int err;
3065
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003066 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003067 if (!cmd)
3068 return -ENOENT;
3069
Johan Hedberg88c3df12012-02-09 14:27:38 +02003070 bacpy(&rp.addr.bdaddr, bdaddr);
3071 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003072
Johan Hedberg88c3df12012-02-09 14:27:38 +02003073 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003074 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003075
Johan Hedberga664b5b2011-02-19 12:06:02 -03003076 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003077
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003078 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3079 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003080 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003081}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003082
Johan Hedberg48264f02011-11-09 13:58:58 +02003083int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003084 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003085{
3086 struct mgmt_ev_connect_failed ev;
3087
Johan Hedberg4c659c32011-11-07 23:13:39 +02003088 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003089 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003090 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003091
Johan Hedberg744cf192011-11-08 20:40:14 +02003092 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003093}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003094
Johan Hedberg744cf192011-11-08 20:40:14 +02003095int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003096{
3097 struct mgmt_ev_pin_code_request ev;
3098
Johan Hedbergd8457692012-02-17 14:24:57 +02003099 bacpy(&ev.addr.bdaddr, bdaddr);
3100 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003101 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003102
Johan Hedberg744cf192011-11-08 20:40:14 +02003103 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003104 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003105}
3106
Johan Hedberg744cf192011-11-08 20:40:14 +02003107int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003108 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003109{
3110 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003111 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003112 int err;
3113
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003114 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003115 if (!cmd)
3116 return -ENOENT;
3117
Johan Hedbergd8457692012-02-17 14:24:57 +02003118 bacpy(&rp.addr.bdaddr, bdaddr);
3119 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003120
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003121 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003122 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003123
Johan Hedberga664b5b2011-02-19 12:06:02 -03003124 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003125
3126 return err;
3127}
3128
Johan Hedberg744cf192011-11-08 20:40:14 +02003129int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003130 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003131{
3132 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003133 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003134 int err;
3135
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003136 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003137 if (!cmd)
3138 return -ENOENT;
3139
Johan Hedbergd8457692012-02-17 14:24:57 +02003140 bacpy(&rp.addr.bdaddr, bdaddr);
3141 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003142
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003143 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003144 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003145
Johan Hedberga664b5b2011-02-19 12:06:02 -03003146 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003147
3148 return err;
3149}
Johan Hedberga5c29682011-02-19 12:05:57 -03003150
Johan Hedberg744cf192011-11-08 20:40:14 +02003151int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003152 u8 link_type, u8 addr_type, __le32 value,
3153 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003154{
3155 struct mgmt_ev_user_confirm_request ev;
3156
Johan Hedberg744cf192011-11-08 20:40:14 +02003157 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003158
Johan Hedberg272d90d2012-02-09 15:26:12 +02003159 bacpy(&ev.addr.bdaddr, bdaddr);
3160 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003161 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003162 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003163
Johan Hedberg744cf192011-11-08 20:40:14 +02003164 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003165 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003166}
3167
Johan Hedberg272d90d2012-02-09 15:26:12 +02003168int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3169 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003170{
3171 struct mgmt_ev_user_passkey_request ev;
3172
3173 BT_DBG("%s", hdev->name);
3174
Johan Hedberg272d90d2012-02-09 15:26:12 +02003175 bacpy(&ev.addr.bdaddr, bdaddr);
3176 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003177
3178 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003179 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003180}
3181
Brian Gix0df4c182011-11-16 13:53:13 -08003182static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003183 u8 link_type, u8 addr_type, u8 status,
3184 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003185{
3186 struct pending_cmd *cmd;
3187 struct mgmt_rp_user_confirm_reply rp;
3188 int err;
3189
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003190 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003191 if (!cmd)
3192 return -ENOENT;
3193
Johan Hedberg272d90d2012-02-09 15:26:12 +02003194 bacpy(&rp.addr.bdaddr, bdaddr);
3195 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003196 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003197 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003198
Johan Hedberga664b5b2011-02-19 12:06:02 -03003199 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003200
3201 return err;
3202}
3203
Johan Hedberg744cf192011-11-08 20:40:14 +02003204int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003205 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003206{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003207 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003208 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003209}
3210
Johan Hedberg272d90d2012-02-09 15:26:12 +02003211int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003212 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003213{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003214 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003215 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003216}
Johan Hedberg2a611692011-02-19 12:06:00 -03003217
Brian Gix604086b2011-11-23 08:28:33 -08003218int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003219 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003220{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003221 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003222 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003223}
3224
Johan Hedberg272d90d2012-02-09 15:26:12 +02003225int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003226 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003227{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003228 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003229 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003230}
3231
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003232int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003233 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003234{
3235 struct mgmt_ev_auth_failed ev;
3236
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003237 bacpy(&ev.addr.bdaddr, bdaddr);
3238 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003239 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003240
Johan Hedberg744cf192011-11-08 20:40:14 +02003241 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003242}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003243
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003244int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3245{
3246 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003247 bool changed = false;
3248 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003249
3250 if (status) {
3251 u8 mgmt_err = mgmt_status(status);
3252 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003253 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003254 return 0;
3255 }
3256
Johan Hedberg47990ea2012-02-22 11:58:37 +02003257 if (test_bit(HCI_AUTH, &hdev->flags)) {
3258 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3259 changed = true;
3260 } else {
3261 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3262 changed = true;
3263 }
3264
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003265 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003266 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003267
Johan Hedberg47990ea2012-02-22 11:58:37 +02003268 if (changed)
3269 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003270
3271 if (match.sk)
3272 sock_put(match.sk);
3273
3274 return err;
3275}
3276
Johan Hedbergcacaf522012-02-21 00:52:42 +02003277static int clear_eir(struct hci_dev *hdev)
3278{
3279 struct hci_cp_write_eir cp;
3280
3281 if (!(hdev->features[6] & LMP_EXT_INQ))
3282 return 0;
3283
Johan Hedbergc80da272012-02-22 15:38:48 +02003284 memset(hdev->eir, 0, sizeof(hdev->eir));
3285
Johan Hedbergcacaf522012-02-21 00:52:42 +02003286 memset(&cp, 0, sizeof(cp));
3287
3288 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3289}
3290
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003291int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003292{
3293 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003294 bool changed = false;
3295 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003296
3297 if (status) {
3298 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003299
3300 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003301 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003302 err = new_settings(hdev, NULL);
3303
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003304 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3305 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003306
3307 return err;
3308 }
3309
3310 if (enable) {
3311 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3312 changed = true;
3313 } else {
3314 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3315 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003316 }
3317
3318 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3319
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003320 if (changed)
3321 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003322
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003323 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003324 sock_put(match.sk);
3325
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003326 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3327 update_eir(hdev);
3328 else
3329 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003330
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003331 return err;
3332}
3333
Johan Hedberg90e70452012-02-23 23:09:40 +02003334static void class_rsp(struct pending_cmd *cmd, void *data)
3335{
3336 struct cmd_lookup *match = data;
3337
3338 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003339 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003340
3341 list_del(&cmd->list);
3342
3343 if (match->sk == NULL) {
3344 match->sk = cmd->sk;
3345 sock_hold(match->sk);
3346 }
3347
3348 mgmt_pending_free(cmd);
3349}
3350
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003351int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003352 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003353{
Johan Hedberg90e70452012-02-23 23:09:40 +02003354 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3355 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003356
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003357 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3358
Johan Hedberg90e70452012-02-23 23:09:40 +02003359 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3360 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3361 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3362
3363 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003364 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3365 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003366
3367 if (match.sk)
3368 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003369
3370 return err;
3371}
3372
Johan Hedberg744cf192011-11-08 20:40:14 +02003373int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003374{
3375 struct pending_cmd *cmd;
3376 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003377 bool changed = false;
3378 int err = 0;
3379
3380 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3381 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3382 changed = true;
3383 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003384
3385 memset(&ev, 0, sizeof(ev));
3386 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003387 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003388
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003389 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003390 if (!cmd)
3391 goto send_event;
3392
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003393 /* Always assume that either the short or the complete name has
3394 * changed if there was a pending mgmt command */
3395 changed = true;
3396
Johan Hedbergb312b1612011-03-16 14:29:37 +02003397 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003398 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003399 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003400 goto failed;
3401 }
3402
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003403 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003404 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003405 if (err < 0)
3406 goto failed;
3407
3408send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003409 if (changed)
3410 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003411 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003412
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003413 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003414
3415failed:
3416 if (cmd)
3417 mgmt_pending_remove(cmd);
3418 return err;
3419}
Szymon Jancc35938b2011-03-22 13:12:21 +01003420
Johan Hedberg744cf192011-11-08 20:40:14 +02003421int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003422 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003423{
3424 struct pending_cmd *cmd;
3425 int err;
3426
Johan Hedberg744cf192011-11-08 20:40:14 +02003427 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003428
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003429 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003430 if (!cmd)
3431 return -ENOENT;
3432
3433 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003434 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3435 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003436 } else {
3437 struct mgmt_rp_read_local_oob_data rp;
3438
3439 memcpy(rp.hash, hash, sizeof(rp.hash));
3440 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3441
Johan Hedberg744cf192011-11-08 20:40:14 +02003442 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003443 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3444 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003445 }
3446
3447 mgmt_pending_remove(cmd);
3448
3449 return err;
3450}
Johan Hedberge17acd42011-03-30 23:57:16 +03003451
Johan Hedberg06199cf2012-02-22 16:37:11 +02003452int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3453{
3454 struct cmd_lookup match = { NULL, hdev };
3455 bool changed = false;
3456 int err = 0;
3457
3458 if (status) {
3459 u8 mgmt_err = mgmt_status(status);
3460
3461 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003462 &hdev->dev_flags))
3463 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003464
3465 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003466 cmd_status_rsp, &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003467
3468 return err;
3469 }
3470
3471 if (enable) {
3472 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3473 changed = true;
3474 } else {
3475 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3476 changed = true;
3477 }
3478
3479 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3480
3481 if (changed)
3482 err = new_settings(hdev, match.sk);
3483
3484 if (match.sk)
3485 sock_put(match.sk);
3486
3487 return err;
3488}
3489
Johan Hedberg48264f02011-11-09 13:58:58 +02003490int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003491 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3492 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003493{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003494 char buf[512];
3495 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003496 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003497
Johan Hedberg1dc06092012-01-15 21:01:23 +02003498 /* Leave 5 bytes for a potential CoD field */
3499 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003500 return -EINVAL;
3501
Johan Hedberg1dc06092012-01-15 21:01:23 +02003502 memset(buf, 0, sizeof(buf));
3503
Johan Hedberge319d2e2012-01-15 19:51:59 +02003504 bacpy(&ev->addr.bdaddr, bdaddr);
3505 ev->addr.type = link_to_mgmt(link_type, addr_type);
3506 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003507 if (cfm_name)
3508 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003509 if (!ssp)
3510 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003511
Johan Hedberg1dc06092012-01-15 21:01:23 +02003512 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003513 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003514
Johan Hedberg1dc06092012-01-15 21:01:23 +02003515 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3516 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003517 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003518
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003519 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003520
3521 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003522
Johan Hedberge319d2e2012-01-15 19:51:59 +02003523 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003524}
Johan Hedberga88a9652011-03-30 13:18:12 +03003525
Johan Hedbergb644ba32012-01-17 21:48:47 +02003526int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003527 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003528{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003529 struct mgmt_ev_device_found *ev;
3530 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3531 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003532
Johan Hedbergb644ba32012-01-17 21:48:47 +02003533 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003534
Johan Hedbergb644ba32012-01-17 21:48:47 +02003535 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003536
Johan Hedbergb644ba32012-01-17 21:48:47 +02003537 bacpy(&ev->addr.bdaddr, bdaddr);
3538 ev->addr.type = link_to_mgmt(link_type, addr_type);
3539 ev->rssi = rssi;
3540
3541 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003542 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003543
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003544 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003545
Johan Hedberg053c7e02012-02-04 00:06:00 +02003546 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003547 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003548}
Johan Hedberg314b2382011-04-27 10:29:57 -04003549
Andre Guedes7a135102011-11-09 17:14:25 -03003550int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003551{
3552 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003553 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003554 int err;
3555
Andre Guedes203159d2012-02-13 15:41:01 -03003556 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3557
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003558 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003559 if (!cmd)
3560 return -ENOENT;
3561
Johan Hedbergf808e162012-02-19 12:52:07 +02003562 type = hdev->discovery.type;
3563
3564 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003565 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003566 mgmt_pending_remove(cmd);
3567
3568 return err;
3569}
3570
Andre Guedese6d465c2011-11-09 17:14:26 -03003571int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3572{
3573 struct pending_cmd *cmd;
3574 int err;
3575
3576 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3577 if (!cmd)
3578 return -ENOENT;
3579
Johan Hedbergd9306502012-02-20 23:25:18 +02003580 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003581 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003582 mgmt_pending_remove(cmd);
3583
3584 return err;
3585}
Johan Hedberg314b2382011-04-27 10:29:57 -04003586
Johan Hedberg744cf192011-11-08 20:40:14 +02003587int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003588{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003589 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003590 struct pending_cmd *cmd;
3591
Andre Guedes343fb142011-11-22 17:14:19 -03003592 BT_DBG("%s discovering %u", hdev->name, discovering);
3593
Johan Hedberg164a6e72011-11-01 17:06:44 +02003594 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003595 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003596 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003597 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003598
3599 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003600 u8 type = hdev->discovery.type;
3601
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003602 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3603 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003604 mgmt_pending_remove(cmd);
3605 }
3606
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003607 memset(&ev, 0, sizeof(ev));
3608 ev.type = hdev->discovery.type;
3609 ev.discovering = discovering;
3610
3611 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003612}
Antti Julku5e762442011-08-25 16:48:02 +03003613
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003614int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003615{
3616 struct pending_cmd *cmd;
3617 struct mgmt_ev_device_blocked ev;
3618
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003619 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003620
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003621 bacpy(&ev.addr.bdaddr, bdaddr);
3622 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003623
Johan Hedberg744cf192011-11-08 20:40:14 +02003624 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003625 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003626}
3627
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003628int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003629{
3630 struct pending_cmd *cmd;
3631 struct mgmt_ev_device_unblocked ev;
3632
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003633 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003634
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003635 bacpy(&ev.addr.bdaddr, bdaddr);
3636 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003637
Johan Hedberg744cf192011-11-08 20:40:14 +02003638 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003639 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003640}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003641
3642module_param(enable_hs, bool, 0644);
3643MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3644
3645module_param(enable_le, bool, 0644);
3646MODULE_PARM_DESC(enable_le, "Enable Low Energy support");