blob: 632d43d0980b4328d2737d244b88b117e9c1b9c8 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
38bool enable_le;
39
Johan Hedberg2da9c552012-02-17 14:39:28 +020040#define MGMT_VERSION 1
Marcel Holtmann053262d2012-03-27 18:49:02 +020041#define MGMT_REVISION 1
Johan Hedberg02d98122010-12-13 21:07:04 +020042
Johan Hedberge70bb2e2012-02-13 16:59:33 +020043static const u16 mgmt_commands[] = {
44 MGMT_OP_READ_INDEX_LIST,
45 MGMT_OP_READ_INFO,
46 MGMT_OP_SET_POWERED,
47 MGMT_OP_SET_DISCOVERABLE,
48 MGMT_OP_SET_CONNECTABLE,
49 MGMT_OP_SET_FAST_CONNECTABLE,
50 MGMT_OP_SET_PAIRABLE,
51 MGMT_OP_SET_LINK_SECURITY,
52 MGMT_OP_SET_SSP,
53 MGMT_OP_SET_HS,
54 MGMT_OP_SET_LE,
55 MGMT_OP_SET_DEV_CLASS,
56 MGMT_OP_SET_LOCAL_NAME,
57 MGMT_OP_ADD_UUID,
58 MGMT_OP_REMOVE_UUID,
59 MGMT_OP_LOAD_LINK_KEYS,
60 MGMT_OP_LOAD_LONG_TERM_KEYS,
61 MGMT_OP_DISCONNECT,
62 MGMT_OP_GET_CONNECTIONS,
63 MGMT_OP_PIN_CODE_REPLY,
64 MGMT_OP_PIN_CODE_NEG_REPLY,
65 MGMT_OP_SET_IO_CAPABILITY,
66 MGMT_OP_PAIR_DEVICE,
67 MGMT_OP_CANCEL_PAIR_DEVICE,
68 MGMT_OP_UNPAIR_DEVICE,
69 MGMT_OP_USER_CONFIRM_REPLY,
70 MGMT_OP_USER_CONFIRM_NEG_REPLY,
71 MGMT_OP_USER_PASSKEY_REPLY,
72 MGMT_OP_USER_PASSKEY_NEG_REPLY,
73 MGMT_OP_READ_LOCAL_OOB_DATA,
74 MGMT_OP_ADD_REMOTE_OOB_DATA,
75 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
76 MGMT_OP_START_DISCOVERY,
77 MGMT_OP_STOP_DISCOVERY,
78 MGMT_OP_CONFIRM_NAME,
79 MGMT_OP_BLOCK_DEVICE,
80 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070081 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020082};
83
84static const u16 mgmt_events[] = {
85 MGMT_EV_CONTROLLER_ERROR,
86 MGMT_EV_INDEX_ADDED,
87 MGMT_EV_INDEX_REMOVED,
88 MGMT_EV_NEW_SETTINGS,
89 MGMT_EV_CLASS_OF_DEV_CHANGED,
90 MGMT_EV_LOCAL_NAME_CHANGED,
91 MGMT_EV_NEW_LINK_KEY,
92 MGMT_EV_NEW_LONG_TERM_KEY,
93 MGMT_EV_DEVICE_CONNECTED,
94 MGMT_EV_DEVICE_DISCONNECTED,
95 MGMT_EV_CONNECT_FAILED,
96 MGMT_EV_PIN_CODE_REQUEST,
97 MGMT_EV_USER_CONFIRM_REQUEST,
98 MGMT_EV_USER_PASSKEY_REQUEST,
99 MGMT_EV_AUTH_FAILED,
100 MGMT_EV_DEVICE_FOUND,
101 MGMT_EV_DISCOVERING,
102 MGMT_EV_DEVICE_BLOCKED,
103 MGMT_EV_DEVICE_UNBLOCKED,
104 MGMT_EV_DEVICE_UNPAIRED,
105};
106
Andre Guedes3fd24152012-02-03 17:48:01 -0300107/*
108 * These LE scan and inquiry parameters were chosen according to LE General
109 * Discovery Procedure specification.
110 */
111#define LE_SCAN_TYPE 0x01
112#define LE_SCAN_WIN 0x12
113#define LE_SCAN_INT 0x12
114#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300115#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300116
Andre Guedese8777522012-02-03 17:48:02 -0300117#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300118#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300119
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800120#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200121
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200122#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
123 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
124
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200125struct pending_cmd {
126 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200127 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200128 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100129 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200130 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300131 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200132};
133
Johan Hedbergca69b792011-11-11 18:10:00 +0200134/* HCI to MGMT error code conversion table */
135static u8 mgmt_status_table[] = {
136 MGMT_STATUS_SUCCESS,
137 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
138 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
139 MGMT_STATUS_FAILED, /* Hardware Failure */
140 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
141 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
142 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
143 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
144 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
146 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
147 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
148 MGMT_STATUS_BUSY, /* Command Disallowed */
149 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
150 MGMT_STATUS_REJECTED, /* Rejected Security */
151 MGMT_STATUS_REJECTED, /* Rejected Personal */
152 MGMT_STATUS_TIMEOUT, /* Host Timeout */
153 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
154 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
155 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
156 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
157 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
158 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
159 MGMT_STATUS_BUSY, /* Repeated Attempts */
160 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
161 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
162 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
163 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
164 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
165 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
166 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
167 MGMT_STATUS_FAILED, /* Unspecified Error */
168 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
169 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
170 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
171 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
172 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
173 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
174 MGMT_STATUS_FAILED, /* Unit Link Key Used */
175 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
176 MGMT_STATUS_TIMEOUT, /* Instant Passed */
177 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
178 MGMT_STATUS_FAILED, /* Transaction Collision */
179 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
180 MGMT_STATUS_REJECTED, /* QoS Rejected */
181 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
182 MGMT_STATUS_REJECTED, /* Insufficient Security */
183 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
184 MGMT_STATUS_BUSY, /* Role Switch Pending */
185 MGMT_STATUS_FAILED, /* Slot Violation */
186 MGMT_STATUS_FAILED, /* Role Switch Failed */
187 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
188 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
189 MGMT_STATUS_BUSY, /* Host Busy Pairing */
190 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
191 MGMT_STATUS_BUSY, /* Controller Busy */
192 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
193 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
194 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
195 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
196 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
197};
198
199static u8 mgmt_status(u8 hci_status)
200{
201 if (hci_status < ARRAY_SIZE(mgmt_status_table))
202 return mgmt_status_table[hci_status];
203
204 return MGMT_STATUS_FAILED;
205}
206
Szymon Janc4e51eae2011-02-25 19:05:48 +0100207static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200208{
209 struct sk_buff *skb;
210 struct mgmt_hdr *hdr;
211 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300212 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200213
Szymon Janc34eb5252011-02-28 14:10:08 +0100214 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200215
216 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
217 if (!skb)
218 return -ENOMEM;
219
220 hdr = (void *) skb_put(skb, sizeof(*hdr));
221
222 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100223 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200224 hdr->len = cpu_to_le16(sizeof(*ev));
225
226 ev = (void *) skb_put(skb, sizeof(*ev));
227 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200228 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200229
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300230 err = sock_queue_rcv_skb(sk, skb);
231 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200232 kfree_skb(skb);
233
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300234 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200235}
236
Johan Hedbergaee9b212012-02-18 15:07:59 +0200237static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300238 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200239{
240 struct sk_buff *skb;
241 struct mgmt_hdr *hdr;
242 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300243 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200244
245 BT_DBG("sock %p", sk);
246
Johan Hedberga38528f2011-01-22 06:46:43 +0200247 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200248 if (!skb)
249 return -ENOMEM;
250
251 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200252
Johan Hedberg02d98122010-12-13 21:07:04 +0200253 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100254 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200255 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200256
Johan Hedberga38528f2011-01-22 06:46:43 +0200257 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200258 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200259 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100260
261 if (rp)
262 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200263
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300264 err = sock_queue_rcv_skb(sk, skb);
265 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200266 kfree_skb(skb);
267
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100268 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200269}
270
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300271static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
272 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200273{
274 struct mgmt_rp_read_version rp;
275
276 BT_DBG("sock %p", sk);
277
278 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200279 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200280
Johan Hedbergaee9b212012-02-18 15:07:59 +0200281 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300282 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200283}
284
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300285static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
286 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200287{
288 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200289 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
290 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200291 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200292 size_t rp_size;
293 int i, err;
294
295 BT_DBG("sock %p", sk);
296
297 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
298
299 rp = kmalloc(rp_size, GFP_KERNEL);
300 if (!rp)
301 return -ENOMEM;
302
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200303 rp->num_commands = __constant_cpu_to_le16(num_commands);
304 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200305
306 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
307 put_unaligned_le16(mgmt_commands[i], opcode);
308
309 for (i = 0; i < num_events; i++, opcode++)
310 put_unaligned_le16(mgmt_events[i], opcode);
311
Johan Hedbergaee9b212012-02-18 15:07:59 +0200312 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300313 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200314 kfree(rp);
315
316 return err;
317}
318
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300319static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
320 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200321{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200322 struct mgmt_rp_read_index_list *rp;
323 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200324 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200325 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200326 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200327 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200328
329 BT_DBG("sock %p", sk);
330
331 read_lock(&hci_dev_list_lock);
332
333 count = 0;
334 list_for_each(p, &hci_dev_list) {
335 count++;
336 }
337
Johan Hedberga38528f2011-01-22 06:46:43 +0200338 rp_len = sizeof(*rp) + (2 * count);
339 rp = kmalloc(rp_len, GFP_ATOMIC);
340 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100341 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200342 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100343 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200344
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200345 rp->num_controllers = cpu_to_le16(count);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200346
347 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200348 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200349 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200350 continue;
351
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200352 rp->index[i++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200353 BT_DBG("Added hci%u", d->id);
354 }
355
356 read_unlock(&hci_dev_list_lock);
357
Johan Hedbergaee9b212012-02-18 15:07:59 +0200358 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300359 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200360
Johan Hedberga38528f2011-01-22 06:46:43 +0200361 kfree(rp);
362
363 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200364}
365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200367{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200368 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200369
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200370 settings |= MGMT_SETTING_POWERED;
371 settings |= MGMT_SETTING_CONNECTABLE;
372 settings |= MGMT_SETTING_FAST_CONNECTABLE;
373 settings |= MGMT_SETTING_DISCOVERABLE;
374 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200375
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200376 if (hdev->features[6] & LMP_SIMPLE_PAIR)
377 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200378
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200379 if (!(hdev->features[4] & LMP_NO_BREDR)) {
380 settings |= MGMT_SETTING_BREDR;
381 settings |= MGMT_SETTING_LINK_SECURITY;
382 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200383
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100384 if (enable_hs)
385 settings |= MGMT_SETTING_HS;
386
387 if (enable_le) {
388 if (hdev->features[4] & LMP_LE)
389 settings |= MGMT_SETTING_LE;
390 }
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200391
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200392 return settings;
393}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200394
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200395static u32 get_current_settings(struct hci_dev *hdev)
396{
397 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200398
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200399 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100400 settings |= MGMT_SETTING_POWERED;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_CONNECTABLE;
404
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200405 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_DISCOVERABLE;
407
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200408 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200409 settings |= MGMT_SETTING_PAIRABLE;
410
411 if (!(hdev->features[4] & LMP_NO_BREDR))
412 settings |= MGMT_SETTING_BREDR;
413
Johan Hedberg06199cf2012-02-22 16:37:11 +0200414 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200416
Johan Hedberg47990ea2012-02-22 11:58:37 +0200417 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200419
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200420 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200421 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200422
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200423 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
424 settings |= MGMT_SETTING_HS;
425
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200426 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200427}
428
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300429#define PNP_INFO_SVCLASS_ID 0x1200
430
431static u8 bluetooth_base_uuid[] = {
432 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
433 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
434};
435
436static u16 get_uuid16(u8 *uuid128)
437{
438 u32 val;
439 int i;
440
441 for (i = 0; i < 12; i++) {
442 if (bluetooth_base_uuid[i] != uuid128[i])
443 return 0;
444 }
445
Andrei Emeltchenko3e9fb6d2012-03-20 10:32:25 +0200446 val = get_unaligned_le32(&uuid128[12]);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300447 if (val > 0xffff)
448 return 0;
449
450 return (u16) val;
451}
452
453static void create_eir(struct hci_dev *hdev, u8 *data)
454{
455 u8 *ptr = data;
456 u16 eir_len = 0;
457 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
458 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200459 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300460 size_t name_len;
461
462 name_len = strlen(hdev->dev_name);
463
464 if (name_len > 0) {
465 /* EIR Data type */
466 if (name_len > 48) {
467 name_len = 48;
468 ptr[1] = EIR_NAME_SHORT;
469 } else
470 ptr[1] = EIR_NAME_COMPLETE;
471
472 /* EIR Data length */
473 ptr[0] = name_len + 1;
474
475 memcpy(ptr + 2, hdev->dev_name, name_len);
476
477 eir_len += (name_len + 2);
478 ptr += (name_len + 2);
479 }
480
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700481 if (hdev->inq_tx_power) {
482 ptr[0] = 2;
483 ptr[1] = EIR_TX_POWER;
484 ptr[2] = (u8) hdev->inq_tx_power;
485
486 eir_len += 3;
487 ptr += 3;
488 }
489
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700490 if (hdev->devid_source > 0) {
491 ptr[0] = 9;
492 ptr[1] = EIR_DEVICE_ID;
493
494 put_unaligned_le16(hdev->devid_source, ptr + 2);
495 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
496 put_unaligned_le16(hdev->devid_product, ptr + 6);
497 put_unaligned_le16(hdev->devid_version, ptr + 8);
498
499 eir_len += 10;
500 ptr += 10;
501 }
502
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300503 memset(uuid16_list, 0, sizeof(uuid16_list));
504
505 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200506 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300507 u16 uuid16;
508
509 uuid16 = get_uuid16(uuid->uuid);
510 if (uuid16 == 0)
511 return;
512
513 if (uuid16 < 0x1100)
514 continue;
515
516 if (uuid16 == PNP_INFO_SVCLASS_ID)
517 continue;
518
519 /* Stop if not enough space to put next UUID */
520 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
521 truncated = 1;
522 break;
523 }
524
525 /* Check for duplicates */
526 for (i = 0; uuid16_list[i] != 0; i++)
527 if (uuid16_list[i] == uuid16)
528 break;
529
530 if (uuid16_list[i] == 0) {
531 uuid16_list[i] = uuid16;
532 eir_len += sizeof(u16);
533 }
534 }
535
536 if (uuid16_list[0] != 0) {
537 u8 *length = ptr;
538
539 /* EIR Data type */
540 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
541
542 ptr += 2;
543 eir_len += 2;
544
545 for (i = 0; uuid16_list[i] != 0; i++) {
546 *ptr++ = (uuid16_list[i] & 0x00ff);
547 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
548 }
549
550 /* EIR Data length */
551 *length = (i * sizeof(u16)) + 1;
552 }
553}
554
555static int update_eir(struct hci_dev *hdev)
556{
557 struct hci_cp_write_eir cp;
558
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200559 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200560 return 0;
561
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300562 if (!(hdev->features[6] & LMP_EXT_INQ))
563 return 0;
564
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200565 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300566 return 0;
567
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200568 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300569 return 0;
570
571 memset(&cp, 0, sizeof(cp));
572
573 create_eir(hdev, cp.data);
574
575 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
576 return 0;
577
578 memcpy(hdev->eir, cp.data, sizeof(cp.data));
579
580 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
581}
582
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200583static u8 get_service_classes(struct hci_dev *hdev)
584{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300585 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200586 u8 val = 0;
587
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300588 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200589 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200590
591 return val;
592}
593
594static int update_class(struct hci_dev *hdev)
595{
596 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200597 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200598
599 BT_DBG("%s", hdev->name);
600
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200601 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200602 return 0;
603
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200604 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200605 return 0;
606
607 cod[0] = hdev->minor_class;
608 cod[1] = hdev->major_class;
609 cod[2] = get_service_classes(hdev);
610
611 if (memcmp(cod, hdev->dev_class, 3) == 0)
612 return 0;
613
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200614 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
615 if (err == 0)
616 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
617
618 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200619}
620
Johan Hedberg7d785252011-12-15 00:47:39 +0200621static void service_cache_off(struct work_struct *work)
622{
623 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300624 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200625
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200626 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200627 return;
628
629 hci_dev_lock(hdev);
630
631 update_eir(hdev);
632 update_class(hdev);
633
634 hci_dev_unlock(hdev);
635}
636
Johan Hedberg6a919082012-02-28 06:17:26 +0200637static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200638{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200639 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200640 return;
641
Johan Hedberg4f87da82012-03-02 19:55:56 +0200642 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200643
Johan Hedberg4f87da82012-03-02 19:55:56 +0200644 /* Non-mgmt controlled devices get this bit set
645 * implicitly so that pairing works for them, however
646 * for mgmt we require user-space to explicitly enable
647 * it
648 */
649 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200650}
651
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200652static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300653 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200654{
655 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200656
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200657 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200658
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300659 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200660
Johan Hedberg03811012010-12-08 00:21:06 +0200661 memset(&rp, 0, sizeof(rp));
662
Johan Hedberg03811012010-12-08 00:21:06 +0200663 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200664
665 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200666 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200667
668 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
669 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
670
671 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200672
673 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200674 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200675
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300676 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200677
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200678 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300679 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200680}
681
682static void mgmt_pending_free(struct pending_cmd *cmd)
683{
684 sock_put(cmd->sk);
685 kfree(cmd->param);
686 kfree(cmd);
687}
688
689static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300690 struct hci_dev *hdev, void *data,
691 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200692{
693 struct pending_cmd *cmd;
694
695 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
696 if (!cmd)
697 return NULL;
698
699 cmd->opcode = opcode;
700 cmd->index = hdev->id;
701
702 cmd->param = kmalloc(len, GFP_ATOMIC);
703 if (!cmd->param) {
704 kfree(cmd);
705 return NULL;
706 }
707
708 if (data)
709 memcpy(cmd->param, data, len);
710
711 cmd->sk = sk;
712 sock_hold(sk);
713
714 list_add(&cmd->list, &hdev->mgmt_pending);
715
716 return cmd;
717}
718
719static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300720 void (*cb)(struct pending_cmd *cmd, void *data),
721 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200722{
723 struct list_head *p, *n;
724
725 list_for_each_safe(p, n, &hdev->mgmt_pending) {
726 struct pending_cmd *cmd;
727
728 cmd = list_entry(p, struct pending_cmd, list);
729
730 if (opcode > 0 && cmd->opcode != opcode)
731 continue;
732
733 cb(cmd, data);
734 }
735}
736
737static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
738{
739 struct pending_cmd *cmd;
740
741 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
742 if (cmd->opcode == opcode)
743 return cmd;
744 }
745
746 return NULL;
747}
748
749static void mgmt_pending_remove(struct pending_cmd *cmd)
750{
751 list_del(&cmd->list);
752 mgmt_pending_free(cmd);
753}
754
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200755static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200756{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200757 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200758
Johan Hedbergaee9b212012-02-18 15:07:59 +0200759 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300760 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200761}
762
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200763static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300764 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200765{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300766 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200767 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200768 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200769
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200770 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200771
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300772 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200773
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100774 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
775 cancel_delayed_work(&hdev->power_off);
776
777 if (cp->val) {
778 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
779 mgmt_powered(hdev, 1);
780 goto failed;
781 }
782 }
783
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200784 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200785 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200786 goto failed;
787 }
788
789 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200790 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300791 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200792 goto failed;
793 }
794
795 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
796 if (!cmd) {
797 err = -ENOMEM;
798 goto failed;
799 }
800
801 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200802 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200803 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200804 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200805
806 err = 0;
807
808failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300809 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200810 return err;
811}
812
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300813static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
814 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200815{
816 struct sk_buff *skb;
817 struct mgmt_hdr *hdr;
818
819 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
820 if (!skb)
821 return -ENOMEM;
822
823 hdr = (void *) skb_put(skb, sizeof(*hdr));
824 hdr->opcode = cpu_to_le16(event);
825 if (hdev)
826 hdr->index = cpu_to_le16(hdev->id);
827 else
828 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
829 hdr->len = cpu_to_le16(data_len);
830
831 if (data)
832 memcpy(skb_put(skb, data_len), data, data_len);
833
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100834 /* Time stamp */
835 __net_timestamp(skb);
836
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200837 hci_send_to_control(skb, skip_sk);
838 kfree_skb(skb);
839
840 return 0;
841}
842
843static int new_settings(struct hci_dev *hdev, struct sock *skip)
844{
845 __le32 ev;
846
847 ev = cpu_to_le32(get_current_settings(hdev));
848
849 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
850}
851
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200852static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300853 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200854{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300855 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200856 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200857 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200858 u8 scan;
859 int err;
860
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200861 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200862
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700863 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100864 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200865 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300866 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200867
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300868 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200869
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200870 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200871 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300872 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200873 goto failed;
874 }
875
876 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
877 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200878 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300879 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200880 goto failed;
881 }
882
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200883 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200884 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300885 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200886 goto failed;
887 }
888
889 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200890 bool changed = false;
891
892 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
893 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
894 changed = true;
895 }
896
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200897 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200898 if (err < 0)
899 goto failed;
900
901 if (changed)
902 err = new_settings(hdev, sk);
903
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200904 goto failed;
905 }
906
907 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100908 if (hdev->discov_timeout > 0) {
909 cancel_delayed_work(&hdev->discov_off);
910 hdev->discov_timeout = 0;
911 }
912
913 if (cp->val && timeout > 0) {
914 hdev->discov_timeout = timeout;
915 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
916 msecs_to_jiffies(hdev->discov_timeout * 1000));
917 }
918
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200919 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200920 goto failed;
921 }
922
923 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
924 if (!cmd) {
925 err = -ENOMEM;
926 goto failed;
927 }
928
929 scan = SCAN_PAGE;
930
931 if (cp->val)
932 scan |= SCAN_INQUIRY;
933 else
934 cancel_delayed_work(&hdev->discov_off);
935
936 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
937 if (err < 0)
938 mgmt_pending_remove(cmd);
939
Johan Hedberg03811012010-12-08 00:21:06 +0200940 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200941 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200942
943failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300944 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200945 return err;
946}
947
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200948static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300949 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200950{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300951 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200952 struct pending_cmd *cmd;
953 u8 scan;
954 int err;
955
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200956 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200957
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300958 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200959
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200960 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200961 bool changed = false;
962
963 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
964 changed = true;
965
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200966 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200967 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200968 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200969 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
970 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
971 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200972
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200973 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200974 if (err < 0)
975 goto failed;
976
977 if (changed)
978 err = new_settings(hdev, sk);
979
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200980 goto failed;
981 }
982
983 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
984 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200985 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300986 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200987 goto failed;
988 }
989
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200990 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200991 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200992 goto failed;
993 }
994
995 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
996 if (!cmd) {
997 err = -ENOMEM;
998 goto failed;
999 }
1000
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001001 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001002 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001003 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001004 scan = 0;
1005
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001006 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1007 hdev->discov_timeout > 0)
1008 cancel_delayed_work(&hdev->discov_off);
1009 }
1010
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001011 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1012 if (err < 0)
1013 mgmt_pending_remove(cmd);
1014
1015failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001016 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001017 return err;
1018}
1019
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001020static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001021 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001022{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001023 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001024 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001025
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001026 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001027
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001028 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001029
1030 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001031 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001033 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001034
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001035 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036 if (err < 0)
1037 goto failed;
1038
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001039 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040
1041failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001042 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001043 return err;
1044}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001045
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001046static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1047 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001048{
1049 struct mgmt_mode *cp = data;
1050 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001051 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001052 int err;
1053
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001054 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001055
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001056 hci_dev_lock(hdev);
1057
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001058 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001059 bool changed = false;
1060
1061 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1062 &hdev->dev_flags)) {
1063 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1064 changed = true;
1065 }
1066
1067 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1068 if (err < 0)
1069 goto failed;
1070
1071 if (changed)
1072 err = new_settings(hdev, sk);
1073
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001074 goto failed;
1075 }
1076
1077 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001078 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001079 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001080 goto failed;
1081 }
1082
1083 val = !!cp->val;
1084
1085 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1086 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1087 goto failed;
1088 }
1089
1090 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1091 if (!cmd) {
1092 err = -ENOMEM;
1093 goto failed;
1094 }
1095
1096 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1097 if (err < 0) {
1098 mgmt_pending_remove(cmd);
1099 goto failed;
1100 }
1101
1102failed:
1103 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001104 return err;
1105}
1106
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001107static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001108{
1109 struct mgmt_mode *cp = data;
1110 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001111 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001112 int err;
1113
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001114 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001115
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001116 hci_dev_lock(hdev);
1117
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001118 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001119 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001120 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001121 goto failed;
1122 }
1123
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001124 val = !!cp->val;
1125
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001126 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001127 bool changed = false;
1128
1129 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1130 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1131 changed = true;
1132 }
1133
1134 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1135 if (err < 0)
1136 goto failed;
1137
1138 if (changed)
1139 err = new_settings(hdev, sk);
1140
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001141 goto failed;
1142 }
1143
1144 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001145 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1146 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001147 goto failed;
1148 }
1149
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001150 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1151 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1152 goto failed;
1153 }
1154
1155 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1156 if (!cmd) {
1157 err = -ENOMEM;
1158 goto failed;
1159 }
1160
1161 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1162 if (err < 0) {
1163 mgmt_pending_remove(cmd);
1164 goto failed;
1165 }
1166
1167failed:
1168 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001169 return err;
1170}
1171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001172static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001173{
1174 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001175
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001176 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001177
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001178 if (!enable_hs)
1179 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001180 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001181
1182 if (cp->val)
1183 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1184 else
1185 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001187 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001188}
1189
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001190static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001191{
1192 struct mgmt_mode *cp = data;
1193 struct hci_cp_write_le_host_supported hci_cp;
1194 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001195 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001196 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001197
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001198 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001199
Johan Hedberg1de028c2012-02-29 19:55:35 -08001200 hci_dev_lock(hdev);
1201
Johan Hedberg06199cf2012-02-22 16:37:11 +02001202 if (!enable_le || !(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001203 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001204 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001205 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001206 }
1207
1208 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001209 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001210
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001211 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001212 bool changed = false;
1213
1214 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1215 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1216 changed = true;
1217 }
1218
1219 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1220 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001221 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001222
1223 if (changed)
1224 err = new_settings(hdev, sk);
1225
Johan Hedberg1de028c2012-02-29 19:55:35 -08001226 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001227 }
1228
1229 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001230 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001231 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001232 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001233 }
1234
1235 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1236 if (!cmd) {
1237 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001238 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001239 }
1240
1241 memset(&hci_cp, 0, sizeof(hci_cp));
1242
1243 if (val) {
1244 hci_cp.le = val;
1245 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1246 }
1247
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001248 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1249 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301250 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001251 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001252
Johan Hedberg1de028c2012-02-29 19:55:35 -08001253unlock:
1254 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001255 return err;
1256}
1257
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001258static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001259{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001260 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001261 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001262 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001263 int err;
1264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001265 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001266
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001267 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001268
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001269 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001270 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001271 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001272 goto failed;
1273 }
1274
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001275 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1276 if (!uuid) {
1277 err = -ENOMEM;
1278 goto failed;
1279 }
1280
1281 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001282 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001283
1284 list_add(&uuid->list, &hdev->uuids);
1285
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001286 err = update_class(hdev);
1287 if (err < 0)
1288 goto failed;
1289
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001290 err = update_eir(hdev);
1291 if (err < 0)
1292 goto failed;
1293
Johan Hedberg90e70452012-02-23 23:09:40 +02001294 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001295 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001296 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001297 goto failed;
1298 }
1299
1300 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301301 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001302 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001303
1304failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001305 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001306 return err;
1307}
1308
Johan Hedberg24b78d02012-02-23 23:24:30 +02001309static bool enable_service_cache(struct hci_dev *hdev)
1310{
1311 if (!hdev_is_powered(hdev))
1312 return false;
1313
1314 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001315 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001316 return true;
1317 }
1318
1319 return false;
1320}
1321
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001322static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1323 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001324{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001325 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001326 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001327 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001328 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 +02001329 int err, found;
1330
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001331 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001332
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001333 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001334
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001335 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001336 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001337 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001338 goto unlock;
1339 }
1340
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001341 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1342 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001343
Johan Hedberg24b78d02012-02-23 23:24:30 +02001344 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001345 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001346 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001347 goto unlock;
1348 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001349
Johan Hedberg9246a862012-02-23 21:33:16 +02001350 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001351 }
1352
1353 found = 0;
1354
1355 list_for_each_safe(p, n, &hdev->uuids) {
1356 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1357
1358 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1359 continue;
1360
1361 list_del(&match->list);
1362 found++;
1363 }
1364
1365 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001366 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001367 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001368 goto unlock;
1369 }
1370
Johan Hedberg9246a862012-02-23 21:33:16 +02001371update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001372 err = update_class(hdev);
1373 if (err < 0)
1374 goto unlock;
1375
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001376 err = update_eir(hdev);
1377 if (err < 0)
1378 goto unlock;
1379
Johan Hedberg90e70452012-02-23 23:09:40 +02001380 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001381 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001382 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001383 goto unlock;
1384 }
1385
1386 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301387 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001388 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001389
1390unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001391 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001392 return err;
1393}
1394
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001395static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001396 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001397{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001398 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001399 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001400 int err;
1401
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001402 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001403
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001404 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001405
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001406 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001407 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001408 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001409 goto unlock;
1410 }
1411
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001412 hdev->major_class = cp->major;
1413 hdev->minor_class = cp->minor;
1414
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001415 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001416 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001417 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001418 goto unlock;
1419 }
1420
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001421 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001422 hci_dev_unlock(hdev);
1423 cancel_delayed_work_sync(&hdev->service_cache);
1424 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001425 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001426 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001427
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001428 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001429 if (err < 0)
1430 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001431
Johan Hedberg90e70452012-02-23 23:09:40 +02001432 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001433 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001434 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001435 goto unlock;
1436 }
1437
1438 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301439 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001440 err = -ENOMEM;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001441
Johan Hedbergb5235a62012-02-21 14:32:24 +02001442unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001443 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001444 return err;
1445}
1446
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001447static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1448 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001449{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001450 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001451 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001452 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001453
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001454 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001455
Johan Hedberg86742e12011-11-07 23:13:38 +02001456 expected_len = sizeof(*cp) + key_count *
1457 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001458 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001459 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001460 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001461 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001462 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001463 }
1464
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001465 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001466 key_count);
1467
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001468 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001469
1470 hci_link_keys_clear(hdev);
1471
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001472 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001473
1474 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001475 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001476 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001477 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001478
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001479 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001480 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001481
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001482 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001483 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001484 }
1485
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001486 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001487
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001488 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001489
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001490 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001491}
1492
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001493static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001494 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001495{
1496 struct mgmt_ev_device_unpaired ev;
1497
1498 bacpy(&ev.addr.bdaddr, bdaddr);
1499 ev.addr.type = addr_type;
1500
1501 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001502 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001503}
1504
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001505static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001506 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001507{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001508 struct mgmt_cp_unpair_device *cp = data;
1509 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001510 struct hci_cp_disconnect dc;
1511 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001512 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001513 int err;
1514
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001515 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001516
Johan Hedberga8a1d192011-11-10 15:54:38 +02001517 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001518 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1519 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001520
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001521 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001522 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001523 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001524 goto unlock;
1525 }
1526
Andre Guedes591f47f2012-04-24 21:02:49 -03001527 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001528 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1529 else
1530 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001531
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001532 if (err < 0) {
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_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001535 goto unlock;
1536 }
1537
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001538 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001539 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001540 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1541 &cp->addr.bdaddr);
1542 else
1543 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1544 &cp->addr.bdaddr);
1545 } else {
1546 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001547 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001548
Johan Hedberga8a1d192011-11-10 15:54:38 +02001549 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001550 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001551 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001552 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001553 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001554 }
1555
Johan Hedberg124f6e32012-02-09 13:50:12 +02001556 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001557 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001558 if (!cmd) {
1559 err = -ENOMEM;
1560 goto unlock;
1561 }
1562
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001563 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001564 dc.reason = 0x13; /* Remote User Terminated Connection */
1565 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1566 if (err < 0)
1567 mgmt_pending_remove(cmd);
1568
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001569unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001570 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001571 return err;
1572}
1573
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001574static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001575 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001576{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001577 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001578 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001579 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001580 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001581 int err;
1582
1583 BT_DBG("");
1584
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001585 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001586
1587 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001588 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001589 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001590 goto failed;
1591 }
1592
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001593 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001594 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001595 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001596 goto failed;
1597 }
1598
Andre Guedes591f47f2012-04-24 21:02:49 -03001599 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg88c3df12012-02-09 14:27:38 +02001600 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1601 else
1602 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001603
Johan Hedberg8962ee72011-01-20 12:40:27 +02001604 if (!conn) {
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_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001607 goto failed;
1608 }
1609
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001610 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001611 if (!cmd) {
1612 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001613 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001614 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001615
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001616 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001617 dc.reason = 0x13; /* Remote User Terminated Connection */
1618
1619 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1620 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001621 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001622
1623failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001624 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001625 return err;
1626}
1627
Andre Guedes57c14772012-04-24 21:02:50 -03001628static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001629{
1630 switch (link_type) {
1631 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001632 switch (addr_type) {
1633 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001634 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001635
Johan Hedberg48264f02011-11-09 13:58:58 +02001636 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001637 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001638 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001639 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001640
Johan Hedberg4c659c32011-11-07 23:13:39 +02001641 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001642 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001643 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001644 }
1645}
1646
Hemant Gupta4596fde2012-04-16 14:57:40 +05301647static u8 mgmt_to_le(u8 mgmt_type)
1648{
1649 switch (mgmt_type) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001650 case BDADDR_LE_PUBLIC:
Hemant Gupta4596fde2012-04-16 14:57:40 +05301651 return ADDR_LE_DEV_PUBLIC;
1652
1653 default:
1654 /* Fallback to LE Random address type */
1655 return ADDR_LE_DEV_RANDOM;
1656 }
1657}
1658
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001659static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1660 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001661{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001662 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001663 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001664 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001665 int err;
1666 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001667
1668 BT_DBG("");
1669
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001670 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001671
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001672 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001673 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001674 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001675 goto unlock;
1676 }
1677
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001678 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001679 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1680 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001681 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001682 }
1683
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001684 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001685 rp = kmalloc(rp_len, GFP_ATOMIC);
1686 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001687 err = -ENOMEM;
1688 goto unlock;
1689 }
1690
Johan Hedberg2784eb42011-01-21 13:56:35 +02001691 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001692 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001693 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1694 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001695 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001696 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001697 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001698 continue;
1699 i++;
1700 }
1701
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001702 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001703
Johan Hedberg4c659c32011-11-07 23:13:39 +02001704 /* Recalculate length in case of filtered SCO connections, etc */
1705 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001706
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001707 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001708 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001709
Johan Hedberga38528f2011-01-22 06:46:43 +02001710 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001711
1712unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001713 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001714 return err;
1715}
1716
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001717static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001718 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001719{
1720 struct pending_cmd *cmd;
1721 int err;
1722
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001723 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001724 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001725 if (!cmd)
1726 return -ENOMEM;
1727
Johan Hedbergd8457692012-02-17 14:24:57 +02001728 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001729 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001730 if (err < 0)
1731 mgmt_pending_remove(cmd);
1732
1733 return err;
1734}
1735
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001736static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001737 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001738{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001739 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001740 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001741 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001742 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001743 int err;
1744
1745 BT_DBG("");
1746
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001747 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001748
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001749 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001750 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001751 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001752 goto failed;
1753 }
1754
Johan Hedbergd8457692012-02-17 14:24:57 +02001755 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001756 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001757 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001758 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001759 goto failed;
1760 }
1761
1762 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001763 struct mgmt_cp_pin_code_neg_reply ncp;
1764
1765 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001766
1767 BT_ERR("PIN code is not 16 bytes long");
1768
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001769 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001770 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001771 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001772 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001773
1774 goto failed;
1775 }
1776
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001777 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001778 if (!cmd) {
1779 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001780 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001781 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001782
Johan Hedbergd8457692012-02-17 14:24:57 +02001783 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001784 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001785 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001786
1787 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1788 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001789 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001790
1791failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001792 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001793 return err;
1794}
1795
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001796static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001797 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001798{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001799 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001800 int err;
1801
1802 BT_DBG("");
1803
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001804 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001805
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001806 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001807 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001808 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001809 goto failed;
1810 }
1811
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001812 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001813
1814failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001815 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001816 return err;
1817}
1818
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001819static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1820 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001821{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001822 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001823
1824 BT_DBG("");
1825
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001826 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001827
1828 hdev->io_capability = cp->io_capability;
1829
1830 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001831 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001832
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001833 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001834
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001835 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1836 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001837}
1838
Johan Hedberge9a416b2011-02-19 12:05:56 -03001839static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1840{
1841 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001842 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001843
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001844 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001845 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1846 continue;
1847
Johan Hedberge9a416b2011-02-19 12:05:56 -03001848 if (cmd->user_data != conn)
1849 continue;
1850
1851 return cmd;
1852 }
1853
1854 return NULL;
1855}
1856
1857static void pairing_complete(struct pending_cmd *cmd, u8 status)
1858{
1859 struct mgmt_rp_pair_device rp;
1860 struct hci_conn *conn = cmd->user_data;
1861
Johan Hedbergba4e5642011-11-11 00:07:34 +02001862 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001863 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001864
Johan Hedbergaee9b212012-02-18 15:07:59 +02001865 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001866 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001867
1868 /* So we don't get further callbacks for this connection */
1869 conn->connect_cfm_cb = NULL;
1870 conn->security_cfm_cb = NULL;
1871 conn->disconn_cfm_cb = NULL;
1872
1873 hci_conn_put(conn);
1874
Johan Hedberga664b5b2011-02-19 12:06:02 -03001875 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001876}
1877
1878static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1879{
1880 struct pending_cmd *cmd;
1881
1882 BT_DBG("status %u", status);
1883
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001884 cmd = find_pairing(conn);
1885 if (!cmd)
1886 BT_DBG("Unable to find a pending command");
1887 else
Johan Hedberge2113262012-02-18 15:20:03 +02001888 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001889}
1890
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001891static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001892 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001893{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001894 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001895 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001896 struct pending_cmd *cmd;
1897 u8 sec_level, auth_type;
1898 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001899 int err;
1900
1901 BT_DBG("");
1902
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001903 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001904
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001905 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001906 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001907 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001908 goto unlock;
1909 }
1910
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001911 sec_level = BT_SECURITY_MEDIUM;
1912 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001913 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001914 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001915 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001916
Andre Guedes591f47f2012-04-24 21:02:49 -03001917 if (cp->addr.type == BDADDR_BREDR)
Johan Hedbergba4e5642011-11-11 00:07:34 +02001918 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001919 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001920 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001921 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001922 auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001923
Johan Hedberg1425acb2011-11-11 00:07:35 +02001924 memset(&rp, 0, sizeof(rp));
1925 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1926 rp.addr.type = cp->addr.type;
1927
Ville Tervo30e76272011-02-22 16:10:53 -03001928 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001929 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001930 MGMT_STATUS_CONNECT_FAILED, &rp,
1931 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001932 goto unlock;
1933 }
1934
1935 if (conn->connect_cfm_cb) {
1936 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001937 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001938 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001939 goto unlock;
1940 }
1941
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001942 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001943 if (!cmd) {
1944 err = -ENOMEM;
1945 hci_conn_put(conn);
1946 goto unlock;
1947 }
1948
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001949 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03001950 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001951 conn->connect_cfm_cb = pairing_complete_cb;
1952
Johan Hedberge9a416b2011-02-19 12:05:56 -03001953 conn->security_cfm_cb = pairing_complete_cb;
1954 conn->disconn_cfm_cb = pairing_complete_cb;
1955 conn->io_capability = cp->io_cap;
1956 cmd->user_data = conn;
1957
1958 if (conn->state == BT_CONNECTED &&
1959 hci_conn_security(conn, sec_level, auth_type))
1960 pairing_complete(cmd, 0);
1961
1962 err = 0;
1963
1964unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001965 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001966 return err;
1967}
1968
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001969static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1970 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001971{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001972 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001973 struct pending_cmd *cmd;
1974 struct hci_conn *conn;
1975 int err;
1976
1977 BT_DBG("");
1978
Johan Hedberg28424702012-02-02 04:02:29 +02001979 hci_dev_lock(hdev);
1980
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001981 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001982 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001983 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001984 goto unlock;
1985 }
1986
Johan Hedberg28424702012-02-02 04:02:29 +02001987 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1988 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001989 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001990 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001991 goto unlock;
1992 }
1993
1994 conn = cmd->user_data;
1995
1996 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001997 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001998 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001999 goto unlock;
2000 }
2001
2002 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2003
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002004 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002005 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002006unlock:
2007 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002008 return err;
2009}
2010
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002011static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002012 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2013 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002014{
Johan Hedberga5c29682011-02-19 12:05:57 -03002015 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002016 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002017 int err;
2018
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002019 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002020
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002021 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002022 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002023 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002024 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002025 }
2026
Andre Guedes591f47f2012-04-24 21:02:49 -03002027 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002028 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2029 else
Brian Gix47c15e22011-11-16 13:53:14 -08002030 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002031
Johan Hedberg272d90d2012-02-09 15:26:12 +02002032 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002033 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002034 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002035 goto done;
2036 }
2037
Andre Guedes591f47f2012-04-24 21:02:49 -03002038 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002039 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002040 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002041
Brian Gix5fe57d92011-12-21 16:12:13 -08002042 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002043 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002044 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002045 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002046 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002047 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002048
Brian Gix47c15e22011-11-16 13:53:14 -08002049 goto done;
2050 }
2051
Brian Gix0df4c182011-11-16 13:53:13 -08002052 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002053 if (!cmd) {
2054 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002055 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002056 }
2057
Brian Gix0df4c182011-11-16 13:53:13 -08002058 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002059 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2060 struct hci_cp_user_passkey_reply cp;
2061
2062 bacpy(&cp.bdaddr, bdaddr);
2063 cp.passkey = passkey;
2064 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2065 } else
2066 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2067
Johan Hedberga664b5b2011-02-19 12:06:02 -03002068 if (err < 0)
2069 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002070
Brian Gix0df4c182011-11-16 13:53:13 -08002071done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002072 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002073 return err;
2074}
2075
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002076static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2077 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002078{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002079 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002080
2081 BT_DBG("");
2082
2083 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002084 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002085 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002086
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002087 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002088 MGMT_OP_USER_CONFIRM_REPLY,
2089 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002090}
2091
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002092static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002093 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002094{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002095 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002096
2097 BT_DBG("");
2098
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002099 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002100 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2101 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002102}
2103
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002104static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2105 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002106{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002107 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002108
2109 BT_DBG("");
2110
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002111 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002112 MGMT_OP_USER_PASSKEY_REPLY,
2113 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002114}
2115
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002116static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002117 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002118{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002119 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002120
2121 BT_DBG("");
2122
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002123 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002124 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2125 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002126}
2127
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002128static int update_name(struct hci_dev *hdev, const char *name)
2129{
2130 struct hci_cp_write_local_name cp;
2131
2132 memcpy(cp.name, name, sizeof(cp.name));
2133
2134 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2135}
2136
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002137static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002138 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002139{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002140 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002141 struct pending_cmd *cmd;
2142 int err;
2143
2144 BT_DBG("");
2145
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002146 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002147
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002148 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002149
Johan Hedbergb5235a62012-02-21 14:32:24 +02002150 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002151 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002152
2153 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002154 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002155 if (err < 0)
2156 goto failed;
2157
2158 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002159 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002160
Johan Hedbergb5235a62012-02-21 14:32:24 +02002161 goto failed;
2162 }
2163
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002164 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002165 if (!cmd) {
2166 err = -ENOMEM;
2167 goto failed;
2168 }
2169
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002170 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002171 if (err < 0)
2172 mgmt_pending_remove(cmd);
2173
2174failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002175 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002176 return err;
2177}
2178
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002179static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002180 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002181{
Szymon Jancc35938b2011-03-22 13:12:21 +01002182 struct pending_cmd *cmd;
2183 int err;
2184
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002185 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002186
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002187 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002188
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002189 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002190 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002191 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002192 goto unlock;
2193 }
2194
2195 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002196 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002197 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002198 goto unlock;
2199 }
2200
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002201 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002202 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002203 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002204 goto unlock;
2205 }
2206
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002207 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002208 if (!cmd) {
2209 err = -ENOMEM;
2210 goto unlock;
2211 }
2212
2213 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2214 if (err < 0)
2215 mgmt_pending_remove(cmd);
2216
2217unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002218 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002219 return err;
2220}
2221
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002222static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002223 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002224{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002225 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002226 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002227 int err;
2228
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002229 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002230
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002231 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002232
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002233 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002234 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002235 MGMT_STATUS_NOT_POWERED, &cp->addr,
2236 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002237 goto unlock;
2238 }
2239
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002240 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002241 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002242 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002243 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002244 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002245 status = 0;
2246
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002247 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002248 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002249
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002250unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002251 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002252 return err;
2253}
2254
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002255static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002256 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002257{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002258 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002259 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002260 int err;
2261
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002262 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002263
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002264 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002265
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002266 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002267 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002268 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2269 MGMT_STATUS_NOT_POWERED, &cp->addr,
2270 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002271 goto unlock;
2272 }
2273
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002274 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002275 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002276 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002277 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002278 status = 0;
2279
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002280 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002281 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002282
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002283unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002284 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002285 return err;
2286}
2287
Andre Guedes5e0452c2012-02-17 20:39:38 -03002288int mgmt_interleaved_discovery(struct hci_dev *hdev)
2289{
2290 int err;
2291
2292 BT_DBG("%s", hdev->name);
2293
2294 hci_dev_lock(hdev);
2295
2296 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2297 if (err < 0)
2298 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2299
2300 hci_dev_unlock(hdev);
2301
2302 return err;
2303}
2304
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002305static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002306 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002307{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002308 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002309 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002310 int err;
2311
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002312 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002313
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002314 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002315
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002316 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002317 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002318 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002319 goto failed;
2320 }
2321
Andre Guedes642be6c2012-03-21 00:03:37 -03002322 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2323 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2324 MGMT_STATUS_BUSY);
2325 goto failed;
2326 }
2327
Johan Hedbergff9ef572012-01-04 14:23:45 +02002328 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002329 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002330 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002331 goto failed;
2332 }
2333
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002334 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002335 if (!cmd) {
2336 err = -ENOMEM;
2337 goto failed;
2338 }
2339
Andre Guedes4aab14e2012-02-17 20:39:36 -03002340 hdev->discovery.type = cp->type;
2341
2342 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002343 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002344 if (lmp_bredr_capable(hdev))
2345 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2346 else
2347 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002348 break;
2349
2350 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002351 if (lmp_host_le_capable(hdev))
2352 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002353 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002354 else
2355 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002356 break;
2357
Andre Guedes5e0452c2012-02-17 20:39:38 -03002358 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002359 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2360 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002361 LE_SCAN_WIN,
2362 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002363 else
2364 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002365 break;
2366
Andre Guedesf39799f2012-02-17 20:39:35 -03002367 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002368 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002369 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002370
Johan Hedberg14a53662011-04-27 10:29:56 -04002371 if (err < 0)
2372 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002373 else
2374 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002375
2376failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002377 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002378 return err;
2379}
2380
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002381static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002382 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002383{
Johan Hedbergd9306502012-02-20 23:25:18 +02002384 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002385 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002386 struct hci_cp_remote_name_req_cancel cp;
2387 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002388 int err;
2389
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002390 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002391
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002392 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002393
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002394 if (!hci_discovery_active(hdev)) {
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_REJECTED, &mgmt_cp->type,
2397 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002398 goto unlock;
2399 }
2400
2401 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002402 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002403 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2404 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002405 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002406 }
2407
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002408 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002409 if (!cmd) {
2410 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002411 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002412 }
2413
Andre Guedese0d9727e2012-03-20 15:15:36 -03002414 switch (hdev->discovery.state) {
2415 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002416 if (test_bit(HCI_INQUIRY, &hdev->flags))
2417 err = hci_cancel_inquiry(hdev);
2418 else
2419 err = hci_cancel_le_scan(hdev);
2420
Andre Guedese0d9727e2012-03-20 15:15:36 -03002421 break;
2422
2423 case DISCOVERY_RESOLVING:
2424 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
2425 NAME_PENDING);
2426 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002427 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002428 err = cmd_complete(sk, hdev->id,
2429 MGMT_OP_STOP_DISCOVERY, 0,
2430 &mgmt_cp->type,
2431 sizeof(mgmt_cp->type));
2432 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2433 goto unlock;
2434 }
2435
2436 bacpy(&cp.bdaddr, &e->data.bdaddr);
2437 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2438 sizeof(cp), &cp);
2439
2440 break;
2441
2442 default:
2443 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2444 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002445 }
2446
Johan Hedberg14a53662011-04-27 10:29:56 -04002447 if (err < 0)
2448 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002449 else
2450 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002451
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002452unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002453 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002454 return err;
2455}
2456
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002457static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002458 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002459{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002460 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002461 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002462 int err;
2463
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002464 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002465
Johan Hedberg561aafb2012-01-04 13:31:59 +02002466 hci_dev_lock(hdev);
2467
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002468 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002469 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002470 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002471 goto failed;
2472 }
2473
Johan Hedberga198e7b2012-02-17 14:27:06 +02002474 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002475 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002476 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002477 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002478 goto failed;
2479 }
2480
2481 if (cp->name_known) {
2482 e->name_state = NAME_KNOWN;
2483 list_del(&e->list);
2484 } else {
2485 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002486 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002487 }
2488
2489 err = 0;
2490
2491failed:
2492 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002493 return err;
2494}
2495
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002496static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002497 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002498{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002499 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002500 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002501 int err;
2502
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002503 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002504
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002505 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002506
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002507 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002508 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002509 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002510 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002511 status = 0;
2512
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002513 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002514 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002515
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002516 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002517
2518 return err;
2519}
2520
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002521static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002522 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002523{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002524 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002525 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002526 int err;
2527
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002528 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002529
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002530 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002531
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002532 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002533 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002534 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002535 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002536 status = 0;
2537
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002538 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002539 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002540
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002541 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002542
2543 return err;
2544}
2545
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002546static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2547 u16 len)
2548{
2549 struct mgmt_cp_set_device_id *cp = data;
2550 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002551 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002552
2553 BT_DBG("%s", hdev->name);
2554
Szymon Jancc72d4b82012-03-16 16:02:57 +01002555 source = __le16_to_cpu(cp->source);
2556
2557 if (source > 0x0002)
2558 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2559 MGMT_STATUS_INVALID_PARAMS);
2560
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002561 hci_dev_lock(hdev);
2562
Szymon Jancc72d4b82012-03-16 16:02:57 +01002563 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002564 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2565 hdev->devid_product = __le16_to_cpu(cp->product);
2566 hdev->devid_version = __le16_to_cpu(cp->version);
2567
2568 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2569
2570 update_eir(hdev);
2571
2572 hci_dev_unlock(hdev);
2573
2574 return err;
2575}
2576
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002577static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002578 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002579{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002580 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002581 struct hci_cp_write_page_scan_activity acp;
2582 u8 type;
2583 int err;
2584
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002585 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002586
Johan Hedberg5400c042012-02-21 16:40:33 +02002587 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002588 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002589 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002590
2591 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002592 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002593 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002594
2595 hci_dev_lock(hdev);
2596
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002597 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002598 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002599
2600 /* 22.5 msec page scan interval */
2601 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002602 } else {
2603 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002604
2605 /* default 1.28 sec page scan */
2606 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002607 }
2608
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002609 /* default 11.25 msec page scan window */
2610 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002611
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002612 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2613 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002614 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002615 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002616 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002617 goto done;
2618 }
2619
2620 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2621 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002622 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002623 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002624 goto done;
2625 }
2626
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002627 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002628 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002629done:
2630 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002631 return err;
2632}
2633
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002634static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002635 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002636{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002637 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2638 u16 key_count, expected_len;
2639 int i;
2640
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002641 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002642
2643 expected_len = sizeof(*cp) + key_count *
2644 sizeof(struct mgmt_ltk_info);
2645 if (expected_len != len) {
2646 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2647 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002648 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002649 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002650 }
2651
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002652 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002653
2654 hci_dev_lock(hdev);
2655
2656 hci_smp_ltks_clear(hdev);
2657
2658 for (i = 0; i < key_count; i++) {
2659 struct mgmt_ltk_info *key = &cp->keys[i];
2660 u8 type;
2661
2662 if (key->master)
2663 type = HCI_SMP_LTK;
2664 else
2665 type = HCI_SMP_LTK_SLAVE;
2666
Hemant Gupta4596fde2012-04-16 14:57:40 +05302667 hci_add_ltk(hdev, &key->addr.bdaddr,
2668 mgmt_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002669 type, 0, key->authenticated, key->val,
2670 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002671 }
2672
2673 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002674
2675 return 0;
2676}
2677
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002678static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002679 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2680 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002681 bool var_len;
2682 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002683} mgmt_handlers[] = {
2684 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002685 { read_version, false, MGMT_READ_VERSION_SIZE },
2686 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2687 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2688 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2689 { set_powered, false, MGMT_SETTING_SIZE },
2690 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2691 { set_connectable, false, MGMT_SETTING_SIZE },
2692 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2693 { set_pairable, false, MGMT_SETTING_SIZE },
2694 { set_link_security, false, MGMT_SETTING_SIZE },
2695 { set_ssp, false, MGMT_SETTING_SIZE },
2696 { set_hs, false, MGMT_SETTING_SIZE },
2697 { set_le, false, MGMT_SETTING_SIZE },
2698 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2699 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2700 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2701 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2702 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2703 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2704 { disconnect, false, MGMT_DISCONNECT_SIZE },
2705 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2706 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2707 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2708 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2709 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2710 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2711 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2712 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2713 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2714 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2715 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2716 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2717 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2718 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2719 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2720 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2721 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2722 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2723 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002724 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002725};
2726
2727
Johan Hedberg03811012010-12-08 00:21:06 +02002728int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2729{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002730 void *buf;
2731 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002732 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002733 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002734 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002735 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002736 int err;
2737
2738 BT_DBG("got %zu bytes", msglen);
2739
2740 if (msglen < sizeof(*hdr))
2741 return -EINVAL;
2742
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002743 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002744 if (!buf)
2745 return -ENOMEM;
2746
2747 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2748 err = -EFAULT;
2749 goto done;
2750 }
2751
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002752 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002753 opcode = __le16_to_cpu(hdr->opcode);
2754 index = __le16_to_cpu(hdr->index);
2755 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002756
2757 if (len != msglen - sizeof(*hdr)) {
2758 err = -EINVAL;
2759 goto done;
2760 }
2761
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002762 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002763 hdev = hci_dev_get(index);
2764 if (!hdev) {
2765 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002766 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002767 goto done;
2768 }
2769 }
2770
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002771 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2772 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002773 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002774 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002775 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002776 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002777 }
2778
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002779 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2780 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2781 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002782 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002783 goto done;
2784 }
2785
Johan Hedbergbe22b542012-03-01 22:24:41 +02002786 handler = &mgmt_handlers[opcode];
2787
2788 if ((handler->var_len && len < handler->data_len) ||
2789 (!handler->var_len && len != handler->data_len)) {
2790 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002791 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002792 goto done;
2793 }
2794
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002795 if (hdev)
2796 mgmt_init_hdev(sk, hdev);
2797
2798 cp = buf + sizeof(*hdr);
2799
Johan Hedbergbe22b542012-03-01 22:24:41 +02002800 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002801 if (err < 0)
2802 goto done;
2803
Johan Hedberg03811012010-12-08 00:21:06 +02002804 err = msglen;
2805
2806done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002807 if (hdev)
2808 hci_dev_put(hdev);
2809
Johan Hedberg03811012010-12-08 00:21:06 +02002810 kfree(buf);
2811 return err;
2812}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002813
Johan Hedbergb24752f2011-11-03 14:40:33 +02002814static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2815{
2816 u8 *status = data;
2817
2818 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2819 mgmt_pending_remove(cmd);
2820}
2821
Johan Hedberg744cf192011-11-08 20:40:14 +02002822int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002823{
Johan Hedberg744cf192011-11-08 20:40:14 +02002824 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002825}
2826
Johan Hedberg744cf192011-11-08 20:40:14 +02002827int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002828{
Johan Hedberg5f159032012-03-02 03:13:19 +02002829 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002830
Johan Hedberg744cf192011-11-08 20:40:14 +02002831 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002832
Johan Hedberg744cf192011-11-08 20:40:14 +02002833 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002834}
2835
Johan Hedberg73f22f62010-12-29 16:00:25 +02002836struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002837 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002838 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002839 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002840};
2841
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002842static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002843{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002844 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002845
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002846 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002847
2848 list_del(&cmd->list);
2849
2850 if (match->sk == NULL) {
2851 match->sk = cmd->sk;
2852 sock_hold(match->sk);
2853 }
2854
2855 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002856}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002857
Johan Hedberg744cf192011-11-08 20:40:14 +02002858int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002859{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002860 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002861 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002862
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002863 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2864 return 0;
2865
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002866 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002867
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002868 if (powered) {
2869 u8 scan = 0;
2870
2871 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2872 scan |= SCAN_PAGE;
2873 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2874 scan |= SCAN_INQUIRY;
2875
2876 if (scan)
2877 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002878
2879 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002880 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002881 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002882 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002883 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002884 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002885 }
2886
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002887 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002888
2889 if (match.sk)
2890 sock_put(match.sk);
2891
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002892 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002893}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002894
Johan Hedberg744cf192011-11-08 20:40:14 +02002895int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002896{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002897 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002898 bool changed = false;
2899 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002900
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002901 if (discoverable) {
2902 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2903 changed = true;
2904 } else {
2905 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2906 changed = true;
2907 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002908
Johan Hedberged9b5f22012-02-21 20:47:06 +02002909 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002910 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002911
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002912 if (changed)
2913 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002914
Johan Hedberg73f22f62010-12-29 16:00:25 +02002915 if (match.sk)
2916 sock_put(match.sk);
2917
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002918 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002919}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002920
Johan Hedberg744cf192011-11-08 20:40:14 +02002921int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002922{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002923 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002924 bool changed = false;
2925 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002926
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002927 if (connectable) {
2928 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2929 changed = true;
2930 } else {
2931 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2932 changed = true;
2933 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002934
Johan Hedberged9b5f22012-02-21 20:47:06 +02002935 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002936 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002937
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002938 if (changed)
2939 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002940
2941 if (match.sk)
2942 sock_put(match.sk);
2943
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002944 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002945}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002946
Johan Hedberg744cf192011-11-08 20:40:14 +02002947int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002948{
Johan Hedbergca69b792011-11-11 18:10:00 +02002949 u8 mgmt_err = mgmt_status(status);
2950
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002951 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002952 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002953 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002954
2955 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002956 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002957 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002958
2959 return 0;
2960}
2961
Vishal Agarwal745c0ce2012-04-13 17:43:22 +05302962int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002963{
Johan Hedberg86742e12011-11-07 23:13:38 +02002964 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002965
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002966 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002967
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002968 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002969 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03002970 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002971 ev.key.type = key->type;
2972 memcpy(ev.key.val, key->val, 16);
2973 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002974
Johan Hedberg744cf192011-11-08 20:40:14 +02002975 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002976}
Johan Hedbergf7520542011-01-20 12:34:39 +02002977
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002978int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2979{
2980 struct mgmt_ev_new_long_term_key ev;
2981
2982 memset(&ev, 0, sizeof(ev));
2983
2984 ev.store_hint = persistent;
2985 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03002986 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002987 ev.key.authenticated = key->authenticated;
2988 ev.key.enc_size = key->enc_size;
2989 ev.key.ediv = key->ediv;
2990
2991 if (key->type == HCI_SMP_LTK)
2992 ev.key.master = 1;
2993
2994 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2995 memcpy(ev.key.val, key->val, sizeof(key->val));
2996
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002997 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2998 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002999}
3000
Johan Hedbergafc747a2012-01-15 18:11:07 +02003001int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003002 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3003 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003004{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003005 char buf[512];
3006 struct mgmt_ev_device_connected *ev = (void *) buf;
3007 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003008
Johan Hedbergb644ba32012-01-17 21:48:47 +02003009 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003010 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003011
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003012 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003013
Johan Hedbergb644ba32012-01-17 21:48:47 +02003014 if (name_len > 0)
3015 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003016 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003017
3018 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003019 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003020 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003021
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003022 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003023
3024 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003025 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003026}
3027
Johan Hedberg8962ee72011-01-20 12:40:27 +02003028static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3029{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003030 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003031 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003032 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003033
Johan Hedberg88c3df12012-02-09 14:27:38 +02003034 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3035 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003036
Johan Hedbergaee9b212012-02-18 15:07:59 +02003037 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003038 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003039
3040 *sk = cmd->sk;
3041 sock_hold(*sk);
3042
Johan Hedberga664b5b2011-02-19 12:06:02 -03003043 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003044}
3045
Johan Hedberg124f6e32012-02-09 13:50:12 +02003046static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003047{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003048 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003049 struct mgmt_cp_unpair_device *cp = cmd->param;
3050 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003051
3052 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003053 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3054 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003055
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003056 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3057
Johan Hedbergaee9b212012-02-18 15:07:59 +02003058 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003059
3060 mgmt_pending_remove(cmd);
3061}
3062
Johan Hedbergafc747a2012-01-15 18:11:07 +02003063int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003064 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003065{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003066 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003067 struct sock *sk = NULL;
3068 int err;
3069
Johan Hedberg744cf192011-11-08 20:40:14 +02003070 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003071
Johan Hedbergf7520542011-01-20 12:34:39 +02003072 bacpy(&ev.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003073 ev.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003074
Johan Hedbergafc747a2012-01-15 18:11:07 +02003075 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003076 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003077
3078 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003079 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003080
Johan Hedberg124f6e32012-02-09 13:50:12 +02003081 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003082 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003083
Johan Hedberg8962ee72011-01-20 12:40:27 +02003084 return err;
3085}
3086
Johan Hedberg88c3df12012-02-09 14:27:38 +02003087int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003088 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003089{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003090 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003091 struct pending_cmd *cmd;
3092 int err;
3093
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003094 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003095 if (!cmd)
3096 return -ENOENT;
3097
Johan Hedberg88c3df12012-02-09 14:27:38 +02003098 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003099 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003100
Johan Hedberg88c3df12012-02-09 14:27:38 +02003101 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003102 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003103
Johan Hedberga664b5b2011-02-19 12:06:02 -03003104 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003105
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003106 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3107 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003108 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003109}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003110
Johan Hedberg48264f02011-11-09 13:58:58 +02003111int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003112 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003113{
3114 struct mgmt_ev_connect_failed ev;
3115
Johan Hedberg4c659c32011-11-07 23:13:39 +02003116 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003117 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003118 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003119
Johan Hedberg744cf192011-11-08 20:40:14 +02003120 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003121}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003122
Johan Hedberg744cf192011-11-08 20:40:14 +02003123int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003124{
3125 struct mgmt_ev_pin_code_request ev;
3126
Johan Hedbergd8457692012-02-17 14:24:57 +02003127 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003128 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003129 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003130
Johan Hedberg744cf192011-11-08 20:40:14 +02003131 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003132 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003133}
3134
Johan Hedberg744cf192011-11-08 20:40:14 +02003135int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003136 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003137{
3138 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003139 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003140 int err;
3141
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003142 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003143 if (!cmd)
3144 return -ENOENT;
3145
Johan Hedbergd8457692012-02-17 14:24:57 +02003146 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003147 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003148
Johan Hedbergaee9b212012-02-18 15:07:59 +02003149 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003150 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003151
Johan Hedberga664b5b2011-02-19 12:06:02 -03003152 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003153
3154 return err;
3155}
3156
Johan Hedberg744cf192011-11-08 20:40:14 +02003157int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003158 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003159{
3160 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003161 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003162 int err;
3163
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003164 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003165 if (!cmd)
3166 return -ENOENT;
3167
Johan Hedbergd8457692012-02-17 14:24:57 +02003168 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003169 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003170
Johan Hedbergaee9b212012-02-18 15:07:59 +02003171 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003172 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003173
Johan Hedberga664b5b2011-02-19 12:06:02 -03003174 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003175
3176 return err;
3177}
Johan Hedberga5c29682011-02-19 12:05:57 -03003178
Johan Hedberg744cf192011-11-08 20:40:14 +02003179int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003180 u8 link_type, u8 addr_type, __le32 value,
3181 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003182{
3183 struct mgmt_ev_user_confirm_request ev;
3184
Johan Hedberg744cf192011-11-08 20:40:14 +02003185 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003186
Johan Hedberg272d90d2012-02-09 15:26:12 +02003187 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003188 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003189 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003190 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003191
Johan Hedberg744cf192011-11-08 20:40:14 +02003192 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003193 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003194}
3195
Johan Hedberg272d90d2012-02-09 15:26:12 +02003196int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3197 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003198{
3199 struct mgmt_ev_user_passkey_request ev;
3200
3201 BT_DBG("%s", hdev->name);
3202
Johan Hedberg272d90d2012-02-09 15:26:12 +02003203 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003204 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003205
3206 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003207 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003208}
3209
Brian Gix0df4c182011-11-16 13:53:13 -08003210static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003211 u8 link_type, u8 addr_type, u8 status,
3212 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003213{
3214 struct pending_cmd *cmd;
3215 struct mgmt_rp_user_confirm_reply rp;
3216 int err;
3217
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003218 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003219 if (!cmd)
3220 return -ENOENT;
3221
Johan Hedberg272d90d2012-02-09 15:26:12 +02003222 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003223 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003224 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003225 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003226
Johan Hedberga664b5b2011-02-19 12:06:02 -03003227 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003228
3229 return err;
3230}
3231
Johan Hedberg744cf192011-11-08 20:40:14 +02003232int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003233 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003234{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003235 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003236 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003237}
3238
Johan Hedberg272d90d2012-02-09 15:26:12 +02003239int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003240 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003241{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003242 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003243 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003244}
Johan Hedberg2a611692011-02-19 12:06:00 -03003245
Brian Gix604086b2011-11-23 08:28:33 -08003246int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003247 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003248{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003249 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003250 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003251}
3252
Johan Hedberg272d90d2012-02-09 15:26:12 +02003253int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003254 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003255{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003256 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003257 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003258}
3259
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003260int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003261 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003262{
3263 struct mgmt_ev_auth_failed ev;
3264
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003265 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003266 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003267 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003268
Johan Hedberg744cf192011-11-08 20:40:14 +02003269 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003270}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003271
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003272int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3273{
3274 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003275 bool changed = false;
3276 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003277
3278 if (status) {
3279 u8 mgmt_err = mgmt_status(status);
3280 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003281 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003282 return 0;
3283 }
3284
Johan Hedberg47990ea2012-02-22 11:58:37 +02003285 if (test_bit(HCI_AUTH, &hdev->flags)) {
3286 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3287 changed = true;
3288 } else {
3289 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3290 changed = true;
3291 }
3292
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003293 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003294 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003295
Johan Hedberg47990ea2012-02-22 11:58:37 +02003296 if (changed)
3297 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003298
3299 if (match.sk)
3300 sock_put(match.sk);
3301
3302 return err;
3303}
3304
Johan Hedbergcacaf522012-02-21 00:52:42 +02003305static int clear_eir(struct hci_dev *hdev)
3306{
3307 struct hci_cp_write_eir cp;
3308
3309 if (!(hdev->features[6] & LMP_EXT_INQ))
3310 return 0;
3311
Johan Hedbergc80da272012-02-22 15:38:48 +02003312 memset(hdev->eir, 0, sizeof(hdev->eir));
3313
Johan Hedbergcacaf522012-02-21 00:52:42 +02003314 memset(&cp, 0, sizeof(cp));
3315
3316 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3317}
3318
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003319int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003320{
3321 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003322 bool changed = false;
3323 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003324
3325 if (status) {
3326 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003327
3328 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003329 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003330 err = new_settings(hdev, NULL);
3331
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003332 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3333 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003334
3335 return err;
3336 }
3337
3338 if (enable) {
3339 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3340 changed = true;
3341 } else {
3342 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3343 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003344 }
3345
3346 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3347
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003348 if (changed)
3349 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003350
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003351 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003352 sock_put(match.sk);
3353
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003354 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3355 update_eir(hdev);
3356 else
3357 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003358
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003359 return err;
3360}
3361
Johan Hedberg90e70452012-02-23 23:09:40 +02003362static void class_rsp(struct pending_cmd *cmd, void *data)
3363{
3364 struct cmd_lookup *match = data;
3365
3366 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003367 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003368
3369 list_del(&cmd->list);
3370
3371 if (match->sk == NULL) {
3372 match->sk = cmd->sk;
3373 sock_hold(match->sk);
3374 }
3375
3376 mgmt_pending_free(cmd);
3377}
3378
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003379int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003380 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003381{
Johan Hedberg90e70452012-02-23 23:09:40 +02003382 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3383 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003384
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003385 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3386
Johan Hedberg90e70452012-02-23 23:09:40 +02003387 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3388 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3389 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3390
3391 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003392 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3393 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003394
3395 if (match.sk)
3396 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003397
3398 return err;
3399}
3400
Johan Hedberg744cf192011-11-08 20:40:14 +02003401int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003402{
3403 struct pending_cmd *cmd;
3404 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003405 bool changed = false;
3406 int err = 0;
3407
3408 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3409 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3410 changed = true;
3411 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003412
3413 memset(&ev, 0, sizeof(ev));
3414 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003415 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003416
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003417 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003418 if (!cmd)
3419 goto send_event;
3420
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003421 /* Always assume that either the short or the complete name has
3422 * changed if there was a pending mgmt command */
3423 changed = true;
3424
Johan Hedbergb312b1612011-03-16 14:29:37 +02003425 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003426 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003427 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003428 goto failed;
3429 }
3430
Johan Hedbergaee9b212012-02-18 15:07:59 +02003431 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003432 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003433 if (err < 0)
3434 goto failed;
3435
3436send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003437 if (changed)
3438 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003439 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003440
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003441 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003442
3443failed:
3444 if (cmd)
3445 mgmt_pending_remove(cmd);
3446 return err;
3447}
Szymon Jancc35938b2011-03-22 13:12:21 +01003448
Johan Hedberg744cf192011-11-08 20:40:14 +02003449int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003450 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003451{
3452 struct pending_cmd *cmd;
3453 int err;
3454
Johan Hedberg744cf192011-11-08 20:40:14 +02003455 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003456
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003457 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003458 if (!cmd)
3459 return -ENOENT;
3460
3461 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003462 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3463 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003464 } else {
3465 struct mgmt_rp_read_local_oob_data rp;
3466
3467 memcpy(rp.hash, hash, sizeof(rp.hash));
3468 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3469
Johan Hedberg744cf192011-11-08 20:40:14 +02003470 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003471 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3472 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003473 }
3474
3475 mgmt_pending_remove(cmd);
3476
3477 return err;
3478}
Johan Hedberge17acd42011-03-30 23:57:16 +03003479
Johan Hedberg06199cf2012-02-22 16:37:11 +02003480int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3481{
3482 struct cmd_lookup match = { NULL, hdev };
3483 bool changed = false;
3484 int err = 0;
3485
3486 if (status) {
3487 u8 mgmt_err = mgmt_status(status);
3488
3489 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003490 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003491 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003492
Szymon Jancd97dcb62012-03-16 16:02:56 +01003493 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3494 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003495
3496 return err;
3497 }
3498
3499 if (enable) {
3500 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3501 changed = true;
3502 } else {
3503 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3504 changed = true;
3505 }
3506
3507 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3508
3509 if (changed)
3510 err = new_settings(hdev, match.sk);
3511
3512 if (match.sk)
3513 sock_put(match.sk);
3514
3515 return err;
3516}
3517
Johan Hedberg48264f02011-11-09 13:58:58 +02003518int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003519 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3520 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003521{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003522 char buf[512];
3523 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003524 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003525
Johan Hedberg1dc06092012-01-15 21:01:23 +02003526 /* Leave 5 bytes for a potential CoD field */
3527 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003528 return -EINVAL;
3529
Johan Hedberg1dc06092012-01-15 21:01:23 +02003530 memset(buf, 0, sizeof(buf));
3531
Johan Hedberge319d2e2012-01-15 19:51:59 +02003532 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003533 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003534 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003535 if (cfm_name)
3536 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003537 if (!ssp)
3538 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003539
Johan Hedberg1dc06092012-01-15 21:01:23 +02003540 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003541 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003542
Johan Hedberg1dc06092012-01-15 21:01:23 +02003543 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3544 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003545 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003546
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003547 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003548
3549 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003550
Johan Hedberge319d2e2012-01-15 19:51:59 +02003551 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003552}
Johan Hedberga88a9652011-03-30 13:18:12 +03003553
Johan Hedbergb644ba32012-01-17 21:48:47 +02003554int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003555 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003556{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003557 struct mgmt_ev_device_found *ev;
3558 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3559 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003560
Johan Hedbergb644ba32012-01-17 21:48:47 +02003561 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003562
Johan Hedbergb644ba32012-01-17 21:48:47 +02003563 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003564
Johan Hedbergb644ba32012-01-17 21:48:47 +02003565 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003566 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003567 ev->rssi = rssi;
3568
3569 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003570 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003571
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003572 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003573
Johan Hedberg053c7e02012-02-04 00:06:00 +02003574 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003575 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003576}
Johan Hedberg314b2382011-04-27 10:29:57 -04003577
Andre Guedes7a135102011-11-09 17:14:25 -03003578int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003579{
3580 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003581 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003582 int err;
3583
Andre Guedes203159d2012-02-13 15:41:01 -03003584 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3585
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003586 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003587 if (!cmd)
3588 return -ENOENT;
3589
Johan Hedbergf808e162012-02-19 12:52:07 +02003590 type = hdev->discovery.type;
3591
3592 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003593 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003594 mgmt_pending_remove(cmd);
3595
3596 return err;
3597}
3598
Andre Guedese6d465c2011-11-09 17:14:26 -03003599int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3600{
3601 struct pending_cmd *cmd;
3602 int err;
3603
3604 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3605 if (!cmd)
3606 return -ENOENT;
3607
Johan Hedbergd9306502012-02-20 23:25:18 +02003608 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003609 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003610 mgmt_pending_remove(cmd);
3611
3612 return err;
3613}
Johan Hedberg314b2382011-04-27 10:29:57 -04003614
Johan Hedberg744cf192011-11-08 20:40:14 +02003615int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003616{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003617 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003618 struct pending_cmd *cmd;
3619
Andre Guedes343fb142011-11-22 17:14:19 -03003620 BT_DBG("%s discovering %u", hdev->name, discovering);
3621
Johan Hedberg164a6e72011-11-01 17:06:44 +02003622 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003623 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003624 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003625 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003626
3627 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003628 u8 type = hdev->discovery.type;
3629
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003630 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3631 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003632 mgmt_pending_remove(cmd);
3633 }
3634
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003635 memset(&ev, 0, sizeof(ev));
3636 ev.type = hdev->discovery.type;
3637 ev.discovering = discovering;
3638
3639 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003640}
Antti Julku5e762442011-08-25 16:48:02 +03003641
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003642int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003643{
3644 struct pending_cmd *cmd;
3645 struct mgmt_ev_device_blocked ev;
3646
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003647 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003648
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003649 bacpy(&ev.addr.bdaddr, bdaddr);
3650 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003651
Johan Hedberg744cf192011-11-08 20:40:14 +02003652 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003653 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003654}
3655
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003656int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003657{
3658 struct pending_cmd *cmd;
3659 struct mgmt_ev_device_unblocked ev;
3660
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003661 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003662
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003663 bacpy(&ev.addr.bdaddr, bdaddr);
3664 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003665
Johan Hedberg744cf192011-11-08 20:40:14 +02003666 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003667 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003668}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003669
3670module_param(enable_hs, bool, 0644);
3671MODULE_PARM_DESC(enable_hs, "Enable High Speed support");
3672
3673module_param(enable_le, bool, 0644);
3674MODULE_PARM_DESC(enable_le, "Enable Low Energy support");