blob: a9cd38dc2cab2f11962c2e598f058f13c53a002c [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
Johan Hedberg02d98122010-12-13 21:07:04 +020037#define MGMT_VERSION 0
38#define MGMT_REVISION 1
39
Johan Hedberge70bb2e2012-02-13 16:59:33 +020040static const u16 mgmt_commands[] = {
41 MGMT_OP_READ_INDEX_LIST,
42 MGMT_OP_READ_INFO,
43 MGMT_OP_SET_POWERED,
44 MGMT_OP_SET_DISCOVERABLE,
45 MGMT_OP_SET_CONNECTABLE,
46 MGMT_OP_SET_FAST_CONNECTABLE,
47 MGMT_OP_SET_PAIRABLE,
48 MGMT_OP_SET_LINK_SECURITY,
49 MGMT_OP_SET_SSP,
50 MGMT_OP_SET_HS,
51 MGMT_OP_SET_LE,
52 MGMT_OP_SET_DEV_CLASS,
53 MGMT_OP_SET_LOCAL_NAME,
54 MGMT_OP_ADD_UUID,
55 MGMT_OP_REMOVE_UUID,
56 MGMT_OP_LOAD_LINK_KEYS,
57 MGMT_OP_LOAD_LONG_TERM_KEYS,
58 MGMT_OP_DISCONNECT,
59 MGMT_OP_GET_CONNECTIONS,
60 MGMT_OP_PIN_CODE_REPLY,
61 MGMT_OP_PIN_CODE_NEG_REPLY,
62 MGMT_OP_SET_IO_CAPABILITY,
63 MGMT_OP_PAIR_DEVICE,
64 MGMT_OP_CANCEL_PAIR_DEVICE,
65 MGMT_OP_UNPAIR_DEVICE,
66 MGMT_OP_USER_CONFIRM_REPLY,
67 MGMT_OP_USER_CONFIRM_NEG_REPLY,
68 MGMT_OP_USER_PASSKEY_REPLY,
69 MGMT_OP_USER_PASSKEY_NEG_REPLY,
70 MGMT_OP_READ_LOCAL_OOB_DATA,
71 MGMT_OP_ADD_REMOTE_OOB_DATA,
72 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
73 MGMT_OP_START_DISCOVERY,
74 MGMT_OP_STOP_DISCOVERY,
75 MGMT_OP_CONFIRM_NAME,
76 MGMT_OP_BLOCK_DEVICE,
77 MGMT_OP_UNBLOCK_DEVICE,
78};
79
80static const u16 mgmt_events[] = {
81 MGMT_EV_CONTROLLER_ERROR,
82 MGMT_EV_INDEX_ADDED,
83 MGMT_EV_INDEX_REMOVED,
84 MGMT_EV_NEW_SETTINGS,
85 MGMT_EV_CLASS_OF_DEV_CHANGED,
86 MGMT_EV_LOCAL_NAME_CHANGED,
87 MGMT_EV_NEW_LINK_KEY,
88 MGMT_EV_NEW_LONG_TERM_KEY,
89 MGMT_EV_DEVICE_CONNECTED,
90 MGMT_EV_DEVICE_DISCONNECTED,
91 MGMT_EV_CONNECT_FAILED,
92 MGMT_EV_PIN_CODE_REQUEST,
93 MGMT_EV_USER_CONFIRM_REQUEST,
94 MGMT_EV_USER_PASSKEY_REQUEST,
95 MGMT_EV_AUTH_FAILED,
96 MGMT_EV_DEVICE_FOUND,
97 MGMT_EV_DISCOVERING,
98 MGMT_EV_DEVICE_BLOCKED,
99 MGMT_EV_DEVICE_UNBLOCKED,
100 MGMT_EV_DEVICE_UNPAIRED,
101};
102
Andre Guedes3fd24152012-02-03 17:48:01 -0300103/*
104 * These LE scan and inquiry parameters were chosen according to LE General
105 * Discovery Procedure specification.
106 */
107#define LE_SCAN_TYPE 0x01
108#define LE_SCAN_WIN 0x12
109#define LE_SCAN_INT 0x12
110#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
111
Andre Guedese8777522012-02-03 17:48:02 -0300112#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300113
Johan Hedberg7d785252011-12-15 00:47:39 +0200114#define SERVICE_CACHE_TIMEOUT (5 * 1000)
115
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200116struct pending_cmd {
117 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200118 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200119 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100120 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200121 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300122 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200123};
124
Johan Hedbergca69b792011-11-11 18:10:00 +0200125/* HCI to MGMT error code conversion table */
126static u8 mgmt_status_table[] = {
127 MGMT_STATUS_SUCCESS,
128 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
129 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
130 MGMT_STATUS_FAILED, /* Hardware Failure */
131 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
132 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
133 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
134 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
135 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
136 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
137 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
138 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
139 MGMT_STATUS_BUSY, /* Command Disallowed */
140 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
141 MGMT_STATUS_REJECTED, /* Rejected Security */
142 MGMT_STATUS_REJECTED, /* Rejected Personal */
143 MGMT_STATUS_TIMEOUT, /* Host Timeout */
144 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
145 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
146 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
147 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
148 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
149 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
150 MGMT_STATUS_BUSY, /* Repeated Attempts */
151 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
152 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
153 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
154 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
155 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
156 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
157 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
158 MGMT_STATUS_FAILED, /* Unspecified Error */
159 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
160 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
161 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
162 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
163 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
164 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
165 MGMT_STATUS_FAILED, /* Unit Link Key Used */
166 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
167 MGMT_STATUS_TIMEOUT, /* Instant Passed */
168 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
169 MGMT_STATUS_FAILED, /* Transaction Collision */
170 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
171 MGMT_STATUS_REJECTED, /* QoS Rejected */
172 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
173 MGMT_STATUS_REJECTED, /* Insufficient Security */
174 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
175 MGMT_STATUS_BUSY, /* Role Switch Pending */
176 MGMT_STATUS_FAILED, /* Slot Violation */
177 MGMT_STATUS_FAILED, /* Role Switch Failed */
178 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
179 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
180 MGMT_STATUS_BUSY, /* Host Busy Pairing */
181 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
182 MGMT_STATUS_BUSY, /* Controller Busy */
183 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
184 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
185 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
186 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
187 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
188};
189
190static u8 mgmt_status(u8 hci_status)
191{
192 if (hci_status < ARRAY_SIZE(mgmt_status_table))
193 return mgmt_status_table[hci_status];
194
195 return MGMT_STATUS_FAILED;
196}
197
Szymon Janc4e51eae2011-02-25 19:05:48 +0100198static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200199{
200 struct sk_buff *skb;
201 struct mgmt_hdr *hdr;
202 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300203 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200204
Szymon Janc34eb5252011-02-28 14:10:08 +0100205 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200206
207 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
208 if (!skb)
209 return -ENOMEM;
210
211 hdr = (void *) skb_put(skb, sizeof(*hdr));
212
213 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100214 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200215 hdr->len = cpu_to_le16(sizeof(*ev));
216
217 ev = (void *) skb_put(skb, sizeof(*ev));
218 ev->status = status;
219 put_unaligned_le16(cmd, &ev->opcode);
220
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300221 err = sock_queue_rcv_skb(sk, skb);
222 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200223 kfree_skb(skb);
224
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300225 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200226}
227
Szymon Janc4e51eae2011-02-25 19:05:48 +0100228static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
229 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200230{
231 struct sk_buff *skb;
232 struct mgmt_hdr *hdr;
233 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300234 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200235
236 BT_DBG("sock %p", sk);
237
Johan Hedberga38528f2011-01-22 06:46:43 +0200238 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200239 if (!skb)
240 return -ENOMEM;
241
242 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200243
Johan Hedberg02d98122010-12-13 21:07:04 +0200244 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100245 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247
Johan Hedberga38528f2011-01-22 06:46:43 +0200248 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
249 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100250
251 if (rp)
252 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200253
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300254 err = sock_queue_rcv_skb(sk, skb);
255 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200256 kfree_skb(skb);
257
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300258 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200259}
260
Johan Hedberga38528f2011-01-22 06:46:43 +0200261static int read_version(struct sock *sk)
262{
263 struct mgmt_rp_read_version rp;
264
265 BT_DBG("sock %p", sk);
266
267 rp.version = MGMT_VERSION;
268 put_unaligned_le16(MGMT_REVISION, &rp.revision);
269
Szymon Janc4e51eae2011-02-25 19:05:48 +0100270 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
271 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200272}
273
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200274static int read_commands(struct sock *sk)
275{
276 struct mgmt_rp_read_commands *rp;
277 u16 num_commands = ARRAY_SIZE(mgmt_commands);
278 u16 num_events = ARRAY_SIZE(mgmt_events);
279 u16 *opcode;
280 size_t rp_size;
281 int i, err;
282
283 BT_DBG("sock %p", sk);
284
285 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
286
287 rp = kmalloc(rp_size, GFP_KERNEL);
288 if (!rp)
289 return -ENOMEM;
290
291 put_unaligned_le16(num_commands, &rp->num_commands);
292 put_unaligned_le16(num_events, &rp->num_events);
293
294 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
295 put_unaligned_le16(mgmt_commands[i], opcode);
296
297 for (i = 0; i < num_events; i++, opcode++)
298 put_unaligned_le16(mgmt_events[i], opcode);
299
300 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, rp,
301 rp_size);
302 kfree(rp);
303
304 return err;
305}
306
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200307static int read_index_list(struct sock *sk)
308{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200309 struct mgmt_rp_read_index_list *rp;
310 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200311 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200312 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200314 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200315
316 BT_DBG("sock %p", sk);
317
318 read_lock(&hci_dev_list_lock);
319
320 count = 0;
321 list_for_each(p, &hci_dev_list) {
322 count++;
323 }
324
Johan Hedberga38528f2011-01-22 06:46:43 +0200325 rp_len = sizeof(*rp) + (2 * count);
326 rp = kmalloc(rp_len, GFP_ATOMIC);
327 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100328 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200329 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100330 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200331
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200332 put_unaligned_le16(count, &rp->num_controllers);
333
334 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200335 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200336 if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200337 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200338
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200339 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200340 continue;
341
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200342 put_unaligned_le16(d->id, &rp->index[i++]);
343 BT_DBG("Added hci%u", d->id);
344 }
345
346 read_unlock(&hci_dev_list_lock);
347
Szymon Janc4e51eae2011-02-25 19:05:48 +0100348 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
349 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350
Johan Hedberga38528f2011-01-22 06:46:43 +0200351 kfree(rp);
352
353 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200354}
355
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200356static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200357{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200358 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200359
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200360 settings |= MGMT_SETTING_POWERED;
361 settings |= MGMT_SETTING_CONNECTABLE;
362 settings |= MGMT_SETTING_FAST_CONNECTABLE;
363 settings |= MGMT_SETTING_DISCOVERABLE;
364 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200365
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200366 if (hdev->features[6] & LMP_SIMPLE_PAIR)
367 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 if (!(hdev->features[4] & LMP_NO_BREDR)) {
370 settings |= MGMT_SETTING_BREDR;
371 settings |= MGMT_SETTING_LINK_SECURITY;
372 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200373
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200374 if (hdev->features[4] & LMP_LE)
375 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200376
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200377 return settings;
378}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200379
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200380static u32 get_current_settings(struct hci_dev *hdev)
381{
382 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200383
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200384 if (test_bit(HCI_UP, &hdev->flags))
385 settings |= MGMT_SETTING_POWERED;
386 else
387 return settings;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200388
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389 if (test_bit(HCI_PSCAN, &hdev->flags))
390 settings |= MGMT_SETTING_CONNECTABLE;
391
392 if (test_bit(HCI_ISCAN, &hdev->flags))
393 settings |= MGMT_SETTING_DISCOVERABLE;
394
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200395 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200396 settings |= MGMT_SETTING_PAIRABLE;
397
398 if (!(hdev->features[4] & LMP_NO_BREDR))
399 settings |= MGMT_SETTING_BREDR;
400
Andre Guedes59e29402011-12-30 10:34:03 -0300401 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200402 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200403
404 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200406
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200407 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200409
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200411}
412
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300413#define PNP_INFO_SVCLASS_ID 0x1200
414
415static u8 bluetooth_base_uuid[] = {
416 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
417 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
418};
419
420static u16 get_uuid16(u8 *uuid128)
421{
422 u32 val;
423 int i;
424
425 for (i = 0; i < 12; i++) {
426 if (bluetooth_base_uuid[i] != uuid128[i])
427 return 0;
428 }
429
430 memcpy(&val, &uuid128[12], 4);
431
432 val = le32_to_cpu(val);
433 if (val > 0xffff)
434 return 0;
435
436 return (u16) val;
437}
438
439static void create_eir(struct hci_dev *hdev, u8 *data)
440{
441 u8 *ptr = data;
442 u16 eir_len = 0;
443 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
444 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200445 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300446 size_t name_len;
447
448 name_len = strlen(hdev->dev_name);
449
450 if (name_len > 0) {
451 /* EIR Data type */
452 if (name_len > 48) {
453 name_len = 48;
454 ptr[1] = EIR_NAME_SHORT;
455 } else
456 ptr[1] = EIR_NAME_COMPLETE;
457
458 /* EIR Data length */
459 ptr[0] = name_len + 1;
460
461 memcpy(ptr + 2, hdev->dev_name, name_len);
462
463 eir_len += (name_len + 2);
464 ptr += (name_len + 2);
465 }
466
467 memset(uuid16_list, 0, sizeof(uuid16_list));
468
469 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200470 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300471 u16 uuid16;
472
473 uuid16 = get_uuid16(uuid->uuid);
474 if (uuid16 == 0)
475 return;
476
477 if (uuid16 < 0x1100)
478 continue;
479
480 if (uuid16 == PNP_INFO_SVCLASS_ID)
481 continue;
482
483 /* Stop if not enough space to put next UUID */
484 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
485 truncated = 1;
486 break;
487 }
488
489 /* Check for duplicates */
490 for (i = 0; uuid16_list[i] != 0; i++)
491 if (uuid16_list[i] == uuid16)
492 break;
493
494 if (uuid16_list[i] == 0) {
495 uuid16_list[i] = uuid16;
496 eir_len += sizeof(u16);
497 }
498 }
499
500 if (uuid16_list[0] != 0) {
501 u8 *length = ptr;
502
503 /* EIR Data type */
504 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
505
506 ptr += 2;
507 eir_len += 2;
508
509 for (i = 0; uuid16_list[i] != 0; i++) {
510 *ptr++ = (uuid16_list[i] & 0x00ff);
511 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
512 }
513
514 /* EIR Data length */
515 *length = (i * sizeof(u16)) + 1;
516 }
517}
518
519static int update_eir(struct hci_dev *hdev)
520{
521 struct hci_cp_write_eir cp;
522
523 if (!(hdev->features[6] & LMP_EXT_INQ))
524 return 0;
525
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200526 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300527 return 0;
528
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200529 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300530 return 0;
531
532 memset(&cp, 0, sizeof(cp));
533
534 create_eir(hdev, cp.data);
535
536 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
537 return 0;
538
539 memcpy(hdev->eir, cp.data, sizeof(cp.data));
540
541 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
542}
543
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200544static u8 get_service_classes(struct hci_dev *hdev)
545{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300546 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200547 u8 val = 0;
548
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300549 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200550 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200551
552 return val;
553}
554
555static int update_class(struct hci_dev *hdev)
556{
557 u8 cod[3];
558
559 BT_DBG("%s", hdev->name);
560
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200561 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200562 return 0;
563
564 cod[0] = hdev->minor_class;
565 cod[1] = hdev->major_class;
566 cod[2] = get_service_classes(hdev);
567
568 if (memcmp(cod, hdev->dev_class, 3) == 0)
569 return 0;
570
571 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
572}
573
Johan Hedberg7d785252011-12-15 00:47:39 +0200574static void service_cache_off(struct work_struct *work)
575{
576 struct hci_dev *hdev = container_of(work, struct hci_dev,
577 service_cache.work);
578
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200579 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200580 return;
581
582 hci_dev_lock(hdev);
583
584 update_eir(hdev);
585 update_class(hdev);
586
587 hci_dev_unlock(hdev);
588}
589
590static void mgmt_init_hdev(struct hci_dev *hdev)
591{
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200592 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200593 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
594
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200595 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200596 schedule_delayed_work(&hdev->service_cache,
597 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
598}
599
Johan Hedberg03811012010-12-08 00:21:06 +0200600static int read_controller_info(struct sock *sk, u16 index)
601{
602 struct mgmt_rp_read_info rp;
603 struct hci_dev *hdev;
604
605 BT_DBG("sock %p hci%u", sk, index);
606
607 hdev = hci_dev_get(index);
608 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200609 return cmd_status(sk, index, MGMT_OP_READ_INFO,
610 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200611
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200612 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
Johan Hedberg03811012010-12-08 00:21:06 +0200613 cancel_delayed_work_sync(&hdev->power_off);
614
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300615 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200616
Johan Hedberg7d785252011-12-15 00:47:39 +0200617 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
618 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200619
620 memset(&rp, 0, sizeof(rp));
621
Johan Hedberg03811012010-12-08 00:21:06 +0200622 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200623
624 rp.version = hdev->hci_ver;
625
Johan Hedberg03811012010-12-08 00:21:06 +0200626 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200627
628 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
629 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
630
631 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200632
633 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
634
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300635 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200636 hci_dev_put(hdev);
637
638 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
639}
640
641static void mgmt_pending_free(struct pending_cmd *cmd)
642{
643 sock_put(cmd->sk);
644 kfree(cmd->param);
645 kfree(cmd);
646}
647
648static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
649 struct hci_dev *hdev,
650 void *data, u16 len)
651{
652 struct pending_cmd *cmd;
653
654 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
655 if (!cmd)
656 return NULL;
657
658 cmd->opcode = opcode;
659 cmd->index = hdev->id;
660
661 cmd->param = kmalloc(len, GFP_ATOMIC);
662 if (!cmd->param) {
663 kfree(cmd);
664 return NULL;
665 }
666
667 if (data)
668 memcpy(cmd->param, data, len);
669
670 cmd->sk = sk;
671 sock_hold(sk);
672
673 list_add(&cmd->list, &hdev->mgmt_pending);
674
675 return cmd;
676}
677
678static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
679 void (*cb)(struct pending_cmd *cmd, void *data),
680 void *data)
681{
682 struct list_head *p, *n;
683
684 list_for_each_safe(p, n, &hdev->mgmt_pending) {
685 struct pending_cmd *cmd;
686
687 cmd = list_entry(p, struct pending_cmd, list);
688
689 if (opcode > 0 && cmd->opcode != opcode)
690 continue;
691
692 cb(cmd, data);
693 }
694}
695
696static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
697{
698 struct pending_cmd *cmd;
699
700 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
701 if (cmd->opcode == opcode)
702 return cmd;
703 }
704
705 return NULL;
706}
707
708static void mgmt_pending_remove(struct pending_cmd *cmd)
709{
710 list_del(&cmd->list);
711 mgmt_pending_free(cmd);
712}
713
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200714static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200715{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200716 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200717
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200718 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200719}
720
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300721static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200722{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300723 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200724 struct hci_dev *hdev;
725 struct pending_cmd *cmd;
726 int err, up;
727
Johan Hedberg03811012010-12-08 00:21:06 +0200728 BT_DBG("request for hci%u", index);
729
730 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200731 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
732 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200733
734 hdev = hci_dev_get(index);
735 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200736 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
737 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200738
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300739 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200740
741 up = test_bit(HCI_UP, &hdev->flags);
742 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200743 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200744 goto failed;
745 }
746
747 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200748 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
749 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200750 goto failed;
751 }
752
753 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
754 if (!cmd) {
755 err = -ENOMEM;
756 goto failed;
757 }
758
759 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200760 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200761 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200762 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200763
764 err = 0;
765
766failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300767 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200768 hci_dev_put(hdev);
769 return err;
770}
771
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300772static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200773{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300774 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200775 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200776 struct pending_cmd *cmd;
777 u8 scan;
778 int err;
779
Johan Hedberg03811012010-12-08 00:21:06 +0200780 BT_DBG("request for hci%u", index);
781
782 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200783 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
784 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200785
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200786 hdev = hci_dev_get(index);
787 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200788 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
789 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200790
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300791 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200792
793 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200794 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
795 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200796 goto failed;
797 }
798
799 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
800 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200801 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
802 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200803 goto failed;
804 }
805
806 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
807 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200808 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200809 goto failed;
810 }
811
812 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
813 if (!cmd) {
814 err = -ENOMEM;
815 goto failed;
816 }
817
818 scan = SCAN_PAGE;
819
820 if (cp->val)
821 scan |= SCAN_INQUIRY;
822 else
823 cancel_delayed_work(&hdev->discov_off);
824
825 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
826 if (err < 0)
827 mgmt_pending_remove(cmd);
828
Johan Hedberg03811012010-12-08 00:21:06 +0200829 if (cp->val)
830 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
831
Johan Hedberge41d8b42010-12-13 21:07:03 +0200832failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300833 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200834 hci_dev_put(hdev);
835
836 return err;
837}
838
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300839static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200840{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300841 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200842 struct hci_dev *hdev;
843 struct pending_cmd *cmd;
844 u8 scan;
845 int err;
846
Johan Hedberge41d8b42010-12-13 21:07:03 +0200847 BT_DBG("request for hci%u", index);
848
Johan Hedberg03811012010-12-08 00:21:06 +0200849 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200850 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
851 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200852
853 hdev = hci_dev_get(index);
854 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200855 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
856 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300858 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200859
860 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200861 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
862 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200863 goto failed;
864 }
865
866 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
867 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200868 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
869 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200870 goto failed;
871 }
872
873 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200874 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200875 goto failed;
876 }
877
878 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
879 if (!cmd) {
880 err = -ENOMEM;
881 goto failed;
882 }
883
884 if (cp->val)
885 scan = SCAN_PAGE;
886 else
887 scan = 0;
888
889 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
890 if (err < 0)
891 mgmt_pending_remove(cmd);
892
893failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300894 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200895 hci_dev_put(hdev);
896
897 return err;
898}
899
900static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
901 u16 data_len, struct sock *skip_sk)
902{
903 struct sk_buff *skb;
904 struct mgmt_hdr *hdr;
905
906 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
907 if (!skb)
908 return -ENOMEM;
909
910 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
911
912 hdr = (void *) skb_put(skb, sizeof(*hdr));
913 hdr->opcode = cpu_to_le16(event);
914 if (hdev)
915 hdr->index = cpu_to_le16(hdev->id);
916 else
917 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
918 hdr->len = cpu_to_le16(data_len);
919
920 if (data)
921 memcpy(skb_put(skb, data_len), data, data_len);
922
923 hci_send_to_sock(NULL, skb, skip_sk);
924 kfree_skb(skb);
925
926 return 0;
927}
928
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300929static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200930{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300931 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200932 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200933 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200934 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200935
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200936 BT_DBG("request for hci%u", index);
937
938 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200939 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
940 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200941
942 hdev = hci_dev_get(index);
943 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200944 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
945 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200946
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300947 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200948
949 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200950 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200951 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200952 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200953
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200954 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200955 if (err < 0)
956 goto failed;
957
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200958 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200959
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200960 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200961
962failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300963 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200964 hci_dev_put(hdev);
965
966 return err;
967}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200968
Johan Hedberg33ef95e2012-02-16 23:56:27 +0200969static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
970{
971 struct mgmt_mode *cp = data;
972 struct pending_cmd *cmd;
973 struct hci_dev *hdev;
974 uint8_t val;
975 int err;
976
977 BT_DBG("request for hci%u", index);
978
979 if (len != sizeof(*cp))
980 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
981 MGMT_STATUS_INVALID_PARAMS);
982
983 hdev = hci_dev_get(index);
984 if (!hdev)
985 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
986 MGMT_STATUS_INVALID_PARAMS);
987
988 hci_dev_lock(hdev);
989
990 if (!test_bit(HCI_UP, &hdev->flags)) {
991 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
992 MGMT_STATUS_NOT_POWERED);
993 goto failed;
994 }
995
996 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
997 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
998 MGMT_STATUS_BUSY);
999 goto failed;
1000 }
1001
1002 val = !!cp->val;
1003
1004 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1005 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1006 goto failed;
1007 }
1008
1009 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1010 if (!cmd) {
1011 err = -ENOMEM;
1012 goto failed;
1013 }
1014
1015 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1016 if (err < 0) {
1017 mgmt_pending_remove(cmd);
1018 goto failed;
1019 }
1020
1021failed:
1022 hci_dev_unlock(hdev);
1023 hci_dev_put(hdev);
1024
1025 return err;
1026}
1027
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001028static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1029{
1030 struct mgmt_mode *cp = data;
1031 struct pending_cmd *cmd;
1032 struct hci_dev *hdev;
1033 uint8_t val;
1034 int err;
1035
1036 BT_DBG("request for hci%u", index);
1037
1038 if (len != sizeof(*cp))
1039 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1040 MGMT_STATUS_INVALID_PARAMS);
1041
1042 hdev = hci_dev_get(index);
1043 if (!hdev)
1044 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1045 MGMT_STATUS_INVALID_PARAMS);
1046
1047 hci_dev_lock(hdev);
1048
1049 if (!test_bit(HCI_UP, &hdev->flags)) {
1050 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1051 MGMT_STATUS_NOT_POWERED);
1052 goto failed;
1053 }
1054
1055 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1056 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1057 goto failed;
1058 }
1059
1060 val = !!cp->val;
1061
1062 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1063 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1064 goto failed;
1065 }
1066
1067 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1068 if (!cmd) {
1069 err = -ENOMEM;
1070 goto failed;
1071 }
1072
1073 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1074 if (err < 0) {
1075 mgmt_pending_remove(cmd);
1076 goto failed;
1077 }
1078
1079failed:
1080 hci_dev_unlock(hdev);
1081 hci_dev_put(hdev);
1082
1083 return err;
1084}
1085
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001086static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001087{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001088 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001089 struct hci_dev *hdev;
1090 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001091 int err;
1092
Szymon Janc4e51eae2011-02-25 19:05:48 +01001093 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001094
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001095 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001096 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1097 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001098
Szymon Janc4e51eae2011-02-25 19:05:48 +01001099 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001100 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001101 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1102 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001103
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001104 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001105
1106 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1107 if (!uuid) {
1108 err = -ENOMEM;
1109 goto failed;
1110 }
1111
1112 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001113 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001114
1115 list_add(&uuid->list, &hdev->uuids);
1116
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001117 err = update_class(hdev);
1118 if (err < 0)
1119 goto failed;
1120
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001121 err = update_eir(hdev);
1122 if (err < 0)
1123 goto failed;
1124
Szymon Janc4e51eae2011-02-25 19:05:48 +01001125 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001126
1127failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001128 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001129 hci_dev_put(hdev);
1130
1131 return err;
1132}
1133
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001134static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001135{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001136 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001137 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001138 struct hci_dev *hdev;
1139 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 +02001140 int err, found;
1141
Szymon Janc4e51eae2011-02-25 19:05:48 +01001142 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001143
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001144 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001145 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1146 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001147
Szymon Janc4e51eae2011-02-25 19:05:48 +01001148 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001149 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001150 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1151 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001152
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001153 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001154
1155 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1156 err = hci_uuids_clear(hdev);
1157 goto unlock;
1158 }
1159
1160 found = 0;
1161
1162 list_for_each_safe(p, n, &hdev->uuids) {
1163 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1164
1165 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1166 continue;
1167
1168 list_del(&match->list);
1169 found++;
1170 }
1171
1172 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001173 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1174 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001175 goto unlock;
1176 }
1177
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001178 err = update_class(hdev);
1179 if (err < 0)
1180 goto unlock;
1181
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001182 err = update_eir(hdev);
1183 if (err < 0)
1184 goto unlock;
1185
Szymon Janc4e51eae2011-02-25 19:05:48 +01001186 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001187
1188unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001189 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001190 hci_dev_put(hdev);
1191
1192 return err;
1193}
1194
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001195static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001196{
1197 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001198 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001199 int err;
1200
Szymon Janc4e51eae2011-02-25 19:05:48 +01001201 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001202
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001203 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001204 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1205 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001206
Szymon Janc4e51eae2011-02-25 19:05:48 +01001207 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001208 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001209 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1210 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001211
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001212 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001213
1214 hdev->major_class = cp->major;
1215 hdev->minor_class = cp->minor;
1216
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001217 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001218 hci_dev_unlock(hdev);
1219 cancel_delayed_work_sync(&hdev->service_cache);
1220 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001221 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001222 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001223
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001224 err = update_class(hdev);
1225
1226 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001227 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001228
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001229 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001230 hci_dev_put(hdev);
1231
1232 return err;
1233}
1234
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001235static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001236{
1237 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001238 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001239 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001240 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001241
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001242 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001243 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1244 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001245
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001246 key_count = get_unaligned_le16(&cp->key_count);
1247
Johan Hedberg86742e12011-11-07 23:13:38 +02001248 expected_len = sizeof(*cp) + key_count *
1249 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001250 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001251 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001252 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001253 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1254 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001255 }
1256
Szymon Janc4e51eae2011-02-25 19:05:48 +01001257 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001258 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001259 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1260 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001261
Szymon Janc4e51eae2011-02-25 19:05:48 +01001262 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001263 key_count);
1264
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001265 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001266
1267 hci_link_keys_clear(hdev);
1268
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001269 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001270
1271 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001272 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001273 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001274 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001275
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001276 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001277 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001278
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001279 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1280 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001281 }
1282
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001283 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1284
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001285 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001286 hci_dev_put(hdev);
1287
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001288 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001289}
1290
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001291static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1292 u8 addr_type, struct sock *skip_sk)
1293{
1294 struct mgmt_ev_device_unpaired ev;
1295
1296 bacpy(&ev.addr.bdaddr, bdaddr);
1297 ev.addr.type = addr_type;
1298
1299 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1300 skip_sk);
1301}
1302
Johan Hedberg124f6e32012-02-09 13:50:12 +02001303static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001304{
1305 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001306 struct mgmt_cp_unpair_device *cp = data;
1307 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001308 struct hci_cp_disconnect dc;
1309 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001310 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001311 int err;
1312
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001313 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001314 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001315 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001316
Szymon Janc4e51eae2011-02-25 19:05:48 +01001317 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001318 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001319 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001320 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001321
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001322 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001323
Johan Hedberga8a1d192011-11-10 15:54:38 +02001324 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001325 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1326 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001327
Johan Hedberg124f6e32012-02-09 13:50:12 +02001328 if (cp->addr.type == MGMT_ADDR_BREDR)
1329 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1330 else
1331 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001332
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001333 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001334 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001335 goto unlock;
1336 }
1337
Johan Hedberga8a1d192011-11-10 15:54:38 +02001338 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02001339 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001340 sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001341 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001342 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001343 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001344
Johan Hedberg124f6e32012-02-09 13:50:12 +02001345 if (cp->addr.type == MGMT_ADDR_BREDR)
1346 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1347 &cp->addr.bdaddr);
1348 else
1349 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1350 &cp->addr.bdaddr);
1351
Johan Hedberga8a1d192011-11-10 15:54:38 +02001352 if (!conn) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02001353 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001354 sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001355 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001356 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001357 }
1358
Johan Hedberg124f6e32012-02-09 13:50:12 +02001359 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1360 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001361 if (!cmd) {
1362 err = -ENOMEM;
1363 goto unlock;
1364 }
1365
1366 put_unaligned_le16(conn->handle, &dc.handle);
1367 dc.reason = 0x13; /* Remote User Terminated Connection */
1368 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1369 if (err < 0)
1370 mgmt_pending_remove(cmd);
1371
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001372unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001373 if (err < 0)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001374 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001375 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001376 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001377 hci_dev_put(hdev);
1378
1379 return err;
1380}
1381
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001382static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001383{
1384 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001385 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001386 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001387 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001388 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001389 int err;
1390
1391 BT_DBG("");
1392
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001393 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001394 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1395 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001396
Szymon Janc4e51eae2011-02-25 19:05:48 +01001397 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001398 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001399 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1400 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001401
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001402 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001403
1404 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001405 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1406 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001407 goto failed;
1408 }
1409
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001410 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001411 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1412 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001413 goto failed;
1414 }
1415
Johan Hedberg88c3df12012-02-09 14:27:38 +02001416 if (cp->addr.type == MGMT_ADDR_BREDR)
1417 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1418 else
1419 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001420
Johan Hedberg8962ee72011-01-20 12:40:27 +02001421 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001422 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1423 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001424 goto failed;
1425 }
1426
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001427 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001428 if (!cmd) {
1429 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001430 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001431 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001432
1433 put_unaligned_le16(conn->handle, &dc.handle);
1434 dc.reason = 0x13; /* Remote User Terminated Connection */
1435
1436 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1437 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001438 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001439
1440failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001441 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001442 hci_dev_put(hdev);
1443
1444 return err;
1445}
1446
Johan Hedberg48264f02011-11-09 13:58:58 +02001447static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001448{
1449 switch (link_type) {
1450 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001451 switch (addr_type) {
1452 case ADDR_LE_DEV_PUBLIC:
1453 return MGMT_ADDR_LE_PUBLIC;
1454 case ADDR_LE_DEV_RANDOM:
1455 return MGMT_ADDR_LE_RANDOM;
1456 default:
1457 return MGMT_ADDR_INVALID;
1458 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001459 case ACL_LINK:
1460 return MGMT_ADDR_BREDR;
1461 default:
1462 return MGMT_ADDR_INVALID;
1463 }
1464}
1465
Szymon Janc8ce62842011-03-01 16:55:32 +01001466static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001467{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001468 struct mgmt_rp_get_connections *rp;
1469 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001470 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001471 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001472 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001473 int i, err;
1474
1475 BT_DBG("");
1476
Szymon Janc4e51eae2011-02-25 19:05:48 +01001477 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001478 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001479 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1480 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001481
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001482 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001483
1484 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001485 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1486 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1487 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001488 }
1489
Johan Hedberg4c659c32011-11-07 23:13:39 +02001490 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001491 rp = kmalloc(rp_len, GFP_ATOMIC);
1492 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001493 err = -ENOMEM;
1494 goto unlock;
1495 }
1496
Johan Hedberg2784eb42011-01-21 13:56:35 +02001497 put_unaligned_le16(count, &rp->conn_count);
1498
Johan Hedberg2784eb42011-01-21 13:56:35 +02001499 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001500 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001501 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1502 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001503 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001504 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001505 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1506 continue;
1507 i++;
1508 }
1509
1510 /* Recalculate length in case of filtered SCO connections, etc */
1511 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001512
Szymon Janc4e51eae2011-02-25 19:05:48 +01001513 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001514
1515unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001516 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001517 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001518 hci_dev_put(hdev);
1519 return err;
1520}
1521
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001522static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1523 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1524{
1525 struct pending_cmd *cmd;
1526 int err;
1527
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001528 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001529 sizeof(*cp));
1530 if (!cmd)
1531 return -ENOMEM;
1532
Johan Hedbergd8457692012-02-17 14:24:57 +02001533 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1534 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001535 if (err < 0)
1536 mgmt_pending_remove(cmd);
1537
1538 return err;
1539}
1540
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001541static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001542{
1543 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001544 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001545 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001546 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001547 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001548 int err;
1549
1550 BT_DBG("");
1551
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001552 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001553 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1554 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001555
Szymon Janc4e51eae2011-02-25 19:05:48 +01001556 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001557 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001558 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1559 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001560
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001561 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001562
1563 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001564 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1565 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001566 goto failed;
1567 }
1568
Johan Hedbergd8457692012-02-17 14:24:57 +02001569 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001570 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001571 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1572 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001573 goto failed;
1574 }
1575
1576 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001577 struct mgmt_cp_pin_code_neg_reply ncp;
1578
1579 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001580
1581 BT_ERR("PIN code is not 16 bytes long");
1582
1583 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1584 if (err >= 0)
1585 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001586 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001587
1588 goto failed;
1589 }
1590
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001591 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1592 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001593 if (!cmd) {
1594 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001595 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001596 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001597
Johan Hedbergd8457692012-02-17 14:24:57 +02001598 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001599 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001600 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001601
1602 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1603 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001604 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001605
1606failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001607 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001608 hci_dev_put(hdev);
1609
1610 return err;
1611}
1612
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001613static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001614{
1615 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001616 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001617 int err;
1618
1619 BT_DBG("");
1620
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001621 if (len != sizeof(*cp))
1622 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001623 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001624
Szymon Janc4e51eae2011-02-25 19:05:48 +01001625 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001626 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001627 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001628 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001629
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001630 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001631
1632 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001633 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001634 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001635 goto failed;
1636 }
1637
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001638 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001639
1640failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001641 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001642 hci_dev_put(hdev);
1643
1644 return err;
1645}
1646
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001647static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001648{
1649 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001650 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001651
1652 BT_DBG("");
1653
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001654 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001655 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1656 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001657
Szymon Janc4e51eae2011-02-25 19:05:48 +01001658 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001659 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001660 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1661 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001662
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001663 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001664
1665 hdev->io_capability = cp->io_capability;
1666
1667 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001668 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001669
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001670 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001671 hci_dev_put(hdev);
1672
Szymon Janc4e51eae2011-02-25 19:05:48 +01001673 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001674}
1675
Johan Hedberge9a416b2011-02-19 12:05:56 -03001676static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1677{
1678 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001679 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001680
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001681 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001682 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1683 continue;
1684
Johan Hedberge9a416b2011-02-19 12:05:56 -03001685 if (cmd->user_data != conn)
1686 continue;
1687
1688 return cmd;
1689 }
1690
1691 return NULL;
1692}
1693
1694static void pairing_complete(struct pending_cmd *cmd, u8 status)
1695{
1696 struct mgmt_rp_pair_device rp;
1697 struct hci_conn *conn = cmd->user_data;
1698
Johan Hedbergba4e5642011-11-11 00:07:34 +02001699 bacpy(&rp.addr.bdaddr, &conn->dst);
1700 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001701 rp.status = status;
1702
Szymon Janc4e51eae2011-02-25 19:05:48 +01001703 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001704
1705 /* So we don't get further callbacks for this connection */
1706 conn->connect_cfm_cb = NULL;
1707 conn->security_cfm_cb = NULL;
1708 conn->disconn_cfm_cb = NULL;
1709
1710 hci_conn_put(conn);
1711
Johan Hedberga664b5b2011-02-19 12:06:02 -03001712 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001713}
1714
1715static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1716{
1717 struct pending_cmd *cmd;
1718
1719 BT_DBG("status %u", status);
1720
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001721 cmd = find_pairing(conn);
1722 if (!cmd)
1723 BT_DBG("Unable to find a pending command");
1724 else
1725 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001726}
1727
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001728static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001729{
1730 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001731 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001732 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001733 struct pending_cmd *cmd;
1734 u8 sec_level, auth_type;
1735 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001736 int err;
1737
1738 BT_DBG("");
1739
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001740 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001741 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1742 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001743
Szymon Janc4e51eae2011-02-25 19:05:48 +01001744 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001745 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001746 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1747 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001748
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001749 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001750
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001751 sec_level = BT_SECURITY_MEDIUM;
1752 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001753 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001754 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001755 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001756
Johan Hedbergba4e5642011-11-11 00:07:34 +02001757 if (cp->addr.type == MGMT_ADDR_BREDR)
1758 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001759 auth_type);
1760 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001761 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001762 auth_type);
1763
Johan Hedberg1425acb2011-11-11 00:07:35 +02001764 memset(&rp, 0, sizeof(rp));
1765 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1766 rp.addr.type = cp->addr.type;
1767
Ville Tervo30e76272011-02-22 16:10:53 -03001768 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001769 rp.status = -PTR_ERR(conn);
1770 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1771 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001772 goto unlock;
1773 }
1774
1775 if (conn->connect_cfm_cb) {
1776 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001777 rp.status = EBUSY;
1778 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1779 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001780 goto unlock;
1781 }
1782
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001783 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001784 if (!cmd) {
1785 err = -ENOMEM;
1786 hci_conn_put(conn);
1787 goto unlock;
1788 }
1789
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001790 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001791 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001792 conn->connect_cfm_cb = pairing_complete_cb;
1793
Johan Hedberge9a416b2011-02-19 12:05:56 -03001794 conn->security_cfm_cb = pairing_complete_cb;
1795 conn->disconn_cfm_cb = pairing_complete_cb;
1796 conn->io_capability = cp->io_cap;
1797 cmd->user_data = conn;
1798
1799 if (conn->state == BT_CONNECTED &&
1800 hci_conn_security(conn, sec_level, auth_type))
1801 pairing_complete(cmd, 0);
1802
1803 err = 0;
1804
1805unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001806 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001807 hci_dev_put(hdev);
1808
1809 return err;
1810}
1811
Johan Hedberg28424702012-02-02 04:02:29 +02001812static int cancel_pair_device(struct sock *sk, u16 index,
1813 unsigned char *data, u16 len)
1814{
1815 struct mgmt_addr_info *addr = (void *) data;
1816 struct hci_dev *hdev;
1817 struct pending_cmd *cmd;
1818 struct hci_conn *conn;
1819 int err;
1820
1821 BT_DBG("");
1822
1823 if (len != sizeof(*addr))
1824 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1825 MGMT_STATUS_INVALID_PARAMS);
1826
1827 hdev = hci_dev_get(index);
1828 if (!hdev)
1829 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1830 MGMT_STATUS_INVALID_PARAMS);
1831
1832 hci_dev_lock(hdev);
1833
1834 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1835 if (!cmd) {
1836 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1837 MGMT_STATUS_INVALID_PARAMS);
1838 goto unlock;
1839 }
1840
1841 conn = cmd->user_data;
1842
1843 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1844 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1845 MGMT_STATUS_INVALID_PARAMS);
1846 goto unlock;
1847 }
1848
1849 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1850
1851 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr,
1852 sizeof(*addr));
1853unlock:
1854 hci_dev_unlock(hdev);
1855 hci_dev_put(hdev);
1856
1857 return err;
1858}
1859
Brian Gix0df4c182011-11-16 13:53:13 -08001860static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001861 u8 type, u16 mgmt_op, u16 hci_op,
1862 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001863{
Johan Hedberga5c29682011-02-19 12:05:57 -03001864 struct pending_cmd *cmd;
1865 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001866 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001867 int err;
1868
Szymon Janc4e51eae2011-02-25 19:05:48 +01001869 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001870 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001871 return cmd_status(sk, index, mgmt_op,
1872 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001873
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001874 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001875
Johan Hedberga5c29682011-02-19 12:05:57 -03001876 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001877 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1878 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001879 }
1880
Johan Hedberg272d90d2012-02-09 15:26:12 +02001881 if (type == MGMT_ADDR_BREDR)
1882 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1883 else
Brian Gix47c15e22011-11-16 13:53:14 -08001884 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001885
Johan Hedberg272d90d2012-02-09 15:26:12 +02001886 if (!conn) {
1887 err = cmd_status(sk, index, mgmt_op,
1888 MGMT_STATUS_NOT_CONNECTED);
1889 goto done;
1890 }
1891
1892 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001893 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001894 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001895
Brian Gix5fe57d92011-12-21 16:12:13 -08001896 if (!err)
1897 err = cmd_status(sk, index, mgmt_op,
1898 MGMT_STATUS_SUCCESS);
1899 else
1900 err = cmd_status(sk, index, mgmt_op,
1901 MGMT_STATUS_FAILED);
1902
Brian Gix47c15e22011-11-16 13:53:14 -08001903 goto done;
1904 }
1905
Brian Gix0df4c182011-11-16 13:53:13 -08001906 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001907 if (!cmd) {
1908 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001909 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001910 }
1911
Brian Gix0df4c182011-11-16 13:53:13 -08001912 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001913 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1914 struct hci_cp_user_passkey_reply cp;
1915
1916 bacpy(&cp.bdaddr, bdaddr);
1917 cp.passkey = passkey;
1918 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1919 } else
1920 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1921
Johan Hedberga664b5b2011-02-19 12:06:02 -03001922 if (err < 0)
1923 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001924
Brian Gix0df4c182011-11-16 13:53:13 -08001925done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001926 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001927 hci_dev_put(hdev);
1928
1929 return err;
1930}
1931
Brian Gix0df4c182011-11-16 13:53:13 -08001932static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1933{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001934 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001935
1936 BT_DBG("");
1937
1938 if (len != sizeof(*cp))
1939 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1940 MGMT_STATUS_INVALID_PARAMS);
1941
Johan Hedberg272d90d2012-02-09 15:26:12 +02001942 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1943 MGMT_OP_USER_CONFIRM_REPLY,
1944 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001945}
1946
1947static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1948 u16 len)
1949{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001950 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001951
1952 BT_DBG("");
1953
1954 if (len != sizeof(*cp))
1955 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1956 MGMT_STATUS_INVALID_PARAMS);
1957
Johan Hedberg272d90d2012-02-09 15:26:12 +02001958 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1959 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1960 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001961}
1962
Brian Gix604086b2011-11-23 08:28:33 -08001963static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1964{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001965 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001966
1967 BT_DBG("");
1968
1969 if (len != sizeof(*cp))
1970 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1971 EINVAL);
1972
Johan Hedberg272d90d2012-02-09 15:26:12 +02001973 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1974 MGMT_OP_USER_PASSKEY_REPLY,
1975 HCI_OP_USER_PASSKEY_REPLY,
1976 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08001977}
1978
1979static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1980 u16 len)
1981{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001982 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001983
1984 BT_DBG("");
1985
1986 if (len != sizeof(*cp))
1987 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1988 EINVAL);
1989
Johan Hedberg272d90d2012-02-09 15:26:12 +02001990 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1991 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1992 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08001993}
1994
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001995static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02001996 u16 len)
1997{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001998 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001999 struct hci_cp_write_local_name hci_cp;
2000 struct hci_dev *hdev;
2001 struct pending_cmd *cmd;
2002 int err;
2003
2004 BT_DBG("");
2005
2006 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002007 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2008 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002009
2010 hdev = hci_dev_get(index);
2011 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002012 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2013 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002014
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002015 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002016
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002017 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2018 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002019 if (!cmd) {
2020 err = -ENOMEM;
2021 goto failed;
2022 }
2023
2024 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2025 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2026 &hci_cp);
2027 if (err < 0)
2028 mgmt_pending_remove(cmd);
2029
2030failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002031 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002032 hci_dev_put(hdev);
2033
2034 return err;
2035}
2036
Szymon Jancc35938b2011-03-22 13:12:21 +01002037static int read_local_oob_data(struct sock *sk, u16 index)
2038{
2039 struct hci_dev *hdev;
2040 struct pending_cmd *cmd;
2041 int err;
2042
2043 BT_DBG("hci%u", index);
2044
2045 hdev = hci_dev_get(index);
2046 if (!hdev)
2047 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002048 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002049
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002050 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002051
2052 if (!test_bit(HCI_UP, &hdev->flags)) {
2053 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002054 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002055 goto unlock;
2056 }
2057
2058 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2059 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002060 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002061 goto unlock;
2062 }
2063
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002064 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002065 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2066 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002067 goto unlock;
2068 }
2069
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002070 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002071 if (!cmd) {
2072 err = -ENOMEM;
2073 goto unlock;
2074 }
2075
2076 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2077 if (err < 0)
2078 mgmt_pending_remove(cmd);
2079
2080unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002081 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002082 hci_dev_put(hdev);
2083
2084 return err;
2085}
2086
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002087static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2088 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002089{
2090 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002091 struct mgmt_cp_add_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01002092 int err;
2093
2094 BT_DBG("hci%u ", index);
2095
2096 if (len != sizeof(*cp))
2097 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002098 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002099
2100 hdev = hci_dev_get(index);
2101 if (!hdev)
2102 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002103 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002104
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002105 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002106
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002107 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002108 cp->randomizer);
2109 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002110 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2111 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01002112 else
2113 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2114 0);
2115
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002116 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002117 hci_dev_put(hdev);
2118
2119 return err;
2120}
2121
2122static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002123 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002124{
2125 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002126 struct mgmt_cp_remove_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01002127 int err;
2128
2129 BT_DBG("hci%u ", index);
2130
2131 if (len != sizeof(*cp))
2132 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002133 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002134
2135 hdev = hci_dev_get(index);
2136 if (!hdev)
2137 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002138 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002139
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002140 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002141
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002142 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002143 if (err < 0)
2144 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002145 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002146 else
2147 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2148 NULL, 0);
2149
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002150 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002151 hci_dev_put(hdev);
2152
2153 return err;
2154}
2155
Johan Hedberg450dfda2011-11-12 11:58:22 +02002156static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002157 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002158{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002159 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002160 struct pending_cmd *cmd;
2161 struct hci_dev *hdev;
2162 int err;
2163
2164 BT_DBG("hci%u", index);
2165
Johan Hedberg450dfda2011-11-12 11:58:22 +02002166 if (len != sizeof(*cp))
2167 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2168 MGMT_STATUS_INVALID_PARAMS);
2169
Johan Hedberg14a53662011-04-27 10:29:56 -04002170 hdev = hci_dev_get(index);
2171 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002172 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2173 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002174
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002175 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002176
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002177 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002178 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2179 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002180 goto failed;
2181 }
2182
Johan Hedbergff9ef572012-01-04 14:23:45 +02002183 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2184 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2185 MGMT_STATUS_BUSY);
2186 goto failed;
2187 }
2188
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002189 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002190 if (!cmd) {
2191 err = -ENOMEM;
2192 goto failed;
2193 }
2194
Andre Guedes4aab14e2012-02-17 20:39:36 -03002195 hdev->discovery.type = cp->type;
2196
2197 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002198 case DISCOV_TYPE_BREDR:
2199 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes3fd24152012-02-03 17:48:01 -03002200 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002201 break;
2202
2203 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002204 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2205 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002206 break;
2207
2208 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002209 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002210 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002211
Johan Hedberg14a53662011-04-27 10:29:56 -04002212 if (err < 0)
2213 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002214 else
2215 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002216
2217failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002218 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002219 hci_dev_put(hdev);
2220
2221 return err;
2222}
2223
2224static int stop_discovery(struct sock *sk, u16 index)
2225{
2226 struct hci_dev *hdev;
2227 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002228 struct hci_cp_remote_name_req_cancel cp;
2229 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002230 int err;
2231
2232 BT_DBG("hci%u", index);
2233
2234 hdev = hci_dev_get(index);
2235 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002236 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2237 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002238
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002239 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002240
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002241 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002242 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2243 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002244 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002245 }
2246
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002247 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002248 if (!cmd) {
2249 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002250 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002251 }
2252
Andre Guedes343f9352012-02-17 20:39:37 -03002253 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002254 err = hci_cancel_inquiry(hdev);
2255 if (err < 0)
2256 mgmt_pending_remove(cmd);
2257 else
2258 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2259 goto unlock;
2260 }
2261
2262 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2263 if (!e) {
2264 mgmt_pending_remove(cmd);
2265 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2266 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2267 goto unlock;
2268 }
2269
2270 bacpy(&cp.bdaddr, &e->data.bdaddr);
2271 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2272 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002273 if (err < 0)
2274 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002275 else
2276 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002277
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002278unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002279 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002280 hci_dev_put(hdev);
2281
2282 return err;
2283}
2284
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002285static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002286{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002287 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002288 struct inquiry_entry *e;
2289 struct hci_dev *hdev;
2290 int err;
2291
2292 BT_DBG("hci%u", index);
2293
2294 if (len != sizeof(*cp))
2295 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2296 MGMT_STATUS_INVALID_PARAMS);
2297
2298 hdev = hci_dev_get(index);
2299 if (!hdev)
2300 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2301 MGMT_STATUS_INVALID_PARAMS);
2302
2303 hci_dev_lock(hdev);
2304
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002305 if (!hci_discovery_active(hdev)) {
2306 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2307 MGMT_STATUS_FAILED);
2308 goto failed;
2309 }
2310
Johan Hedberga198e7b2012-02-17 14:27:06 +02002311 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002312 if (!e) {
2313 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2314 MGMT_STATUS_INVALID_PARAMS);
2315 goto failed;
2316 }
2317
2318 if (cp->name_known) {
2319 e->name_state = NAME_KNOWN;
2320 list_del(&e->list);
2321 } else {
2322 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002323 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002324 }
2325
2326 err = 0;
2327
2328failed:
2329 hci_dev_unlock(hdev);
2330
2331 return err;
2332}
2333
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002334static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002335{
2336 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002337 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002338 int err;
2339
2340 BT_DBG("hci%u", index);
2341
Antti Julku7fbec222011-06-15 12:01:15 +03002342 if (len != sizeof(*cp))
2343 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002344 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002345
2346 hdev = hci_dev_get(index);
2347 if (!hdev)
2348 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002349 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002350
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002351 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002352
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002353 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002354 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002355 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2356 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002357 else
2358 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2359 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002360
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002361 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002362 hci_dev_put(hdev);
2363
2364 return err;
2365}
2366
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002367static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002368{
2369 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002370 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002371 int err;
2372
2373 BT_DBG("hci%u", index);
2374
Antti Julku7fbec222011-06-15 12:01:15 +03002375 if (len != sizeof(*cp))
2376 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002377 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002378
2379 hdev = hci_dev_get(index);
2380 if (!hdev)
2381 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002382 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002383
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002384 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002385
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002386 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002387
2388 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002389 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2390 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002391 else
2392 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2393 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002394
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002395 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002396 hci_dev_put(hdev);
2397
2398 return err;
2399}
2400
Antti Julkuf6422ec2011-06-22 13:11:56 +03002401static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002402 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002403{
2404 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002405 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002406 struct hci_cp_write_page_scan_activity acp;
2407 u8 type;
2408 int err;
2409
2410 BT_DBG("hci%u", index);
2411
2412 if (len != sizeof(*cp))
2413 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002414 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002415
2416 hdev = hci_dev_get(index);
2417 if (!hdev)
2418 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002419 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002420
2421 hci_dev_lock(hdev);
2422
Johan Hedbergf7c68692011-12-15 00:47:36 +02002423 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002424 type = PAGE_SCAN_TYPE_INTERLACED;
2425 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2426 } else {
2427 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2428 acp.interval = 0x0800; /* default 1.28 sec page scan */
2429 }
2430
2431 acp.window = 0x0012; /* default 11.25 msec page scan window */
2432
2433 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2434 sizeof(acp), &acp);
2435 if (err < 0) {
2436 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002437 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002438 goto done;
2439 }
2440
2441 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2442 if (err < 0) {
2443 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002444 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002445 goto done;
2446 }
2447
2448 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2449 NULL, 0);
2450done:
2451 hci_dev_unlock(hdev);
2452 hci_dev_put(hdev);
2453
2454 return err;
2455}
2456
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002457static int load_long_term_keys(struct sock *sk, u16 index,
2458 void *cp_data, u16 len)
2459{
2460 struct hci_dev *hdev;
2461 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2462 u16 key_count, expected_len;
2463 int i;
2464
2465 if (len < sizeof(*cp))
2466 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2467 EINVAL);
2468
2469 key_count = get_unaligned_le16(&cp->key_count);
2470
2471 expected_len = sizeof(*cp) + key_count *
2472 sizeof(struct mgmt_ltk_info);
2473 if (expected_len != len) {
2474 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2475 len, expected_len);
2476 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2477 EINVAL);
2478 }
2479
2480 hdev = hci_dev_get(index);
2481 if (!hdev)
2482 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2483 ENODEV);
2484
2485 BT_DBG("hci%u key_count %u", index, key_count);
2486
2487 hci_dev_lock(hdev);
2488
2489 hci_smp_ltks_clear(hdev);
2490
2491 for (i = 0; i < key_count; i++) {
2492 struct mgmt_ltk_info *key = &cp->keys[i];
2493 u8 type;
2494
2495 if (key->master)
2496 type = HCI_SMP_LTK;
2497 else
2498 type = HCI_SMP_LTK_SLAVE;
2499
2500 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2501 type, 0, key->authenticated, key->val,
2502 key->enc_size, key->ediv, key->rand);
2503 }
2504
2505 hci_dev_unlock(hdev);
2506 hci_dev_put(hdev);
2507
2508 return 0;
2509}
2510
Johan Hedberg03811012010-12-08 00:21:06 +02002511int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2512{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002513 void *buf;
2514 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002515 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002516 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002517 int err;
2518
2519 BT_DBG("got %zu bytes", msglen);
2520
2521 if (msglen < sizeof(*hdr))
2522 return -EINVAL;
2523
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002524 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002525 if (!buf)
2526 return -ENOMEM;
2527
2528 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2529 err = -EFAULT;
2530 goto done;
2531 }
2532
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002533 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002534 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002535 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002536 len = get_unaligned_le16(&hdr->len);
2537
2538 if (len != msglen - sizeof(*hdr)) {
2539 err = -EINVAL;
2540 goto done;
2541 }
2542
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002543 cp = buf + sizeof(*hdr);
2544
Johan Hedberg03811012010-12-08 00:21:06 +02002545 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002546 case MGMT_OP_READ_VERSION:
2547 err = read_version(sk);
2548 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002549 case MGMT_OP_READ_COMMANDS:
2550 err = read_commands(sk);
2551 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002552 case MGMT_OP_READ_INDEX_LIST:
2553 err = read_index_list(sk);
2554 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002555 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002556 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002557 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002558 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002559 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002560 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002561 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002562 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002563 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002564 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002565 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002566 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002567 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002568 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002569 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002570 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002571 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002572 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002573 case MGMT_OP_SET_LINK_SECURITY:
2574 err = set_link_security(sk, index, cp, len);
2575 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002576 case MGMT_OP_SET_SSP:
2577 err = set_ssp(sk, index, cp, len);
2578 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002579 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002580 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002581 break;
2582 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002583 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002584 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002585 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002586 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002587 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002588 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002589 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002590 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002591 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002592 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002593 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002594 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002595 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002596 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002597 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002598 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002599 break;
2600 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002601 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002602 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002603 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002604 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002605 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002606 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002607 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002608 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002609 case MGMT_OP_CANCEL_PAIR_DEVICE:
2610 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2611 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002612 case MGMT_OP_UNPAIR_DEVICE:
2613 err = unpair_device(sk, index, cp, len);
2614 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002615 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002616 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002617 break;
2618 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002619 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002620 break;
Brian Gix604086b2011-11-23 08:28:33 -08002621 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002622 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002623 break;
2624 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002625 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002626 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002627 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002628 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002629 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002630 case MGMT_OP_READ_LOCAL_OOB_DATA:
2631 err = read_local_oob_data(sk, index);
2632 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002633 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002634 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002635 break;
2636 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002637 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002638 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002639 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002640 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002641 break;
2642 case MGMT_OP_STOP_DISCOVERY:
2643 err = stop_discovery(sk, index);
2644 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002645 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002646 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002647 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002648 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002649 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002650 break;
2651 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002652 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002653 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002654 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2655 err = load_long_term_keys(sk, index, cp, len);
2656 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002657 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002658 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002659 err = cmd_status(sk, index, opcode,
2660 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002661 break;
2662 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002663
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002664 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002665 goto done;
2666
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002667 err = msglen;
2668
2669done:
2670 kfree(buf);
2671 return err;
2672}
2673
Johan Hedbergb24752f2011-11-03 14:40:33 +02002674static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2675{
2676 u8 *status = data;
2677
2678 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2679 mgmt_pending_remove(cmd);
2680}
2681
Johan Hedberg744cf192011-11-08 20:40:14 +02002682int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002683{
Johan Hedberg744cf192011-11-08 20:40:14 +02002684 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002685}
2686
Johan Hedberg744cf192011-11-08 20:40:14 +02002687int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002688{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002689 u8 status = ENODEV;
2690
Johan Hedberg744cf192011-11-08 20:40:14 +02002691 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002692
Johan Hedberg744cf192011-11-08 20:40:14 +02002693 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002694}
2695
2696struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002697 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002698 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002699};
2700
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002701static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002702{
Johan Hedberg03811012010-12-08 00:21:06 +02002703 struct cmd_lookup *match = data;
2704
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002705 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002706
2707 list_del(&cmd->list);
2708
2709 if (match->sk == NULL) {
2710 match->sk = cmd->sk;
2711 sock_hold(match->sk);
2712 }
2713
2714 mgmt_pending_free(cmd);
2715}
2716
Johan Hedberg744cf192011-11-08 20:40:14 +02002717int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002718{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002719 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002720 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002721 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002722
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002723 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002724
Johan Hedbergb24752f2011-11-03 14:40:33 +02002725 if (!powered) {
2726 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002727 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002728 }
2729
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002730 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002731
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002732 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002733 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002734
2735 if (match.sk)
2736 sock_put(match.sk);
2737
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002738 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002739}
2740
Johan Hedberg744cf192011-11-08 20:40:14 +02002741int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002742{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002743 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002744 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002745 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002746
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002747 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002748
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002749 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002750
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002751 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002752 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002753 if (match.sk)
2754 sock_put(match.sk);
2755
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002756 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002757}
2758
Johan Hedberg744cf192011-11-08 20:40:14 +02002759int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002760{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002761 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002762 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002763 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002764
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002765 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2766 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002767
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002768 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002769
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002770 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002771
2772 if (match.sk)
2773 sock_put(match.sk);
2774
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002775 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002776}
2777
Johan Hedberg744cf192011-11-08 20:40:14 +02002778int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002779{
Johan Hedbergca69b792011-11-11 18:10:00 +02002780 u8 mgmt_err = mgmt_status(status);
2781
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002782 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002783 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002784 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002785
2786 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002787 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002788 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002789
2790 return 0;
2791}
2792
Johan Hedberg744cf192011-11-08 20:40:14 +02002793int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2794 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002795{
Johan Hedberg86742e12011-11-07 23:13:38 +02002796 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002797
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002798 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002799
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002800 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002801 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2802 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002803 ev.key.type = key->type;
2804 memcpy(ev.key.val, key->val, 16);
2805 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002806
Johan Hedberg744cf192011-11-08 20:40:14 +02002807 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002808}
Johan Hedbergf7520542011-01-20 12:34:39 +02002809
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002810int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2811{
2812 struct mgmt_ev_new_long_term_key ev;
2813
2814 memset(&ev, 0, sizeof(ev));
2815
2816 ev.store_hint = persistent;
2817 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2818 ev.key.addr.type = key->bdaddr_type;
2819 ev.key.authenticated = key->authenticated;
2820 ev.key.enc_size = key->enc_size;
2821 ev.key.ediv = key->ediv;
2822
2823 if (key->type == HCI_SMP_LTK)
2824 ev.key.master = 1;
2825
2826 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2827 memcpy(ev.key.val, key->val, sizeof(key->val));
2828
2829 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2830 &ev, sizeof(ev), NULL);
2831}
2832
Johan Hedbergafc747a2012-01-15 18:11:07 +02002833int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002834 u8 addr_type, u8 *name, u8 name_len,
2835 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002836{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002837 char buf[512];
2838 struct mgmt_ev_device_connected *ev = (void *) buf;
2839 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002840
Johan Hedbergb644ba32012-01-17 21:48:47 +02002841 bacpy(&ev->addr.bdaddr, bdaddr);
2842 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002843
Johan Hedbergb644ba32012-01-17 21:48:47 +02002844 if (name_len > 0)
2845 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2846 name, name_len);
2847
2848 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2849 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2850 EIR_CLASS_OF_DEV, dev_class, 3);
2851
2852 put_unaligned_le16(eir_len, &ev->eir_len);
2853
2854 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2855 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002856}
2857
Johan Hedberg8962ee72011-01-20 12:40:27 +02002858static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2859{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002860 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002861 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002862 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002863
Johan Hedberg88c3df12012-02-09 14:27:38 +02002864 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2865 rp.addr.type = cp->addr.type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002866 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002867
Szymon Janc4e51eae2011-02-25 19:05:48 +01002868 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002869
2870 *sk = cmd->sk;
2871 sock_hold(*sk);
2872
Johan Hedberga664b5b2011-02-19 12:06:02 -03002873 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002874}
2875
Johan Hedberg124f6e32012-02-09 13:50:12 +02002876static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002877{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002878 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002879 struct mgmt_cp_unpair_device *cp = cmd->param;
2880 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002881
2882 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002883 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2884 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002885
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002886 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2887
2888 cmd_complete(cmd->sk, cmd->index, cmd->opcode, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002889
2890 mgmt_pending_remove(cmd);
2891}
2892
Johan Hedbergafc747a2012-01-15 18:11:07 +02002893int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2894 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002895{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002896 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002897 struct sock *sk = NULL;
2898 int err;
2899
Johan Hedberg744cf192011-11-08 20:40:14 +02002900 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002901
Johan Hedbergf7520542011-01-20 12:34:39 +02002902 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002903 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002904
Johan Hedbergafc747a2012-01-15 18:11:07 +02002905 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2906 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002907
2908 if (sk)
2909 sock_put(sk);
2910
Johan Hedberg124f6e32012-02-09 13:50:12 +02002911 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002912 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002913
Johan Hedberg8962ee72011-01-20 12:40:27 +02002914 return err;
2915}
2916
Johan Hedberg88c3df12012-02-09 14:27:38 +02002917int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
2918 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002919{
Johan Hedberg88c3df12012-02-09 14:27:38 +02002920 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002921 struct pending_cmd *cmd;
2922 int err;
2923
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002924 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002925 if (!cmd)
2926 return -ENOENT;
2927
Johan Hedberg88c3df12012-02-09 14:27:38 +02002928 bacpy(&rp.addr.bdaddr, bdaddr);
2929 rp.addr.type = link_to_mgmt(link_type, addr_type);
2930 rp.status = mgmt_status(status);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002931
Johan Hedberg88c3df12012-02-09 14:27:38 +02002932 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002933 &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002934
Johan Hedberga664b5b2011-02-19 12:06:02 -03002935 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002936
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002937 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
2938 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002939 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002940}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002941
Johan Hedberg48264f02011-11-09 13:58:58 +02002942int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2943 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002944{
2945 struct mgmt_ev_connect_failed ev;
2946
Johan Hedberg4c659c32011-11-07 23:13:39 +02002947 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002948 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002949 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002950
Johan Hedberg744cf192011-11-08 20:40:14 +02002951 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002952}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002953
Johan Hedberg744cf192011-11-08 20:40:14 +02002954int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002955{
2956 struct mgmt_ev_pin_code_request ev;
2957
Johan Hedbergd8457692012-02-17 14:24:57 +02002958 bacpy(&ev.addr.bdaddr, bdaddr);
2959 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002960 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002961
Johan Hedberg744cf192011-11-08 20:40:14 +02002962 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002963 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002964}
2965
Johan Hedberg744cf192011-11-08 20:40:14 +02002966int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2967 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002968{
2969 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002970 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002971 int err;
2972
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002973 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002974 if (!cmd)
2975 return -ENOENT;
2976
Johan Hedbergd8457692012-02-17 14:24:57 +02002977 bacpy(&rp.addr.bdaddr, bdaddr);
2978 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergca69b792011-11-11 18:10:00 +02002979 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002980
Johan Hedberg744cf192011-11-08 20:40:14 +02002981 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002982 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002983
Johan Hedberga664b5b2011-02-19 12:06:02 -03002984 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002985
2986 return err;
2987}
2988
Johan Hedberg744cf192011-11-08 20:40:14 +02002989int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2990 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002991{
2992 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002993 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002994 int err;
2995
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002996 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002997 if (!cmd)
2998 return -ENOENT;
2999
Johan Hedbergd8457692012-02-17 14:24:57 +02003000 bacpy(&rp.addr.bdaddr, bdaddr);
3001 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergca69b792011-11-11 18:10:00 +02003002 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03003003
Johan Hedberg744cf192011-11-08 20:40:14 +02003004 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01003005 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003006
Johan Hedberga664b5b2011-02-19 12:06:02 -03003007 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003008
3009 return err;
3010}
Johan Hedberga5c29682011-02-19 12:05:57 -03003011
Johan Hedberg744cf192011-11-08 20:40:14 +02003012int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003013 u8 link_type, u8 addr_type, __le32 value,
3014 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003015{
3016 struct mgmt_ev_user_confirm_request ev;
3017
Johan Hedberg744cf192011-11-08 20:40:14 +02003018 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003019
Johan Hedberg272d90d2012-02-09 15:26:12 +02003020 bacpy(&ev.addr.bdaddr, bdaddr);
3021 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003022 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003023 put_unaligned_le32(value, &ev.value);
3024
Johan Hedberg744cf192011-11-08 20:40:14 +02003025 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003026 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003027}
3028
Johan Hedberg272d90d2012-02-09 15:26:12 +02003029int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3030 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003031{
3032 struct mgmt_ev_user_passkey_request ev;
3033
3034 BT_DBG("%s", hdev->name);
3035
Johan Hedberg272d90d2012-02-09 15:26:12 +02003036 bacpy(&ev.addr.bdaddr, bdaddr);
3037 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003038
3039 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3040 NULL);
3041}
3042
Brian Gix0df4c182011-11-16 13:53:13 -08003043static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003044 u8 link_type, u8 addr_type, u8 status,
3045 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003046{
3047 struct pending_cmd *cmd;
3048 struct mgmt_rp_user_confirm_reply rp;
3049 int err;
3050
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003051 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003052 if (!cmd)
3053 return -ENOENT;
3054
Johan Hedberg272d90d2012-02-09 15:26:12 +02003055 bacpy(&rp.addr.bdaddr, bdaddr);
3056 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003057 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02003058 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003059
Johan Hedberga664b5b2011-02-19 12:06:02 -03003060 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003061
3062 return err;
3063}
3064
Johan Hedberg744cf192011-11-08 20:40:14 +02003065int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003066 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003067{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003068 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3069 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003070}
3071
Johan Hedberg272d90d2012-02-09 15:26:12 +02003072int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3073 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003074{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003075 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3076 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003077}
Johan Hedberg2a611692011-02-19 12:06:00 -03003078
Brian Gix604086b2011-11-23 08:28:33 -08003079int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003080 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003081{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003082 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3083 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003084}
3085
Johan Hedberg272d90d2012-02-09 15:26:12 +02003086int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3087 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003088{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003089 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3090 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003091}
3092
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003093int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3094 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003095{
3096 struct mgmt_ev_auth_failed ev;
3097
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003098 bacpy(&ev.addr.bdaddr, bdaddr);
3099 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003100 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003101
Johan Hedberg744cf192011-11-08 20:40:14 +02003102 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003103}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003104
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003105int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3106{
3107 struct cmd_lookup match = { NULL, hdev };
3108 __le32 ev;
3109 int err;
3110
3111 if (status) {
3112 u8 mgmt_err = mgmt_status(status);
3113 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3114 cmd_status_rsp, &mgmt_err);
3115 return 0;
3116 }
3117
3118 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3119 &match);
3120
3121 ev = cpu_to_le32(get_current_settings(hdev));
3122 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3123
3124 if (match.sk)
3125 sock_put(match.sk);
3126
3127 return err;
3128}
3129
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003130int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3131{
3132 struct cmd_lookup match = { NULL, hdev };
3133 __le32 ev;
3134 int err;
3135
3136 if (status) {
3137 u8 mgmt_err = mgmt_status(status);
3138 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3139 cmd_status_rsp, &mgmt_err);
3140 return 0;
3141 }
3142
3143 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3144
3145 ev = cpu_to_le32(get_current_settings(hdev));
3146 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3147
3148 if (match.sk)
3149 sock_put(match.sk);
3150
3151 return err;
3152}
3153
Johan Hedberg744cf192011-11-08 20:40:14 +02003154int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003155{
3156 struct pending_cmd *cmd;
3157 struct mgmt_cp_set_local_name ev;
3158 int err;
3159
3160 memset(&ev, 0, sizeof(ev));
3161 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3162
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003163 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003164 if (!cmd)
3165 goto send_event;
3166
3167 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003168 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003169 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003170 goto failed;
3171 }
3172
Johan Hedberg744cf192011-11-08 20:40:14 +02003173 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003174
Johan Hedberg744cf192011-11-08 20:40:14 +02003175 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003176 sizeof(ev));
3177 if (err < 0)
3178 goto failed;
3179
3180send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003181 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003182 cmd ? cmd->sk : NULL);
3183
3184failed:
3185 if (cmd)
3186 mgmt_pending_remove(cmd);
3187 return err;
3188}
Szymon Jancc35938b2011-03-22 13:12:21 +01003189
Johan Hedberg744cf192011-11-08 20:40:14 +02003190int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3191 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003192{
3193 struct pending_cmd *cmd;
3194 int err;
3195
Johan Hedberg744cf192011-11-08 20:40:14 +02003196 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003197
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003198 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003199 if (!cmd)
3200 return -ENOENT;
3201
3202 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003203 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003204 MGMT_OP_READ_LOCAL_OOB_DATA,
3205 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003206 } else {
3207 struct mgmt_rp_read_local_oob_data rp;
3208
3209 memcpy(rp.hash, hash, sizeof(rp.hash));
3210 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3211
Johan Hedberg744cf192011-11-08 20:40:14 +02003212 err = cmd_complete(cmd->sk, hdev->id,
3213 MGMT_OP_READ_LOCAL_OOB_DATA,
3214 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003215 }
3216
3217 mgmt_pending_remove(cmd);
3218
3219 return err;
3220}
Johan Hedberge17acd42011-03-30 23:57:16 +03003221
Johan Hedberg48264f02011-11-09 13:58:58 +02003222int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003223 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003224 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003225{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003226 char buf[512];
3227 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003228 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003229
Johan Hedberg1dc06092012-01-15 21:01:23 +02003230 /* Leave 5 bytes for a potential CoD field */
3231 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003232 return -EINVAL;
3233
Johan Hedberg1dc06092012-01-15 21:01:23 +02003234 memset(buf, 0, sizeof(buf));
3235
Johan Hedberge319d2e2012-01-15 19:51:59 +02003236 bacpy(&ev->addr.bdaddr, bdaddr);
3237 ev->addr.type = link_to_mgmt(link_type, addr_type);
3238 ev->rssi = rssi;
3239 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003240
Johan Hedberg1dc06092012-01-15 21:01:23 +02003241 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003242 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003243
Johan Hedberg1dc06092012-01-15 21:01:23 +02003244 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3245 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3246 dev_class, 3);
3247
3248 put_unaligned_le16(eir_len, &ev->eir_len);
3249
3250 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003251
Johan Hedberge319d2e2012-01-15 19:51:59 +02003252 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003253}
Johan Hedberga88a9652011-03-30 13:18:12 +03003254
Johan Hedbergb644ba32012-01-17 21:48:47 +02003255int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3256 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003257{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003258 struct mgmt_ev_device_found *ev;
3259 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3260 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003261
Johan Hedbergb644ba32012-01-17 21:48:47 +02003262 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003263
Johan Hedbergb644ba32012-01-17 21:48:47 +02003264 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003265
Johan Hedbergb644ba32012-01-17 21:48:47 +02003266 bacpy(&ev->addr.bdaddr, bdaddr);
3267 ev->addr.type = link_to_mgmt(link_type, addr_type);
3268 ev->rssi = rssi;
3269
3270 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3271 name_len);
3272
3273 put_unaligned_le16(eir_len, &ev->eir_len);
3274
Johan Hedberg053c7e02012-02-04 00:06:00 +02003275 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3276 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003277}
Johan Hedberg314b2382011-04-27 10:29:57 -04003278
Andre Guedes7a135102011-11-09 17:14:25 -03003279int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003280{
3281 struct pending_cmd *cmd;
3282 int err;
3283
Andre Guedes203159d2012-02-13 15:41:01 -03003284 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3285
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003286 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003287 if (!cmd)
3288 return -ENOENT;
3289
Johan Hedbergca69b792011-11-11 18:10:00 +02003290 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003291 mgmt_pending_remove(cmd);
3292
3293 return err;
3294}
3295
Andre Guedese6d465c2011-11-09 17:14:26 -03003296int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3297{
3298 struct pending_cmd *cmd;
3299 int err;
3300
3301 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3302 if (!cmd)
3303 return -ENOENT;
3304
Andre Guedese75a8b0c2012-01-02 16:50:53 -03003305 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02003306 mgmt_pending_remove(cmd);
3307
3308 return err;
3309}
Johan Hedberg314b2382011-04-27 10:29:57 -04003310
Johan Hedberg744cf192011-11-08 20:40:14 +02003311int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003312{
Johan Hedberg164a6e72011-11-01 17:06:44 +02003313 struct pending_cmd *cmd;
3314
Andre Guedes343fb142011-11-22 17:14:19 -03003315 BT_DBG("%s discovering %u", hdev->name, discovering);
3316
Johan Hedberg164a6e72011-11-01 17:06:44 +02003317 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003318 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003319 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003320 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003321
3322 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003323 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003324 mgmt_pending_remove(cmd);
3325 }
3326
Johan Hedberg744cf192011-11-08 20:40:14 +02003327 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04003328 sizeof(discovering), NULL);
3329}
Antti Julku5e762442011-08-25 16:48:02 +03003330
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003331int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003332{
3333 struct pending_cmd *cmd;
3334 struct mgmt_ev_device_blocked ev;
3335
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003336 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003337
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003338 bacpy(&ev.addr.bdaddr, bdaddr);
3339 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003340
Johan Hedberg744cf192011-11-08 20:40:14 +02003341 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3342 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003343}
3344
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003345int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003346{
3347 struct pending_cmd *cmd;
3348 struct mgmt_ev_device_unblocked ev;
3349
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003350 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003351
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003352 bacpy(&ev.addr.bdaddr, bdaddr);
3353 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003354
Johan Hedberg744cf192011-11-08 20:40:14 +02003355 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3356 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003357}