blob: 5e88fda42f1fd7796bb8602a05f537e5d52fe8f7 [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;
228 put_unaligned_le16(cmd, &ev->opcode);
229
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 Hedbergaee9b212012-02-18 15:07:59 +0200237static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300238 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200239{
240 struct sk_buff *skb;
241 struct mgmt_hdr *hdr;
242 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300243 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200244
245 BT_DBG("sock %p", sk);
246
Johan Hedberga38528f2011-01-22 06:46:43 +0200247 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200248 if (!skb)
249 return -ENOMEM;
250
251 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200252
Johan Hedberg02d98122010-12-13 21:07:04 +0200253 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100254 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200255 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200256
Johan Hedberga38528f2011-01-22 06:46:43 +0200257 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
258 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200259 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100260
261 if (rp)
262 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200263
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300264 err = sock_queue_rcv_skb(sk, skb);
265 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200266 kfree_skb(skb);
267
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100268 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200269}
270
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300271static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
272 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200273{
274 struct mgmt_rp_read_version rp;
275
276 BT_DBG("sock %p", sk);
277
278 rp.version = MGMT_VERSION;
279 put_unaligned_le16(MGMT_REVISION, &rp.revision);
280
Johan Hedbergaee9b212012-02-18 15:07:59 +0200281 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300282 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200283}
284
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300285static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
286 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200287{
288 struct mgmt_rp_read_commands *rp;
289 u16 num_commands = ARRAY_SIZE(mgmt_commands);
290 u16 num_events = ARRAY_SIZE(mgmt_events);
291 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
303 put_unaligned_le16(num_commands, &rp->num_commands);
304 put_unaligned_le16(num_events, &rp->num_events);
305
306 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
307 put_unaligned_le16(mgmt_commands[i], opcode);
308
309 for (i = 0; i < num_events; i++, opcode++)
310 put_unaligned_le16(mgmt_events[i], opcode);
311
Johan Hedbergaee9b212012-02-18 15:07:59 +0200312 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300313 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200314 kfree(rp);
315
316 return err;
317}
318
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300319static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
320 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200321{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 struct mgmt_rp_read_index_list *rp;
323 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200324 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200325 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200326 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200327 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328
329 BT_DBG("sock %p", sk);
330
331 read_lock(&hci_dev_list_lock);
332
333 count = 0;
334 list_for_each(p, &hci_dev_list) {
335 count++;
336 }
337
Johan Hedberga38528f2011-01-22 06:46:43 +0200338 rp_len = sizeof(*rp) + (2 * count);
339 rp = kmalloc(rp_len, GFP_ATOMIC);
340 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100341 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200342 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100343 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200344
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345 put_unaligned_le16(count, &rp->num_controllers);
346
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
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352 put_unaligned_le16(d->id, &rp->index[i++]);
353 BT_DBG("Added hci%u", d->id);
354 }
355
356 read_unlock(&hci_dev_list_lock);
357
Johan Hedbergaee9b212012-02-18 15:07:59 +0200358 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300359 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360
Johan Hedberga38528f2011-01-22 06:46:43 +0200361 kfree(rp);
362
363 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364}
365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200367{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200368 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200369
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200370 settings |= MGMT_SETTING_POWERED;
371 settings |= MGMT_SETTING_CONNECTABLE;
372 settings |= MGMT_SETTING_FAST_CONNECTABLE;
373 settings |= MGMT_SETTING_DISCOVERABLE;
374 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200375
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200376 if (hdev->features[6] & LMP_SIMPLE_PAIR)
377 settings |= MGMT_SETTING_SSP;
Johan 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;
668
Johan Hedberg03811012010-12-08 00:21:06 +0200669 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200670
671 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
672 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
673
674 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200675
676 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200677 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200678
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300679 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200680
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200681 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300682 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200683}
684
685static void mgmt_pending_free(struct pending_cmd *cmd)
686{
687 sock_put(cmd->sk);
688 kfree(cmd->param);
689 kfree(cmd);
690}
691
692static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300693 struct hci_dev *hdev, void *data,
694 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200695{
696 struct pending_cmd *cmd;
697
698 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
699 if (!cmd)
700 return NULL;
701
702 cmd->opcode = opcode;
703 cmd->index = hdev->id;
704
705 cmd->param = kmalloc(len, GFP_ATOMIC);
706 if (!cmd->param) {
707 kfree(cmd);
708 return NULL;
709 }
710
711 if (data)
712 memcpy(cmd->param, data, len);
713
714 cmd->sk = sk;
715 sock_hold(sk);
716
717 list_add(&cmd->list, &hdev->mgmt_pending);
718
719 return cmd;
720}
721
722static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300723 void (*cb)(struct pending_cmd *cmd, void *data),
724 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200725{
726 struct list_head *p, *n;
727
728 list_for_each_safe(p, n, &hdev->mgmt_pending) {
729 struct pending_cmd *cmd;
730
731 cmd = list_entry(p, struct pending_cmd, list);
732
733 if (opcode > 0 && cmd->opcode != opcode)
734 continue;
735
736 cb(cmd, data);
737 }
738}
739
740static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
741{
742 struct pending_cmd *cmd;
743
744 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
745 if (cmd->opcode == opcode)
746 return cmd;
747 }
748
749 return NULL;
750}
751
752static void mgmt_pending_remove(struct pending_cmd *cmd)
753{
754 list_del(&cmd->list);
755 mgmt_pending_free(cmd);
756}
757
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200758static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200759{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200760 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200761
Johan Hedbergaee9b212012-02-18 15:07:59 +0200762 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300763 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200764}
765
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200766static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300767 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200768{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300769 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200770 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200771 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200772
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200773 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200774
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300775 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200776
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100777 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
778 cancel_delayed_work(&hdev->power_off);
779
780 if (cp->val) {
781 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
782 mgmt_powered(hdev, 1);
783 goto failed;
784 }
785 }
786
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200787 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200788 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200789 goto failed;
790 }
791
792 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200793 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300794 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200795 goto failed;
796 }
797
798 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
799 if (!cmd) {
800 err = -ENOMEM;
801 goto failed;
802 }
803
804 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200805 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200806 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200807 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200808
809 err = 0;
810
811failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300812 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200813 return err;
814}
815
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300816static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
817 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200818{
819 struct sk_buff *skb;
820 struct mgmt_hdr *hdr;
821
822 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
823 if (!skb)
824 return -ENOMEM;
825
826 hdr = (void *) skb_put(skb, sizeof(*hdr));
827 hdr->opcode = cpu_to_le16(event);
828 if (hdev)
829 hdr->index = cpu_to_le16(hdev->id);
830 else
831 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
832 hdr->len = cpu_to_le16(data_len);
833
834 if (data)
835 memcpy(skb_put(skb, data_len), data, data_len);
836
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100837 /* Time stamp */
838 __net_timestamp(skb);
839
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200840 hci_send_to_control(skb, skip_sk);
841 kfree_skb(skb);
842
843 return 0;
844}
845
846static int new_settings(struct hci_dev *hdev, struct sock *skip)
847{
848 __le32 ev;
849
850 ev = cpu_to_le32(get_current_settings(hdev));
851
852 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
853}
854
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200855static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300856 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200857{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300858 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200859 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200860 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200861 u8 scan;
862 int err;
863
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200864 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200865
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100866 timeout = get_unaligned_le16(&cp->timeout);
867 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200868 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300869 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200870
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300871 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200872
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200873 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200874 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300875 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200876 goto failed;
877 }
878
879 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
880 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200881 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300882 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200883 goto failed;
884 }
885
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200886 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200887 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300888 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200889 goto failed;
890 }
891
892 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200893 bool changed = false;
894
895 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
896 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
897 changed = true;
898 }
899
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200900 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200901 if (err < 0)
902 goto failed;
903
904 if (changed)
905 err = new_settings(hdev, sk);
906
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200907 goto failed;
908 }
909
910 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100911 if (hdev->discov_timeout > 0) {
912 cancel_delayed_work(&hdev->discov_off);
913 hdev->discov_timeout = 0;
914 }
915
916 if (cp->val && timeout > 0) {
917 hdev->discov_timeout = timeout;
918 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
919 msecs_to_jiffies(hdev->discov_timeout * 1000));
920 }
921
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200922 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200923 goto failed;
924 }
925
926 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
927 if (!cmd) {
928 err = -ENOMEM;
929 goto failed;
930 }
931
932 scan = SCAN_PAGE;
933
934 if (cp->val)
935 scan |= SCAN_INQUIRY;
936 else
937 cancel_delayed_work(&hdev->discov_off);
938
939 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
940 if (err < 0)
941 mgmt_pending_remove(cmd);
942
Johan Hedberg03811012010-12-08 00:21:06 +0200943 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200944 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200945
946failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300947 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200948 return err;
949}
950
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200951static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300952 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200953{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300954 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200955 struct pending_cmd *cmd;
956 u8 scan;
957 int err;
958
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200959 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200960
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300961 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200962
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200963 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200964 bool changed = false;
965
966 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
967 changed = true;
968
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200969 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200970 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200971 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200972 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
973 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
974 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200975
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200976 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200977 if (err < 0)
978 goto failed;
979
980 if (changed)
981 err = new_settings(hdev, sk);
982
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200983 goto failed;
984 }
985
986 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
987 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200988 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300989 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200990 goto failed;
991 }
992
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200993 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200994 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200995 goto failed;
996 }
997
998 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
999 if (!cmd) {
1000 err = -ENOMEM;
1001 goto failed;
1002 }
1003
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001004 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001005 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001006 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001007 scan = 0;
1008
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001009 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1010 hdev->discov_timeout > 0)
1011 cancel_delayed_work(&hdev->discov_off);
1012 }
1013
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001014 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1015 if (err < 0)
1016 mgmt_pending_remove(cmd);
1017
1018failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001019 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001020 return err;
1021}
1022
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001023static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001024 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001025{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001026 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001027 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001028
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001029 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001030
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001031 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032
1033 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001034 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001035 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001036 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001037
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001038 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001039 if (err < 0)
1040 goto failed;
1041
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001042 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001043
1044failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001045 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001046 return err;
1047}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001048
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001049static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1050 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001051{
1052 struct mgmt_mode *cp = data;
1053 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001054 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001055 int err;
1056
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001057 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001058
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001059 hci_dev_lock(hdev);
1060
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001061 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001062 bool changed = false;
1063
1064 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1065 &hdev->dev_flags)) {
1066 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1067 changed = true;
1068 }
1069
1070 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1071 if (err < 0)
1072 goto failed;
1073
1074 if (changed)
1075 err = new_settings(hdev, sk);
1076
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001077 goto failed;
1078 }
1079
1080 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001081 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001082 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001083 goto failed;
1084 }
1085
1086 val = !!cp->val;
1087
1088 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1089 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1090 goto failed;
1091 }
1092
1093 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1094 if (!cmd) {
1095 err = -ENOMEM;
1096 goto failed;
1097 }
1098
1099 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1100 if (err < 0) {
1101 mgmt_pending_remove(cmd);
1102 goto failed;
1103 }
1104
1105failed:
1106 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001107 return err;
1108}
1109
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001110static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001111{
1112 struct mgmt_mode *cp = data;
1113 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001114 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001115 int err;
1116
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001117 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001118
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001119 hci_dev_lock(hdev);
1120
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001121 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001122 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001123 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001124 goto failed;
1125 }
1126
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001127 val = !!cp->val;
1128
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001129 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001130 bool changed = false;
1131
1132 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1133 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1134 changed = true;
1135 }
1136
1137 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1138 if (err < 0)
1139 goto failed;
1140
1141 if (changed)
1142 err = new_settings(hdev, sk);
1143
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001144 goto failed;
1145 }
1146
1147 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001148 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1149 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001150 goto failed;
1151 }
1152
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001153 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1154 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1155 goto failed;
1156 }
1157
1158 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1159 if (!cmd) {
1160 err = -ENOMEM;
1161 goto failed;
1162 }
1163
1164 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1165 if (err < 0) {
1166 mgmt_pending_remove(cmd);
1167 goto failed;
1168 }
1169
1170failed:
1171 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001172 return err;
1173}
1174
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001175static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001176{
1177 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001178
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001179 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001180
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001181 if (!enable_hs)
1182 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001183 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001184
1185 if (cp->val)
1186 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1187 else
1188 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1189
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001190 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001191}
1192
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001193static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001194{
1195 struct mgmt_mode *cp = data;
1196 struct hci_cp_write_le_host_supported hci_cp;
1197 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001198 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001199 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001200
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001201 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001202
Johan Hedberg1de028c2012-02-29 19:55:35 -08001203 hci_dev_lock(hdev);
1204
Johan Hedberg06199cf2012-02-22 16:37:11 +02001205 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001206 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001207 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001208 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001209 }
1210
1211 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001212 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001213
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001214 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001215 bool changed = false;
1216
1217 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1218 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1219 changed = true;
1220 }
1221
1222 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1223 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001224 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001225
1226 if (changed)
1227 err = new_settings(hdev, sk);
1228
Johan Hedberg1de028c2012-02-29 19:55:35 -08001229 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001230 }
1231
1232 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001233 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001234 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001235 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001236 }
1237
1238 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1239 if (!cmd) {
1240 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001241 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001242 }
1243
1244 memset(&hci_cp, 0, sizeof(hci_cp));
1245
1246 if (val) {
1247 hci_cp.le = val;
1248 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1249 }
1250
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001251 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1252 &hci_cp);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001253 if (err < 0) {
1254 mgmt_pending_remove(cmd);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001255 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001256 }
1257
Johan Hedberg1de028c2012-02-29 19:55:35 -08001258unlock:
1259 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001260 return err;
1261}
1262
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001263static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001264{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001265 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001266 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001267 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001268 int err;
1269
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001270 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001271
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001272 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001273
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001274 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001275 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001276 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001277 goto failed;
1278 }
1279
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001280 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1281 if (!uuid) {
1282 err = -ENOMEM;
1283 goto failed;
1284 }
1285
1286 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001287 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001288
1289 list_add(&uuid->list, &hdev->uuids);
1290
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001291 err = update_class(hdev);
1292 if (err < 0)
1293 goto failed;
1294
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001295 err = update_eir(hdev);
1296 if (err < 0)
1297 goto failed;
1298
Johan Hedberg90e70452012-02-23 23:09:40 +02001299 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001300 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001301 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001302 goto failed;
1303 }
1304
1305 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
1306 if (!cmd) {
1307 err = -ENOMEM;
1308 goto failed;
1309 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001310
1311failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001312 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001313 return err;
1314}
1315
Johan Hedberg24b78d02012-02-23 23:24:30 +02001316static bool enable_service_cache(struct hci_dev *hdev)
1317{
1318 if (!hdev_is_powered(hdev))
1319 return false;
1320
1321 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001322 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001323 return true;
1324 }
1325
1326 return false;
1327}
1328
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001329static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1330 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001331{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001332 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001333 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001334 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001335 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 +02001336 int err, found;
1337
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001338 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001339
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001340 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001341
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001342 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001343 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001344 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001345 goto unlock;
1346 }
1347
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001348 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1349 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001350
Johan Hedberg24b78d02012-02-23 23:24:30 +02001351 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001352 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001353 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001354 goto unlock;
1355 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001356
Johan Hedberg9246a862012-02-23 21:33:16 +02001357 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001358 }
1359
1360 found = 0;
1361
1362 list_for_each_safe(p, n, &hdev->uuids) {
1363 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1364
1365 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1366 continue;
1367
1368 list_del(&match->list);
1369 found++;
1370 }
1371
1372 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001373 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001374 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001375 goto unlock;
1376 }
1377
Johan Hedberg9246a862012-02-23 21:33:16 +02001378update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001379 err = update_class(hdev);
1380 if (err < 0)
1381 goto unlock;
1382
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001383 err = update_eir(hdev);
1384 if (err < 0)
1385 goto unlock;
1386
Johan Hedberg90e70452012-02-23 23:09:40 +02001387 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001388 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001389 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001390 goto unlock;
1391 }
1392
1393 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
1394 if (!cmd) {
1395 err = -ENOMEM;
1396 goto unlock;
1397 }
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001398
1399unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001400 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001401 return err;
1402}
1403
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001404static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001405 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001406{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001407 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001408 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001409 int err;
1410
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001411 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001412
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001413 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001414
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001415 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001416 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001417 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001418 goto unlock;
1419 }
1420
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001421 hdev->major_class = cp->major;
1422 hdev->minor_class = cp->minor;
1423
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001424 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001425 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001426 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001427 goto unlock;
1428 }
1429
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001430 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001431 hci_dev_unlock(hdev);
1432 cancel_delayed_work_sync(&hdev->service_cache);
1433 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001434 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001435 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001436
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001437 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001438 if (err < 0)
1439 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001440
Johan Hedberg90e70452012-02-23 23:09:40 +02001441 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001442 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001443 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001444 goto unlock;
1445 }
1446
1447 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
1448 if (!cmd) {
1449 err = -ENOMEM;
1450 goto unlock;
1451 }
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001452
Johan Hedbergb5235a62012-02-21 14:32:24 +02001453unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001454 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001455 return err;
1456}
1457
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001458static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1459 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001460{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001461 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001462 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001463 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001464
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001465 key_count = get_unaligned_le16(&cp->key_count);
1466
Johan Hedberg86742e12011-11-07 23:13:38 +02001467 expected_len = sizeof(*cp) + key_count *
1468 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001469 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001470 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001471 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001472 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001473 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001474 }
1475
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001476 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001477 key_count);
1478
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001479 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001480
1481 hci_link_keys_clear(hdev);
1482
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001483 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001484
1485 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001486 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001487 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001488 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001489
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001490 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001491 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001492
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001493 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001494 key->type, key->pin_len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001495 }
1496
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001497 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001498
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001499 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001500
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001501 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001502}
1503
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001504static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001505 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001506{
1507 struct mgmt_ev_device_unpaired ev;
1508
1509 bacpy(&ev.addr.bdaddr, bdaddr);
1510 ev.addr.type = addr_type;
1511
1512 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001513 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001514}
1515
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001516static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001517 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001518{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001519 struct mgmt_cp_unpair_device *cp = data;
1520 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001521 struct hci_cp_disconnect dc;
1522 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001523 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001524 int err;
1525
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001526 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001527
Johan Hedberga8a1d192011-11-10 15:54:38 +02001528 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001529 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1530 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001531
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001532 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001533 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001534 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001535 goto unlock;
1536 }
1537
Johan Hedberg124f6e32012-02-09 13:50:12 +02001538 if (cp->addr.type == MGMT_ADDR_BREDR)
1539 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1540 else
1541 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001542
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001543 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001544 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001545 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001546 goto unlock;
1547 }
1548
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001549 if (cp->disconnect) {
1550 if (cp->addr.type == MGMT_ADDR_BREDR)
1551 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1552 &cp->addr.bdaddr);
1553 else
1554 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1555 &cp->addr.bdaddr);
1556 } else {
1557 conn = NULL;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001558 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001559
Johan Hedberga8a1d192011-11-10 15:54:38 +02001560 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001561 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001562 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001563 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001564 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001565 }
1566
Johan Hedberg124f6e32012-02-09 13:50:12 +02001567 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001568 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001569 if (!cmd) {
1570 err = -ENOMEM;
1571 goto unlock;
1572 }
1573
1574 put_unaligned_le16(conn->handle, &dc.handle);
1575 dc.reason = 0x13; /* Remote User Terminated Connection */
1576 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1577 if (err < 0)
1578 mgmt_pending_remove(cmd);
1579
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001580unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001581 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001582 return err;
1583}
1584
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001585static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001586 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001587{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001588 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001589 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001590 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001591 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001592 int err;
1593
1594 BT_DBG("");
1595
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001596 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001597
1598 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001599 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001600 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001601 goto failed;
1602 }
1603
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001604 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001605 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001606 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001607 goto failed;
1608 }
1609
Johan Hedberg88c3df12012-02-09 14:27:38 +02001610 if (cp->addr.type == MGMT_ADDR_BREDR)
1611 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1612 else
1613 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001614
Johan Hedberg8962ee72011-01-20 12:40:27 +02001615 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001616 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001617 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001618 goto failed;
1619 }
1620
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001621 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001622 if (!cmd) {
1623 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001624 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001625 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001626
1627 put_unaligned_le16(conn->handle, &dc.handle);
1628 dc.reason = 0x13; /* Remote User Terminated Connection */
1629
1630 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1631 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001632 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001633
1634failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001635 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001636 return err;
1637}
1638
Johan Hedberg48264f02011-11-09 13:58:58 +02001639static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001640{
1641 switch (link_type) {
1642 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001643 switch (addr_type) {
1644 case ADDR_LE_DEV_PUBLIC:
1645 return MGMT_ADDR_LE_PUBLIC;
1646 case ADDR_LE_DEV_RANDOM:
1647 return MGMT_ADDR_LE_RANDOM;
1648 default:
1649 return MGMT_ADDR_INVALID;
1650 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001651 case ACL_LINK:
1652 return MGMT_ADDR_BREDR;
1653 default:
1654 return MGMT_ADDR_INVALID;
1655 }
1656}
1657
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001658static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1659 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001660{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001661 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001662 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001663 size_t rp_len;
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001664 int err;
1665 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001666
1667 BT_DBG("");
1668
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001669 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001670
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001671 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001672 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001673 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001674 goto unlock;
1675 }
1676
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001677 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001678 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1679 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001680 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001681 }
1682
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001683 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001684 rp = kmalloc(rp_len, GFP_ATOMIC);
1685 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001686 err = -ENOMEM;
1687 goto unlock;
1688 }
1689
Johan Hedberg2784eb42011-01-21 13:56:35 +02001690 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001691 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001692 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1693 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001694 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001695 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001696 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1697 continue;
1698 i++;
1699 }
1700
Johan Hedberg60fc5fb2012-02-23 09:52:28 +02001701 put_unaligned_le16(i, &rp->conn_count);
1702
Johan Hedberg4c659c32011-11-07 23:13:39 +02001703 /* Recalculate length in case of filtered SCO connections, etc */
1704 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001705
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001706 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001707 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001708
Johan Hedberga38528f2011-01-22 06:46:43 +02001709 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001710
1711unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001712 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001713 return err;
1714}
1715
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001716static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001717 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001718{
1719 struct pending_cmd *cmd;
1720 int err;
1721
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001722 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001723 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001724 if (!cmd)
1725 return -ENOMEM;
1726
Johan Hedbergd8457692012-02-17 14:24:57 +02001727 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001728 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001729 if (err < 0)
1730 mgmt_pending_remove(cmd);
1731
1732 return err;
1733}
1734
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001735static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001736 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001737{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001738 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001739 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001740 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001741 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001742 int err;
1743
1744 BT_DBG("");
1745
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001746 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001747
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001748 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001749 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001750 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001751 goto failed;
1752 }
1753
Johan Hedbergd8457692012-02-17 14:24:57 +02001754 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001755 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001756 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001757 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001758 goto failed;
1759 }
1760
1761 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001762 struct mgmt_cp_pin_code_neg_reply ncp;
1763
1764 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001765
1766 BT_ERR("PIN code is not 16 bytes long");
1767
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001768 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001769 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001770 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001771 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001772
1773 goto failed;
1774 }
1775
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001776 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001777 if (!cmd) {
1778 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001779 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001780 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001781
Johan Hedbergd8457692012-02-17 14:24:57 +02001782 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001783 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001784 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001785
1786 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1787 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001788 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001789
1790failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001791 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001792 return err;
1793}
1794
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001795static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001796 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001797{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001798 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001799 int err;
1800
1801 BT_DBG("");
1802
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001803 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001804
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001805 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001806 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001807 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001808 goto failed;
1809 }
1810
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001811 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001812
1813failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001814 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001815 return err;
1816}
1817
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001818static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1819 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001820{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001821 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001822
1823 BT_DBG("");
1824
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001825 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001826
1827 hdev->io_capability = cp->io_capability;
1828
1829 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001830 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001831
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001832 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001833
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001834 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1835 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001836}
1837
Johan Hedberge9a416b2011-02-19 12:05:56 -03001838static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1839{
1840 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001841 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001842
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001843 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001844 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1845 continue;
1846
Johan Hedberge9a416b2011-02-19 12:05:56 -03001847 if (cmd->user_data != conn)
1848 continue;
1849
1850 return cmd;
1851 }
1852
1853 return NULL;
1854}
1855
1856static void pairing_complete(struct pending_cmd *cmd, u8 status)
1857{
1858 struct mgmt_rp_pair_device rp;
1859 struct hci_conn *conn = cmd->user_data;
1860
Johan Hedbergba4e5642011-11-11 00:07:34 +02001861 bacpy(&rp.addr.bdaddr, &conn->dst);
1862 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001863
Johan Hedbergaee9b212012-02-18 15:07:59 +02001864 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001865 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001866
1867 /* So we don't get further callbacks for this connection */
1868 conn->connect_cfm_cb = NULL;
1869 conn->security_cfm_cb = NULL;
1870 conn->disconn_cfm_cb = NULL;
1871
1872 hci_conn_put(conn);
1873
Johan Hedberga664b5b2011-02-19 12:06:02 -03001874 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001875}
1876
1877static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1878{
1879 struct pending_cmd *cmd;
1880
1881 BT_DBG("status %u", status);
1882
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001883 cmd = find_pairing(conn);
1884 if (!cmd)
1885 BT_DBG("Unable to find a pending command");
1886 else
Johan Hedberge2113262012-02-18 15:20:03 +02001887 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001888}
1889
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001890static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001891 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001892{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001893 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001894 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001895 struct pending_cmd *cmd;
1896 u8 sec_level, auth_type;
1897 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001898 int err;
1899
1900 BT_DBG("");
1901
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001902 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001903
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001904 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001905 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001906 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001907 goto unlock;
1908 }
1909
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001910 sec_level = BT_SECURITY_MEDIUM;
1911 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001912 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001913 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001914 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001915
Johan Hedbergba4e5642011-11-11 00:07:34 +02001916 if (cp->addr.type == MGMT_ADDR_BREDR)
1917 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001918 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001919 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001920 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001921 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001922
Johan Hedberg1425acb2011-11-11 00:07:35 +02001923 memset(&rp, 0, sizeof(rp));
1924 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1925 rp.addr.type = cp->addr.type;
1926
Ville Tervo30e76272011-02-22 16:10:53 -03001927 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001928 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001929 MGMT_STATUS_CONNECT_FAILED, &rp,
1930 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001931 goto unlock;
1932 }
1933
1934 if (conn->connect_cfm_cb) {
1935 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001936 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001937 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001938 goto unlock;
1939 }
1940
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001941 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001942 if (!cmd) {
1943 err = -ENOMEM;
1944 hci_conn_put(conn);
1945 goto unlock;
1946 }
1947
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001948 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001949 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001950 conn->connect_cfm_cb = pairing_complete_cb;
1951
Johan Hedberge9a416b2011-02-19 12:05:56 -03001952 conn->security_cfm_cb = pairing_complete_cb;
1953 conn->disconn_cfm_cb = pairing_complete_cb;
1954 conn->io_capability = cp->io_cap;
1955 cmd->user_data = conn;
1956
1957 if (conn->state == BT_CONNECTED &&
1958 hci_conn_security(conn, sec_level, auth_type))
1959 pairing_complete(cmd, 0);
1960
1961 err = 0;
1962
1963unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001964 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001965 return err;
1966}
1967
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001968static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1969 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001970{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001971 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001972 struct pending_cmd *cmd;
1973 struct hci_conn *conn;
1974 int err;
1975
1976 BT_DBG("");
1977
Johan Hedberg28424702012-02-02 04:02:29 +02001978 hci_dev_lock(hdev);
1979
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001980 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001981 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001982 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001983 goto unlock;
1984 }
1985
Johan Hedberg28424702012-02-02 04:02:29 +02001986 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1987 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001988 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001989 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001990 goto unlock;
1991 }
1992
1993 conn = cmd->user_data;
1994
1995 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001996 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001997 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001998 goto unlock;
1999 }
2000
2001 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2002
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002003 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002004 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002005unlock:
2006 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002007 return err;
2008}
2009
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002010static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002011 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2012 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002013{
Johan Hedberga5c29682011-02-19 12:05:57 -03002014 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002015 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002016 int err;
2017
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002018 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002019
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002020 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002021 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002022 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002023 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002024 }
2025
Johan Hedberg272d90d2012-02-09 15:26:12 +02002026 if (type == MGMT_ADDR_BREDR)
2027 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2028 else
Brian Gix47c15e22011-11-16 13:53:14 -08002029 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002030
Johan Hedberg272d90d2012-02-09 15:26:12 +02002031 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002032 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002033 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002034 goto done;
2035 }
2036
2037 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002038 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002039 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002040
Brian Gix5fe57d92011-12-21 16:12:13 -08002041 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002042 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002043 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002044 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002045 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002046 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002047
Brian Gix47c15e22011-11-16 13:53:14 -08002048 goto done;
2049 }
2050
Brian Gix0df4c182011-11-16 13:53:13 -08002051 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002052 if (!cmd) {
2053 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002054 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002055 }
2056
Brian Gix0df4c182011-11-16 13:53:13 -08002057 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002058 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2059 struct hci_cp_user_passkey_reply cp;
2060
2061 bacpy(&cp.bdaddr, bdaddr);
2062 cp.passkey = passkey;
2063 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2064 } else
2065 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2066
Johan Hedberga664b5b2011-02-19 12:06:02 -03002067 if (err < 0)
2068 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002069
Brian Gix0df4c182011-11-16 13:53:13 -08002070done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002071 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002072 return err;
2073}
2074
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002075static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2076 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002077{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002078 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002079
2080 BT_DBG("");
2081
2082 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002083 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002084 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002085
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002086 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002087 MGMT_OP_USER_CONFIRM_REPLY,
2088 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002089}
2090
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002091static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002092 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002093{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002094 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002095
2096 BT_DBG("");
2097
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002098 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002099 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2100 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002101}
2102
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002103static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2104 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002105{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002106 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002107
2108 BT_DBG("");
2109
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002110 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002111 MGMT_OP_USER_PASSKEY_REPLY,
2112 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002113}
2114
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002115static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002116 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002117{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002118 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002119
2120 BT_DBG("");
2121
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002122 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002123 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2124 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002125}
2126
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002127static int update_name(struct hci_dev *hdev, const char *name)
2128{
2129 struct hci_cp_write_local_name cp;
2130
2131 memcpy(cp.name, name, sizeof(cp.name));
2132
2133 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2134}
2135
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002136static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002137 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002138{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002139 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002140 struct pending_cmd *cmd;
2141 int err;
2142
2143 BT_DBG("");
2144
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002145 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002146
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002147 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002148
Johan Hedbergb5235a62012-02-21 14:32:24 +02002149 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002150 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002151
2152 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002153 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002154 if (err < 0)
2155 goto failed;
2156
2157 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002158 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002159
Johan Hedbergb5235a62012-02-21 14:32:24 +02002160 goto failed;
2161 }
2162
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002163 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002164 if (!cmd) {
2165 err = -ENOMEM;
2166 goto failed;
2167 }
2168
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002169 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002170 if (err < 0)
2171 mgmt_pending_remove(cmd);
2172
2173failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002174 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002175 return err;
2176}
2177
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002178static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002179 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002180{
Szymon Jancc35938b2011-03-22 13:12:21 +01002181 struct pending_cmd *cmd;
2182 int err;
2183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002184 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002185
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002186 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002187
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002188 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002189 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002190 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002191 goto unlock;
2192 }
2193
2194 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002195 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002196 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002197 goto unlock;
2198 }
2199
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002200 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002201 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002202 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002203 goto unlock;
2204 }
2205
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002206 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002207 if (!cmd) {
2208 err = -ENOMEM;
2209 goto unlock;
2210 }
2211
2212 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2213 if (err < 0)
2214 mgmt_pending_remove(cmd);
2215
2216unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002217 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002218 return err;
2219}
2220
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002221static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002222 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002223{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002224 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002225 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002226 int err;
2227
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002228 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002229
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002230 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002231
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002232 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002233 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002234 MGMT_STATUS_NOT_POWERED, &cp->addr,
2235 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002236 goto unlock;
2237 }
2238
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002239 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002240 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002241 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002242 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002243 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002244 status = 0;
2245
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002246 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002247 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002248
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002249unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002250 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002251 return err;
2252}
2253
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002254static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002255 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002256{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002257 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002258 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002259 int err;
2260
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002261 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002262
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002263 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002264
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002265 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002266 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002267 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2268 MGMT_STATUS_NOT_POWERED, &cp->addr,
2269 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002270 goto unlock;
2271 }
2272
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002273 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002274 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002275 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002276 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002277 status = 0;
2278
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002279 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002280 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002281
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002282unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002283 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002284 return err;
2285}
2286
Andre Guedes5e0452c2012-02-17 20:39:38 -03002287int mgmt_interleaved_discovery(struct hci_dev *hdev)
2288{
2289 int err;
2290
2291 BT_DBG("%s", hdev->name);
2292
2293 hci_dev_lock(hdev);
2294
2295 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2296 if (err < 0)
2297 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2298
2299 hci_dev_unlock(hdev);
2300
2301 return err;
2302}
2303
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002304static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002305 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002306{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002307 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002308 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002309 int err;
2310
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002311 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002312
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002313 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002314
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002315 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002316 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002317 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002318 goto failed;
2319 }
2320
Johan Hedbergff9ef572012-01-04 14:23:45 +02002321 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002322 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002323 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002324 goto failed;
2325 }
2326
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002327 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002328 if (!cmd) {
2329 err = -ENOMEM;
2330 goto failed;
2331 }
2332
Andre Guedes4aab14e2012-02-17 20:39:36 -03002333 hdev->discovery.type = cp->type;
2334
2335 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002336 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002337 if (lmp_bredr_capable(hdev))
2338 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2339 else
2340 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002341 break;
2342
2343 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002344 if (lmp_host_le_capable(hdev))
2345 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002346 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002347 else
2348 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002349 break;
2350
Andre Guedes5e0452c2012-02-17 20:39:38 -03002351 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002352 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2353 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002354 LE_SCAN_WIN,
2355 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002356 else
2357 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002358 break;
2359
Andre Guedesf39799f2012-02-17 20:39:35 -03002360 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002361 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002362 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002363
Johan Hedberg14a53662011-04-27 10:29:56 -04002364 if (err < 0)
2365 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002366 else
2367 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002368
2369failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002370 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002371 return err;
2372}
2373
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002374static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002375 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002376{
Johan Hedbergd9306502012-02-20 23:25:18 +02002377 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002378 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002379 struct hci_cp_remote_name_req_cancel cp;
2380 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002381 int err;
2382
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002383 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002384
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002385 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002386
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002387 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002388 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002389 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2390 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002391 goto unlock;
2392 }
2393
2394 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002395 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002396 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2397 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002398 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002399 }
2400
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002401 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002402 if (!cmd) {
2403 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002404 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002405 }
2406
Andre Guedes343f9352012-02-17 20:39:37 -03002407 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002408 err = hci_cancel_inquiry(hdev);
2409 if (err < 0)
2410 mgmt_pending_remove(cmd);
2411 else
2412 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2413 goto unlock;
2414 }
2415
2416 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2417 if (!e) {
2418 mgmt_pending_remove(cmd);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002419 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002420 &mgmt_cp->type, sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002421 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2422 goto unlock;
2423 }
2424
2425 bacpy(&cp.bdaddr, &e->data.bdaddr);
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002426 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL, sizeof(cp),
2427 &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002428 if (err < 0)
2429 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002430 else
2431 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002432
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002433unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002434 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002435 return err;
2436}
2437
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002438static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002439 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002440{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002441 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002442 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002443 int err;
2444
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002445 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002446
Johan Hedberg561aafb2012-01-04 13:31:59 +02002447 hci_dev_lock(hdev);
2448
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002449 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002450 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002451 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002452 goto failed;
2453 }
2454
Johan Hedberga198e7b2012-02-17 14:27:06 +02002455 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002456 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002457 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002458 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002459 goto failed;
2460 }
2461
2462 if (cp->name_known) {
2463 e->name_state = NAME_KNOWN;
2464 list_del(&e->list);
2465 } else {
2466 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002467 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002468 }
2469
2470 err = 0;
2471
2472failed:
2473 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002474 return err;
2475}
2476
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002477static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002478 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002479{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002480 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002481 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002482 int err;
2483
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002484 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002485
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002486 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002487
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002488 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002489 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002490 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002491 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002492 status = 0;
2493
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002494 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002495 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002496
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002497 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002498
2499 return err;
2500}
2501
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002502static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002503 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002504{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002505 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002506 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002507 int err;
2508
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002509 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002510
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002511 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002512
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002513 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002514 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002515 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002516 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002517 status = 0;
2518
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002519 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002520 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002521
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002522 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002523
2524 return err;
2525}
2526
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002527static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2528 u16 len)
2529{
2530 struct mgmt_cp_set_device_id *cp = data;
2531 int err;
2532
2533 BT_DBG("%s", hdev->name);
2534
2535 hci_dev_lock(hdev);
2536
2537 hdev->devid_source = __le16_to_cpu(cp->source);
2538 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2539 hdev->devid_product = __le16_to_cpu(cp->product);
2540 hdev->devid_version = __le16_to_cpu(cp->version);
2541
2542 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2543
2544 update_eir(hdev);
2545
2546 hci_dev_unlock(hdev);
2547
2548 return err;
2549}
2550
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002551static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002552 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002553{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002554 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002555 struct hci_cp_write_page_scan_activity acp;
2556 u8 type;
2557 int err;
2558
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002559 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002560
Johan Hedberg5400c042012-02-21 16:40:33 +02002561 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002562 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002563 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002564
2565 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002566 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002567 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002568
2569 hci_dev_lock(hdev);
2570
Johan Hedbergf7c68692011-12-15 00:47:36 +02002571 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002572 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002573
2574 /* 22.5 msec page scan interval */
2575 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002576 } else {
2577 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002578
2579 /* default 1.28 sec page scan */
2580 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002581 }
2582
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002583 /* default 11.25 msec page scan window */
2584 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002585
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002586 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2587 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002588 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002589 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002590 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002591 goto done;
2592 }
2593
2594 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2595 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002596 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002597 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002598 goto done;
2599 }
2600
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002601 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002602 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002603done:
2604 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002605 return err;
2606}
2607
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002608static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002609 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002610{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002611 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2612 u16 key_count, expected_len;
2613 int i;
2614
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002615 key_count = get_unaligned_le16(&cp->key_count);
2616
2617 expected_len = sizeof(*cp) + key_count *
2618 sizeof(struct mgmt_ltk_info);
2619 if (expected_len != len) {
2620 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2621 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002622 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002623 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002624 }
2625
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002626 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002627
2628 hci_dev_lock(hdev);
2629
2630 hci_smp_ltks_clear(hdev);
2631
2632 for (i = 0; i < key_count; i++) {
2633 struct mgmt_ltk_info *key = &cp->keys[i];
2634 u8 type;
2635
2636 if (key->master)
2637 type = HCI_SMP_LTK;
2638 else
2639 type = HCI_SMP_LTK_SLAVE;
2640
2641 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002642 type, 0, key->authenticated, key->val,
2643 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002644 }
2645
2646 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002647
2648 return 0;
2649}
2650
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002651struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002652 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2653 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002654 bool var_len;
2655 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002656} mgmt_handlers[] = {
2657 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002658 { read_version, false, MGMT_READ_VERSION_SIZE },
2659 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2660 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2661 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2662 { set_powered, false, MGMT_SETTING_SIZE },
2663 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2664 { set_connectable, false, MGMT_SETTING_SIZE },
2665 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2666 { set_pairable, false, MGMT_SETTING_SIZE },
2667 { set_link_security, false, MGMT_SETTING_SIZE },
2668 { set_ssp, false, MGMT_SETTING_SIZE },
2669 { set_hs, false, MGMT_SETTING_SIZE },
2670 { set_le, false, MGMT_SETTING_SIZE },
2671 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2672 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2673 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2674 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2675 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2676 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2677 { disconnect, false, MGMT_DISCONNECT_SIZE },
2678 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2679 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2680 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2681 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2682 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2683 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2684 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2685 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2686 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2687 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2688 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2689 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2690 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2691 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2692 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2693 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2694 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2695 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2696 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002697 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002698};
2699
2700
Johan Hedberg03811012010-12-08 00:21:06 +02002701int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2702{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002703 void *buf;
2704 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002705 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002706 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002707 struct hci_dev *hdev = NULL;
Johan Hedbergbe22b542012-03-01 22:24:41 +02002708 struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002709 int err;
2710
2711 BT_DBG("got %zu bytes", msglen);
2712
2713 if (msglen < sizeof(*hdr))
2714 return -EINVAL;
2715
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002716 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002717 if (!buf)
2718 return -ENOMEM;
2719
2720 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2721 err = -EFAULT;
2722 goto done;
2723 }
2724
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002725 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002726 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002727 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002728 len = get_unaligned_le16(&hdr->len);
2729
2730 if (len != msglen - sizeof(*hdr)) {
2731 err = -EINVAL;
2732 goto done;
2733 }
2734
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002735 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002736 hdev = hci_dev_get(index);
2737 if (!hdev) {
2738 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002739 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002740 goto done;
2741 }
2742 }
2743
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002744 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2745 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002746 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002747 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002748 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002749 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002750 }
2751
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002752 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2753 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2754 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002755 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002756 goto done;
2757 }
2758
Johan Hedbergbe22b542012-03-01 22:24:41 +02002759 handler = &mgmt_handlers[opcode];
2760
2761 if ((handler->var_len && len < handler->data_len) ||
2762 (!handler->var_len && len != handler->data_len)) {
2763 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002764 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002765 goto done;
2766 }
2767
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002768 if (hdev)
2769 mgmt_init_hdev(sk, hdev);
2770
2771 cp = buf + sizeof(*hdr);
2772
Johan Hedbergbe22b542012-03-01 22:24:41 +02002773 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002774 if (err < 0)
2775 goto done;
2776
Johan Hedberg03811012010-12-08 00:21:06 +02002777 err = msglen;
2778
2779done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002780 if (hdev)
2781 hci_dev_put(hdev);
2782
Johan Hedberg03811012010-12-08 00:21:06 +02002783 kfree(buf);
2784 return err;
2785}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002786
Johan Hedbergb24752f2011-11-03 14:40:33 +02002787static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2788{
2789 u8 *status = data;
2790
2791 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2792 mgmt_pending_remove(cmd);
2793}
2794
Johan Hedberg744cf192011-11-08 20:40:14 +02002795int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002796{
Johan Hedberg744cf192011-11-08 20:40:14 +02002797 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002798}
2799
Johan Hedberg744cf192011-11-08 20:40:14 +02002800int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002801{
Johan Hedberg5f159032012-03-02 03:13:19 +02002802 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002803
Johan Hedberg744cf192011-11-08 20:40:14 +02002804 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002805
Johan Hedberg744cf192011-11-08 20:40:14 +02002806 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002807}
2808
Johan Hedberg73f22f62010-12-29 16:00:25 +02002809struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002810 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002811 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002812 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002813};
2814
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002815static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002816{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002817 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002818
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002819 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002820
2821 list_del(&cmd->list);
2822
2823 if (match->sk == NULL) {
2824 match->sk = cmd->sk;
2825 sock_hold(match->sk);
2826 }
2827
2828 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002829}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002830
Johan Hedberg744cf192011-11-08 20:40:14 +02002831int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002832{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002833 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002834 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002835
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002836 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2837 return 0;
2838
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002839 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002840
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002841 if (powered) {
2842 u8 scan = 0;
2843
2844 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2845 scan |= SCAN_PAGE;
2846 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2847 scan |= SCAN_INQUIRY;
2848
2849 if (scan)
2850 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002851
2852 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002853 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002854 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002855 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002856 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002857 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002858 }
2859
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002860 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002861
2862 if (match.sk)
2863 sock_put(match.sk);
2864
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002865 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002866}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002867
Johan Hedberg744cf192011-11-08 20:40:14 +02002868int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002869{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002870 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002871 bool changed = false;
2872 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002873
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002874 if (discoverable) {
2875 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2876 changed = true;
2877 } else {
2878 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2879 changed = true;
2880 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002881
Johan Hedberged9b5f22012-02-21 20:47:06 +02002882 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002883 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002884
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002885 if (changed)
2886 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002887
Johan Hedberg73f22f62010-12-29 16:00:25 +02002888 if (match.sk)
2889 sock_put(match.sk);
2890
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002891 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002892}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002893
Johan Hedberg744cf192011-11-08 20:40:14 +02002894int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002895{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002896 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002897 bool changed = false;
2898 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002899
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002900 if (connectable) {
2901 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2902 changed = true;
2903 } else {
2904 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2905 changed = true;
2906 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002907
Johan Hedberged9b5f22012-02-21 20:47:06 +02002908 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002909 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002910
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002911 if (changed)
2912 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002913
2914 if (match.sk)
2915 sock_put(match.sk);
2916
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002917 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002918}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002919
Johan Hedberg744cf192011-11-08 20:40:14 +02002920int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002921{
Johan Hedbergca69b792011-11-11 18:10:00 +02002922 u8 mgmt_err = mgmt_status(status);
2923
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002924 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002925 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002926 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002927
2928 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002929 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002930 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002931
2932 return 0;
2933}
2934
Vishal Agarwal745c0ce2012-04-13 17:43:22 +05302935int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002936{
Johan Hedberg86742e12011-11-07 23:13:38 +02002937 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002938
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002939 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002940
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002941 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002942 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2943 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002944 ev.key.type = key->type;
2945 memcpy(ev.key.val, key->val, 16);
2946 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002947
Johan Hedberg744cf192011-11-08 20:40:14 +02002948 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002949}
Johan Hedbergf7520542011-01-20 12:34:39 +02002950
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002951int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2952{
2953 struct mgmt_ev_new_long_term_key ev;
2954
2955 memset(&ev, 0, sizeof(ev));
2956
2957 ev.store_hint = persistent;
2958 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2959 ev.key.addr.type = key->bdaddr_type;
2960 ev.key.authenticated = key->authenticated;
2961 ev.key.enc_size = key->enc_size;
2962 ev.key.ediv = key->ediv;
2963
2964 if (key->type == HCI_SMP_LTK)
2965 ev.key.master = 1;
2966
2967 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2968 memcpy(ev.key.val, key->val, sizeof(key->val));
2969
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002970 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2971 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002972}
2973
Johan Hedbergafc747a2012-01-15 18:11:07 +02002974int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002975 u8 addr_type, u32 flags, u8 *name, u8 name_len,
2976 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002977{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002978 char buf[512];
2979 struct mgmt_ev_device_connected *ev = (void *) buf;
2980 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002981
Johan Hedbergb644ba32012-01-17 21:48:47 +02002982 bacpy(&ev->addr.bdaddr, bdaddr);
2983 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002984
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002985 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002986
Johan Hedbergb644ba32012-01-17 21:48:47 +02002987 if (name_len > 0)
2988 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002989 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002990
2991 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08002992 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002993 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02002994
2995 put_unaligned_le16(eir_len, &ev->eir_len);
2996
2997 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002998 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002999}
3000
Johan Hedberg8962ee72011-01-20 12:40:27 +02003001static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3002{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003003 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003004 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003005 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003006
Johan Hedberg88c3df12012-02-09 14:27:38 +02003007 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3008 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003009
Johan Hedbergaee9b212012-02-18 15:07:59 +02003010 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003011 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003012
3013 *sk = cmd->sk;
3014 sock_hold(*sk);
3015
Johan Hedberga664b5b2011-02-19 12:06:02 -03003016 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003017}
3018
Johan Hedberg124f6e32012-02-09 13:50:12 +02003019static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003020{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003021 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003022 struct mgmt_cp_unpair_device *cp = cmd->param;
3023 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003024
3025 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003026 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3027 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003028
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003029 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3030
Johan Hedbergaee9b212012-02-18 15:07:59 +02003031 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003032
3033 mgmt_pending_remove(cmd);
3034}
3035
Johan Hedbergafc747a2012-01-15 18:11:07 +02003036int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003037 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003038{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003039 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003040 struct sock *sk = NULL;
3041 int err;
3042
Johan Hedberg744cf192011-11-08 20:40:14 +02003043 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003044
Johan Hedbergf7520542011-01-20 12:34:39 +02003045 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003046 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003047
Johan Hedbergafc747a2012-01-15 18:11:07 +02003048 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003049 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003050
3051 if (sk)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003052 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003053
Johan Hedberg124f6e32012-02-09 13:50:12 +02003054 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003055 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003056
Johan Hedberg8962ee72011-01-20 12:40:27 +02003057 return err;
3058}
3059
Johan Hedberg88c3df12012-02-09 14:27:38 +02003060int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003061 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003062{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003063 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003064 struct pending_cmd *cmd;
3065 int err;
3066
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003067 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003068 if (!cmd)
3069 return -ENOENT;
3070
Johan Hedberg88c3df12012-02-09 14:27:38 +02003071 bacpy(&rp.addr.bdaddr, bdaddr);
3072 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003073
Johan Hedberg88c3df12012-02-09 14:27:38 +02003074 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003075 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003076
Johan Hedberga664b5b2011-02-19 12:06:02 -03003077 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003078
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003079 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3080 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003081 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003082}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003083
Johan Hedberg48264f02011-11-09 13:58:58 +02003084int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003085 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003086{
3087 struct mgmt_ev_connect_failed ev;
3088
Johan Hedberg4c659c32011-11-07 23:13:39 +02003089 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003090 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003091 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003092
Johan Hedberg744cf192011-11-08 20:40:14 +02003093 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003094}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003095
Johan Hedberg744cf192011-11-08 20:40:14 +02003096int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003097{
3098 struct mgmt_ev_pin_code_request ev;
3099
Johan Hedbergd8457692012-02-17 14:24:57 +02003100 bacpy(&ev.addr.bdaddr, bdaddr);
3101 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003102 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003103
Johan Hedberg744cf192011-11-08 20:40:14 +02003104 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003105 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003106}
3107
Johan Hedberg744cf192011-11-08 20:40:14 +02003108int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003109 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003110{
3111 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003112 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003113 int err;
3114
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003115 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003116 if (!cmd)
3117 return -ENOENT;
3118
Johan Hedbergd8457692012-02-17 14:24:57 +02003119 bacpy(&rp.addr.bdaddr, bdaddr);
3120 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003121
Johan Hedbergaee9b212012-02-18 15:07:59 +02003122 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003123 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003124
Johan Hedberga664b5b2011-02-19 12:06:02 -03003125 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003126
3127 return err;
3128}
3129
Johan Hedberg744cf192011-11-08 20:40:14 +02003130int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003131 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003132{
3133 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003134 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003135 int err;
3136
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003137 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003138 if (!cmd)
3139 return -ENOENT;
3140
Johan Hedbergd8457692012-02-17 14:24:57 +02003141 bacpy(&rp.addr.bdaddr, bdaddr);
3142 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003143
Johan Hedbergaee9b212012-02-18 15:07:59 +02003144 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003145 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003146
Johan Hedberga664b5b2011-02-19 12:06:02 -03003147 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003148
3149 return err;
3150}
Johan Hedberga5c29682011-02-19 12:05:57 -03003151
Johan Hedberg744cf192011-11-08 20:40:14 +02003152int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003153 u8 link_type, u8 addr_type, __le32 value,
3154 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003155{
3156 struct mgmt_ev_user_confirm_request ev;
3157
Johan Hedberg744cf192011-11-08 20:40:14 +02003158 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003159
Johan Hedberg272d90d2012-02-09 15:26:12 +02003160 bacpy(&ev.addr.bdaddr, bdaddr);
3161 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003162 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003163 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003164
Johan Hedberg744cf192011-11-08 20:40:14 +02003165 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003166 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003167}
3168
Johan Hedberg272d90d2012-02-09 15:26:12 +02003169int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3170 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003171{
3172 struct mgmt_ev_user_passkey_request ev;
3173
3174 BT_DBG("%s", hdev->name);
3175
Johan Hedberg272d90d2012-02-09 15:26:12 +02003176 bacpy(&ev.addr.bdaddr, bdaddr);
3177 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003178
3179 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003180 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003181}
3182
Brian Gix0df4c182011-11-16 13:53:13 -08003183static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003184 u8 link_type, u8 addr_type, u8 status,
3185 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003186{
3187 struct pending_cmd *cmd;
3188 struct mgmt_rp_user_confirm_reply rp;
3189 int err;
3190
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003191 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003192 if (!cmd)
3193 return -ENOENT;
3194
Johan Hedberg272d90d2012-02-09 15:26:12 +02003195 bacpy(&rp.addr.bdaddr, bdaddr);
3196 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003197 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003198 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003199
Johan Hedberga664b5b2011-02-19 12:06:02 -03003200 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003201
3202 return err;
3203}
3204
Johan Hedberg744cf192011-11-08 20:40:14 +02003205int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003206 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003207{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003208 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003209 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003210}
3211
Johan Hedberg272d90d2012-02-09 15:26:12 +02003212int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003213 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003214{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003215 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003216 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003217}
Johan Hedberg2a611692011-02-19 12:06:00 -03003218
Brian Gix604086b2011-11-23 08:28:33 -08003219int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003220 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003221{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003222 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003223 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003224}
3225
Johan Hedberg272d90d2012-02-09 15:26:12 +02003226int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003227 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003228{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003229 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003230 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003231}
3232
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003233int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003234 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003235{
3236 struct mgmt_ev_auth_failed ev;
3237
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003238 bacpy(&ev.addr.bdaddr, bdaddr);
3239 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003240 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003241
Johan Hedberg744cf192011-11-08 20:40:14 +02003242 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003243}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003244
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003245int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3246{
3247 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003248 bool changed = false;
3249 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003250
3251 if (status) {
3252 u8 mgmt_err = mgmt_status(status);
3253 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003254 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003255 return 0;
3256 }
3257
Johan Hedberg47990ea2012-02-22 11:58:37 +02003258 if (test_bit(HCI_AUTH, &hdev->flags)) {
3259 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3260 changed = true;
3261 } else {
3262 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3263 changed = true;
3264 }
3265
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003266 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003267 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003268
Johan Hedberg47990ea2012-02-22 11:58:37 +02003269 if (changed)
3270 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003271
3272 if (match.sk)
3273 sock_put(match.sk);
3274
3275 return err;
3276}
3277
Johan Hedbergcacaf522012-02-21 00:52:42 +02003278static int clear_eir(struct hci_dev *hdev)
3279{
3280 struct hci_cp_write_eir cp;
3281
3282 if (!(hdev->features[6] & LMP_EXT_INQ))
3283 return 0;
3284
Johan Hedbergc80da272012-02-22 15:38:48 +02003285 memset(hdev->eir, 0, sizeof(hdev->eir));
3286
Johan Hedbergcacaf522012-02-21 00:52:42 +02003287 memset(&cp, 0, sizeof(cp));
3288
3289 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3290}
3291
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003292int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003293{
3294 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003295 bool changed = false;
3296 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003297
3298 if (status) {
3299 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003300
3301 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003302 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003303 err = new_settings(hdev, NULL);
3304
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003305 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3306 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003307
3308 return err;
3309 }
3310
3311 if (enable) {
3312 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3313 changed = true;
3314 } else {
3315 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3316 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003317 }
3318
3319 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3320
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003321 if (changed)
3322 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003323
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003324 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003325 sock_put(match.sk);
3326
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003327 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3328 update_eir(hdev);
3329 else
3330 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003331
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003332 return err;
3333}
3334
Johan Hedberg90e70452012-02-23 23:09:40 +02003335static void class_rsp(struct pending_cmd *cmd, void *data)
3336{
3337 struct cmd_lookup *match = data;
3338
3339 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003340 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003341
3342 list_del(&cmd->list);
3343
3344 if (match->sk == NULL) {
3345 match->sk = cmd->sk;
3346 sock_hold(match->sk);
3347 }
3348
3349 mgmt_pending_free(cmd);
3350}
3351
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003352int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003353 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003354{
Johan Hedberg90e70452012-02-23 23:09:40 +02003355 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3356 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003357
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003358 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3359
Johan Hedberg90e70452012-02-23 23:09:40 +02003360 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3361 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3362 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3363
3364 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003365 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3366 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003367
3368 if (match.sk)
3369 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003370
3371 return err;
3372}
3373
Johan Hedberg744cf192011-11-08 20:40:14 +02003374int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003375{
3376 struct pending_cmd *cmd;
3377 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003378 bool changed = false;
3379 int err = 0;
3380
3381 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3382 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3383 changed = true;
3384 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003385
3386 memset(&ev, 0, sizeof(ev));
3387 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003388 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003389
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003390 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003391 if (!cmd)
3392 goto send_event;
3393
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003394 /* Always assume that either the short or the complete name has
3395 * changed if there was a pending mgmt command */
3396 changed = true;
3397
Johan Hedbergb312b1612011-03-16 14:29:37 +02003398 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003399 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003400 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003401 goto failed;
3402 }
3403
Johan Hedbergaee9b212012-02-18 15:07:59 +02003404 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003405 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003406 if (err < 0)
3407 goto failed;
3408
3409send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003410 if (changed)
3411 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003412 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003413
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003414 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003415
3416failed:
3417 if (cmd)
3418 mgmt_pending_remove(cmd);
3419 return err;
3420}
Szymon Jancc35938b2011-03-22 13:12:21 +01003421
Johan Hedberg744cf192011-11-08 20:40:14 +02003422int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003423 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003424{
3425 struct pending_cmd *cmd;
3426 int err;
3427
Johan Hedberg744cf192011-11-08 20:40:14 +02003428 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003429
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003430 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003431 if (!cmd)
3432 return -ENOENT;
3433
3434 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003435 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3436 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003437 } else {
3438 struct mgmt_rp_read_local_oob_data rp;
3439
3440 memcpy(rp.hash, hash, sizeof(rp.hash));
3441 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3442
Johan Hedberg744cf192011-11-08 20:40:14 +02003443 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003444 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3445 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003446 }
3447
3448 mgmt_pending_remove(cmd);
3449
3450 return err;
3451}
Johan Hedberge17acd42011-03-30 23:57:16 +03003452
Johan Hedberg06199cf2012-02-22 16:37:11 +02003453int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3454{
3455 struct cmd_lookup match = { NULL, hdev };
3456 bool changed = false;
3457 int err = 0;
3458
3459 if (status) {
3460 u8 mgmt_err = mgmt_status(status);
3461
3462 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003463 &hdev->dev_flags))
3464 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003465
3466 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003467 cmd_status_rsp, &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003468
3469 return err;
3470 }
3471
3472 if (enable) {
3473 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3474 changed = true;
3475 } else {
3476 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3477 changed = true;
3478 }
3479
3480 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3481
3482 if (changed)
3483 err = new_settings(hdev, match.sk);
3484
3485 if (match.sk)
3486 sock_put(match.sk);
3487
3488 return err;
3489}
3490
Johan Hedberg48264f02011-11-09 13:58:58 +02003491int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003492 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3493 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003494{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003495 char buf[512];
3496 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003497 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003498
Johan Hedberg1dc06092012-01-15 21:01:23 +02003499 /* Leave 5 bytes for a potential CoD field */
3500 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003501 return -EINVAL;
3502
Johan Hedberg1dc06092012-01-15 21:01:23 +02003503 memset(buf, 0, sizeof(buf));
3504
Johan Hedberge319d2e2012-01-15 19:51:59 +02003505 bacpy(&ev->addr.bdaddr, bdaddr);
3506 ev->addr.type = link_to_mgmt(link_type, addr_type);
3507 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003508 if (cfm_name)
3509 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003510 if (!ssp)
3511 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003512
Johan Hedberg1dc06092012-01-15 21:01:23 +02003513 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003514 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003515
Johan Hedberg1dc06092012-01-15 21:01:23 +02003516 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3517 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003518 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003519
3520 put_unaligned_le16(eir_len, &ev->eir_len);
3521
3522 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003523
Johan Hedberge319d2e2012-01-15 19:51:59 +02003524 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003525}
Johan Hedberga88a9652011-03-30 13:18:12 +03003526
Johan Hedbergb644ba32012-01-17 21:48:47 +02003527int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003528 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003529{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003530 struct mgmt_ev_device_found *ev;
3531 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3532 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003533
Johan Hedbergb644ba32012-01-17 21:48:47 +02003534 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003535
Johan Hedbergb644ba32012-01-17 21:48:47 +02003536 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003537
Johan Hedbergb644ba32012-01-17 21:48:47 +02003538 bacpy(&ev->addr.bdaddr, bdaddr);
3539 ev->addr.type = link_to_mgmt(link_type, addr_type);
3540 ev->rssi = rssi;
3541
3542 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003543 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003544
3545 put_unaligned_le16(eir_len, &ev->eir_len);
3546
Johan Hedberg053c7e02012-02-04 00:06:00 +02003547 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003548 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003549}
Johan Hedberg314b2382011-04-27 10:29:57 -04003550
Andre Guedes7a135102011-11-09 17:14:25 -03003551int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003552{
3553 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003554 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003555 int err;
3556
Andre Guedes203159d2012-02-13 15:41:01 -03003557 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3558
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003559 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003560 if (!cmd)
3561 return -ENOENT;
3562
Johan Hedbergf808e162012-02-19 12:52:07 +02003563 type = hdev->discovery.type;
3564
3565 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003566 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003567 mgmt_pending_remove(cmd);
3568
3569 return err;
3570}
3571
Andre Guedese6d465c2011-11-09 17:14:26 -03003572int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3573{
3574 struct pending_cmd *cmd;
3575 int err;
3576
3577 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3578 if (!cmd)
3579 return -ENOENT;
3580
Johan Hedbergd9306502012-02-20 23:25:18 +02003581 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003582 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003583 mgmt_pending_remove(cmd);
3584
3585 return err;
3586}
Johan Hedberg314b2382011-04-27 10:29:57 -04003587
Johan Hedberg744cf192011-11-08 20:40:14 +02003588int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003589{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003590 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003591 struct pending_cmd *cmd;
3592
Andre Guedes343fb142011-11-22 17:14:19 -03003593 BT_DBG("%s discovering %u", hdev->name, discovering);
3594
Johan Hedberg164a6e72011-11-01 17:06:44 +02003595 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003596 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003597 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003598 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003599
3600 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003601 u8 type = hdev->discovery.type;
3602
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003603 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3604 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003605 mgmt_pending_remove(cmd);
3606 }
3607
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003608 memset(&ev, 0, sizeof(ev));
3609 ev.type = hdev->discovery.type;
3610 ev.discovering = discovering;
3611
3612 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003613}
Antti Julku5e762442011-08-25 16:48:02 +03003614
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003615int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003616{
3617 struct pending_cmd *cmd;
3618 struct mgmt_ev_device_blocked ev;
3619
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003620 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003621
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003622 bacpy(&ev.addr.bdaddr, bdaddr);
3623 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003624
Johan Hedberg744cf192011-11-08 20:40:14 +02003625 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003626 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003627}
3628
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003629int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003630{
3631 struct pending_cmd *cmd;
3632 struct mgmt_ev_device_unblocked ev;
3633
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003634 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003635
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003636 bacpy(&ev.addr.bdaddr, bdaddr);
3637 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003638
Johan Hedberg744cf192011-11-08 20:40:14 +02003639 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003640 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003641}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003642
3643module_param(enable_hs, bool, 0644);
3644MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3645
3646module_param(enable_le, bool, 0644);
3647MODULE_PARM_DESC(enable_le, "Enable Low Energy support");