blob: 196215c9d42494b6d2836d27bf939a450c6c6666 [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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200223 kfree_skb(skb);
224
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300225 return err;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200790
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300791 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Guedesf39799f2012-02-17 20:39:35 -03002195 switch (cp->type) {
2196 case DISCOV_TYPE_BREDR:
2197 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes3fd24152012-02-03 17:48:01 -03002198 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002199 break;
2200
2201 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002202 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2203 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002204 break;
2205
2206 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002207 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002208 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002209
Johan Hedberg14a53662011-04-27 10:29:56 -04002210 if (err < 0)
2211 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002212 else
2213 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002214
2215failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002216 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002217 hci_dev_put(hdev);
2218
2219 return err;
2220}
2221
2222static int stop_discovery(struct sock *sk, u16 index)
2223{
2224 struct hci_dev *hdev;
2225 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002226 struct hci_cp_remote_name_req_cancel cp;
2227 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002228 int err;
2229
2230 BT_DBG("hci%u", index);
2231
2232 hdev = hci_dev_get(index);
2233 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002234 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2235 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002236
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002237 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002238
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002239 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002240 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2241 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002242 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002243 }
2244
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002245 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002246 if (!cmd) {
2247 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002248 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002249 }
2250
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002251 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
2252 err = hci_cancel_inquiry(hdev);
2253 if (err < 0)
2254 mgmt_pending_remove(cmd);
2255 else
2256 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2257 goto unlock;
2258 }
2259
2260 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2261 if (!e) {
2262 mgmt_pending_remove(cmd);
2263 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2264 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2265 goto unlock;
2266 }
2267
2268 bacpy(&cp.bdaddr, &e->data.bdaddr);
2269 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2270 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002271 if (err < 0)
2272 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002273 else
2274 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002275
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002276unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002277 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002278 hci_dev_put(hdev);
2279
2280 return err;
2281}
2282
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002283static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002284{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002285 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002286 struct inquiry_entry *e;
2287 struct hci_dev *hdev;
2288 int err;
2289
2290 BT_DBG("hci%u", index);
2291
2292 if (len != sizeof(*cp))
2293 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2294 MGMT_STATUS_INVALID_PARAMS);
2295
2296 hdev = hci_dev_get(index);
2297 if (!hdev)
2298 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2299 MGMT_STATUS_INVALID_PARAMS);
2300
2301 hci_dev_lock(hdev);
2302
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002303 if (!hci_discovery_active(hdev)) {
2304 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2305 MGMT_STATUS_FAILED);
2306 goto failed;
2307 }
2308
Johan Hedberga198e7b2012-02-17 14:27:06 +02002309 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002310 if (!e) {
2311 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2312 MGMT_STATUS_INVALID_PARAMS);
2313 goto failed;
2314 }
2315
2316 if (cp->name_known) {
2317 e->name_state = NAME_KNOWN;
2318 list_del(&e->list);
2319 } else {
2320 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002321 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002322 }
2323
2324 err = 0;
2325
2326failed:
2327 hci_dev_unlock(hdev);
2328
2329 return err;
2330}
2331
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002332static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002333{
2334 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002335 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002336 int err;
2337
2338 BT_DBG("hci%u", index);
2339
Antti Julku7fbec222011-06-15 12:01:15 +03002340 if (len != sizeof(*cp))
2341 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002342 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002343
2344 hdev = hci_dev_get(index);
2345 if (!hdev)
2346 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002347 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002348
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002349 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002350
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002351 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002352 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002353 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2354 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002355 else
2356 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2357 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002358
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002359 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002360 hci_dev_put(hdev);
2361
2362 return err;
2363}
2364
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002365static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002366{
2367 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002368 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002369 int err;
2370
2371 BT_DBG("hci%u", index);
2372
Antti Julku7fbec222011-06-15 12:01:15 +03002373 if (len != sizeof(*cp))
2374 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002375 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002376
2377 hdev = hci_dev_get(index);
2378 if (!hdev)
2379 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002380 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002381
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002382 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002383
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002384 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002385
2386 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002387 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2388 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002389 else
2390 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2391 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002392
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002393 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002394 hci_dev_put(hdev);
2395
2396 return err;
2397}
2398
Antti Julkuf6422ec2011-06-22 13:11:56 +03002399static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002400 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002401{
2402 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002403 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002404 struct hci_cp_write_page_scan_activity acp;
2405 u8 type;
2406 int err;
2407
2408 BT_DBG("hci%u", index);
2409
2410 if (len != sizeof(*cp))
2411 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002412 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002413
2414 hdev = hci_dev_get(index);
2415 if (!hdev)
2416 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002417 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002418
2419 hci_dev_lock(hdev);
2420
Johan Hedbergf7c6869c2011-12-15 00:47:36 +02002421 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002422 type = PAGE_SCAN_TYPE_INTERLACED;
2423 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2424 } else {
2425 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2426 acp.interval = 0x0800; /* default 1.28 sec page scan */
2427 }
2428
2429 acp.window = 0x0012; /* default 11.25 msec page scan window */
2430
2431 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2432 sizeof(acp), &acp);
2433 if (err < 0) {
2434 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002435 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002436 goto done;
2437 }
2438
2439 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2440 if (err < 0) {
2441 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002442 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002443 goto done;
2444 }
2445
2446 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2447 NULL, 0);
2448done:
2449 hci_dev_unlock(hdev);
2450 hci_dev_put(hdev);
2451
2452 return err;
2453}
2454
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002455static int load_long_term_keys(struct sock *sk, u16 index,
2456 void *cp_data, u16 len)
2457{
2458 struct hci_dev *hdev;
2459 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2460 u16 key_count, expected_len;
2461 int i;
2462
2463 if (len < sizeof(*cp))
2464 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2465 EINVAL);
2466
2467 key_count = get_unaligned_le16(&cp->key_count);
2468
2469 expected_len = sizeof(*cp) + key_count *
2470 sizeof(struct mgmt_ltk_info);
2471 if (expected_len != len) {
2472 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2473 len, expected_len);
2474 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2475 EINVAL);
2476 }
2477
2478 hdev = hci_dev_get(index);
2479 if (!hdev)
2480 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2481 ENODEV);
2482
2483 BT_DBG("hci%u key_count %u", index, key_count);
2484
2485 hci_dev_lock(hdev);
2486
2487 hci_smp_ltks_clear(hdev);
2488
2489 for (i = 0; i < key_count; i++) {
2490 struct mgmt_ltk_info *key = &cp->keys[i];
2491 u8 type;
2492
2493 if (key->master)
2494 type = HCI_SMP_LTK;
2495 else
2496 type = HCI_SMP_LTK_SLAVE;
2497
2498 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2499 type, 0, key->authenticated, key->val,
2500 key->enc_size, key->ediv, key->rand);
2501 }
2502
2503 hci_dev_unlock(hdev);
2504 hci_dev_put(hdev);
2505
2506 return 0;
2507}
2508
Johan Hedberg03811012010-12-08 00:21:06 +02002509int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2510{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002511 void *buf;
2512 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002513 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002514 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002515 int err;
2516
2517 BT_DBG("got %zu bytes", msglen);
2518
2519 if (msglen < sizeof(*hdr))
2520 return -EINVAL;
2521
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002522 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002523 if (!buf)
2524 return -ENOMEM;
2525
2526 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2527 err = -EFAULT;
2528 goto done;
2529 }
2530
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002531 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002532 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002533 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002534 len = get_unaligned_le16(&hdr->len);
2535
2536 if (len != msglen - sizeof(*hdr)) {
2537 err = -EINVAL;
2538 goto done;
2539 }
2540
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002541 cp = buf + sizeof(*hdr);
2542
Johan Hedberg03811012010-12-08 00:21:06 +02002543 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002544 case MGMT_OP_READ_VERSION:
2545 err = read_version(sk);
2546 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002547 case MGMT_OP_READ_COMMANDS:
2548 err = read_commands(sk);
2549 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002550 case MGMT_OP_READ_INDEX_LIST:
2551 err = read_index_list(sk);
2552 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002553 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002554 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002555 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002556 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002557 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002558 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002559 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002560 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002561 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002562 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002563 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002564 break;
Johan Hedbergf7c6869c2011-12-15 00:47:36 +02002565 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002566 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869c2011-12-15 00:47:36 +02002567 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002568 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002569 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002570 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002571 case MGMT_OP_SET_LINK_SECURITY:
2572 err = set_link_security(sk, index, cp, len);
2573 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002574 case MGMT_OP_SET_SSP:
2575 err = set_ssp(sk, index, cp, len);
2576 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002577 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002578 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002579 break;
2580 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002581 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002582 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002583 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002584 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002585 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002586 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002587 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002588 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002589 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002590 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002591 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002592 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002593 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002594 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002595 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002596 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002597 break;
2598 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002599 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002600 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002601 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002602 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002603 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002604 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002605 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002606 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002607 case MGMT_OP_CANCEL_PAIR_DEVICE:
2608 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2609 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002610 case MGMT_OP_UNPAIR_DEVICE:
2611 err = unpair_device(sk, index, cp, len);
2612 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002613 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002614 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002615 break;
2616 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002617 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002618 break;
Brian Gix604086b2011-11-23 08:28:33 -08002619 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002620 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002621 break;
2622 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002623 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002624 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002625 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002626 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002627 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002628 case MGMT_OP_READ_LOCAL_OOB_DATA:
2629 err = read_local_oob_data(sk, index);
2630 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002631 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002632 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002633 break;
2634 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002635 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002636 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002637 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002638 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002639 break;
2640 case MGMT_OP_STOP_DISCOVERY:
2641 err = stop_discovery(sk, index);
2642 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002643 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002644 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002645 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002646 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002647 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002648 break;
2649 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002650 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002651 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002652 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2653 err = load_long_term_keys(sk, index, cp, len);
2654 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002655 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002656 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002657 err = cmd_status(sk, index, opcode,
2658 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002659 break;
2660 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002661
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002662 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002663 goto done;
2664
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002665 err = msglen;
2666
2667done:
2668 kfree(buf);
2669 return err;
2670}
2671
Johan Hedbergb24752f2011-11-03 14:40:33 +02002672static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2673{
2674 u8 *status = data;
2675
2676 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2677 mgmt_pending_remove(cmd);
2678}
2679
Johan Hedberg744cf192011-11-08 20:40:14 +02002680int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002681{
Johan Hedberg744cf192011-11-08 20:40:14 +02002682 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002683}
2684
Johan Hedberg744cf192011-11-08 20:40:14 +02002685int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002686{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002687 u8 status = ENODEV;
2688
Johan Hedberg744cf192011-11-08 20:40:14 +02002689 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002690
Johan Hedberg744cf192011-11-08 20:40:14 +02002691 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002692}
2693
2694struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002695 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002696 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002697};
2698
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002699static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002700{
Johan Hedberg03811012010-12-08 00:21:06 +02002701 struct cmd_lookup *match = data;
2702
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002703 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002704
2705 list_del(&cmd->list);
2706
2707 if (match->sk == NULL) {
2708 match->sk = cmd->sk;
2709 sock_hold(match->sk);
2710 }
2711
2712 mgmt_pending_free(cmd);
2713}
2714
Johan Hedberg744cf192011-11-08 20:40:14 +02002715int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002716{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002717 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002718 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002719 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002720
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002721 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002722
Johan Hedbergb24752f2011-11-03 14:40:33 +02002723 if (!powered) {
2724 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002725 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002726 }
2727
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002728 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002729
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002730 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002731 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002732
2733 if (match.sk)
2734 sock_put(match.sk);
2735
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002736 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002737}
2738
Johan Hedberg744cf192011-11-08 20:40:14 +02002739int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002740{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002741 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002742 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002743 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002744
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002745 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002746
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002747 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002748
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002749 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002750 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002751 if (match.sk)
2752 sock_put(match.sk);
2753
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002754 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002755}
2756
Johan Hedberg744cf192011-11-08 20:40:14 +02002757int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002758{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002759 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002760 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002761 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002762
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002763 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2764 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002765
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002766 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002767
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002768 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002769
2770 if (match.sk)
2771 sock_put(match.sk);
2772
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002773 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002774}
2775
Johan Hedberg744cf192011-11-08 20:40:14 +02002776int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002777{
Johan Hedbergca69b792011-11-11 18:10:00 +02002778 u8 mgmt_err = mgmt_status(status);
2779
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002780 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002781 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002782 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002783
2784 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002785 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002786 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002787
2788 return 0;
2789}
2790
Johan Hedberg744cf192011-11-08 20:40:14 +02002791int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2792 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002793{
Johan Hedberg86742e12011-11-07 23:13:38 +02002794 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002795
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002796 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002797
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002798 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002799 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2800 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002801 ev.key.type = key->type;
2802 memcpy(ev.key.val, key->val, 16);
2803 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002804
Johan Hedberg744cf192011-11-08 20:40:14 +02002805 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002806}
Johan Hedbergf7520542011-01-20 12:34:39 +02002807
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002808int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2809{
2810 struct mgmt_ev_new_long_term_key ev;
2811
2812 memset(&ev, 0, sizeof(ev));
2813
2814 ev.store_hint = persistent;
2815 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2816 ev.key.addr.type = key->bdaddr_type;
2817 ev.key.authenticated = key->authenticated;
2818 ev.key.enc_size = key->enc_size;
2819 ev.key.ediv = key->ediv;
2820
2821 if (key->type == HCI_SMP_LTK)
2822 ev.key.master = 1;
2823
2824 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2825 memcpy(ev.key.val, key->val, sizeof(key->val));
2826
2827 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2828 &ev, sizeof(ev), NULL);
2829}
2830
Johan Hedbergafc747a2012-01-15 18:11:07 +02002831int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002832 u8 addr_type, u8 *name, u8 name_len,
2833 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002834{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002835 char buf[512];
2836 struct mgmt_ev_device_connected *ev = (void *) buf;
2837 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002838
Johan Hedbergb644ba32012-01-17 21:48:47 +02002839 bacpy(&ev->addr.bdaddr, bdaddr);
2840 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002841
Johan Hedbergb644ba32012-01-17 21:48:47 +02002842 if (name_len > 0)
2843 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2844 name, name_len);
2845
2846 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2847 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2848 EIR_CLASS_OF_DEV, dev_class, 3);
2849
2850 put_unaligned_le16(eir_len, &ev->eir_len);
2851
2852 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2853 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002854}
2855
Johan Hedberg8962ee72011-01-20 12:40:27 +02002856static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2857{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002858 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002859 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002860 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002861
Johan Hedberg88c3df12012-02-09 14:27:38 +02002862 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2863 rp.addr.type = cp->addr.type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002864 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002865
Szymon Janc4e51eae2011-02-25 19:05:48 +01002866 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002867
2868 *sk = cmd->sk;
2869 sock_hold(*sk);
2870
Johan Hedberga664b5b2011-02-19 12:06:02 -03002871 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002872}
2873
Johan Hedberg124f6e32012-02-09 13:50:12 +02002874static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002875{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002876 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002877 struct mgmt_cp_unpair_device *cp = cmd->param;
2878 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002879
2880 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002881 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2882 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002883
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002884 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2885
2886 cmd_complete(cmd->sk, cmd->index, cmd->opcode, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002887
2888 mgmt_pending_remove(cmd);
2889}
2890
Johan Hedbergafc747a2012-01-15 18:11:07 +02002891int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2892 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002893{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002894 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002895 struct sock *sk = NULL;
2896 int err;
2897
Johan Hedberg744cf192011-11-08 20:40:14 +02002898 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002899
Johan Hedbergf7520542011-01-20 12:34:39 +02002900 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002901 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002902
Johan Hedbergafc747a2012-01-15 18:11:07 +02002903 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2904 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002905
2906 if (sk)
2907 sock_put(sk);
2908
Johan Hedberg124f6e32012-02-09 13:50:12 +02002909 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002910 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002911
Johan Hedberg8962ee72011-01-20 12:40:27 +02002912 return err;
2913}
2914
Johan Hedberg88c3df12012-02-09 14:27:38 +02002915int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
2916 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002917{
Johan Hedberg88c3df12012-02-09 14:27:38 +02002918 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002919 struct pending_cmd *cmd;
2920 int err;
2921
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002922 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002923 if (!cmd)
2924 return -ENOENT;
2925
Johan Hedberg88c3df12012-02-09 14:27:38 +02002926 bacpy(&rp.addr.bdaddr, bdaddr);
2927 rp.addr.type = link_to_mgmt(link_type, addr_type);
2928 rp.status = mgmt_status(status);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002929
Johan Hedberg88c3df12012-02-09 14:27:38 +02002930 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002931 &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002932
Johan Hedberga664b5b2011-02-19 12:06:02 -03002933 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002934
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002935 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
2936 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002937 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002938}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002939
Johan Hedberg48264f02011-11-09 13:58:58 +02002940int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2941 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002942{
2943 struct mgmt_ev_connect_failed ev;
2944
Johan Hedberg4c659c32011-11-07 23:13:39 +02002945 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002946 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002947 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002948
Johan Hedberg744cf192011-11-08 20:40:14 +02002949 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002950}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002951
Johan Hedberg744cf192011-11-08 20:40:14 +02002952int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002953{
2954 struct mgmt_ev_pin_code_request ev;
2955
Johan Hedbergd8457692012-02-17 14:24:57 +02002956 bacpy(&ev.addr.bdaddr, bdaddr);
2957 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002958 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002959
Johan Hedberg744cf192011-11-08 20:40:14 +02002960 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002961 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002962}
2963
Johan Hedberg744cf192011-11-08 20:40:14 +02002964int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2965 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002966{
2967 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002968 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002969 int err;
2970
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002971 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002972 if (!cmd)
2973 return -ENOENT;
2974
Johan Hedbergd8457692012-02-17 14:24:57 +02002975 bacpy(&rp.addr.bdaddr, bdaddr);
2976 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergca69b792011-11-11 18:10:00 +02002977 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002978
Johan Hedberg744cf192011-11-08 20:40:14 +02002979 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002980 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002981
Johan Hedberga664b5b2011-02-19 12:06:02 -03002982 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002983
2984 return err;
2985}
2986
Johan Hedberg744cf192011-11-08 20:40:14 +02002987int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2988 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002989{
2990 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002991 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002992 int err;
2993
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002994 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002995 if (!cmd)
2996 return -ENOENT;
2997
Johan Hedbergd8457692012-02-17 14:24:57 +02002998 bacpy(&rp.addr.bdaddr, bdaddr);
2999 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergca69b792011-11-11 18:10:00 +02003000 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03003001
Johan Hedberg744cf192011-11-08 20:40:14 +02003002 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01003003 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003004
Johan Hedberga664b5b2011-02-19 12:06:02 -03003005 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003006
3007 return err;
3008}
Johan Hedberga5c29682011-02-19 12:05:57 -03003009
Johan Hedberg744cf192011-11-08 20:40:14 +02003010int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003011 u8 link_type, u8 addr_type, __le32 value,
3012 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003013{
3014 struct mgmt_ev_user_confirm_request ev;
3015
Johan Hedberg744cf192011-11-08 20:40:14 +02003016 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003017
Johan Hedberg272d90d2012-02-09 15:26:12 +02003018 bacpy(&ev.addr.bdaddr, bdaddr);
3019 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003020 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003021 put_unaligned_le32(value, &ev.value);
3022
Johan Hedberg744cf192011-11-08 20:40:14 +02003023 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003024 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003025}
3026
Johan Hedberg272d90d2012-02-09 15:26:12 +02003027int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3028 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003029{
3030 struct mgmt_ev_user_passkey_request ev;
3031
3032 BT_DBG("%s", hdev->name);
3033
Johan Hedberg272d90d2012-02-09 15:26:12 +02003034 bacpy(&ev.addr.bdaddr, bdaddr);
3035 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003036
3037 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3038 NULL);
3039}
3040
Brian Gix0df4c182011-11-16 13:53:13 -08003041static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003042 u8 link_type, u8 addr_type, u8 status,
3043 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003044{
3045 struct pending_cmd *cmd;
3046 struct mgmt_rp_user_confirm_reply rp;
3047 int err;
3048
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003049 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003050 if (!cmd)
3051 return -ENOENT;
3052
Johan Hedberg272d90d2012-02-09 15:26:12 +02003053 bacpy(&rp.addr.bdaddr, bdaddr);
3054 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003055 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02003056 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003057
Johan Hedberga664b5b2011-02-19 12:06:02 -03003058 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003059
3060 return err;
3061}
3062
Johan Hedberg744cf192011-11-08 20:40:14 +02003063int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003064 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003065{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003066 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3067 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003068}
3069
Johan Hedberg272d90d2012-02-09 15:26:12 +02003070int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3071 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003072{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003073 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3074 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003075}
Johan Hedberg2a611692011-02-19 12:06:00 -03003076
Brian Gix604086b2011-11-23 08:28:33 -08003077int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003078 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003079{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003080 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3081 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003082}
3083
Johan Hedberg272d90d2012-02-09 15:26:12 +02003084int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3085 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003086{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003087 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3088 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003089}
3090
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003091int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3092 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003093{
3094 struct mgmt_ev_auth_failed ev;
3095
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003096 bacpy(&ev.addr.bdaddr, bdaddr);
3097 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003098 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003099
Johan Hedberg744cf192011-11-08 20:40:14 +02003100 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003101}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003102
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003103int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3104{
3105 struct cmd_lookup match = { NULL, hdev };
3106 __le32 ev;
3107 int err;
3108
3109 if (status) {
3110 u8 mgmt_err = mgmt_status(status);
3111 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3112 cmd_status_rsp, &mgmt_err);
3113 return 0;
3114 }
3115
3116 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3117 &match);
3118
3119 ev = cpu_to_le32(get_current_settings(hdev));
3120 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3121
3122 if (match.sk)
3123 sock_put(match.sk);
3124
3125 return err;
3126}
3127
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003128int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3129{
3130 struct cmd_lookup match = { NULL, hdev };
3131 __le32 ev;
3132 int err;
3133
3134 if (status) {
3135 u8 mgmt_err = mgmt_status(status);
3136 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3137 cmd_status_rsp, &mgmt_err);
3138 return 0;
3139 }
3140
3141 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3142
3143 ev = cpu_to_le32(get_current_settings(hdev));
3144 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3145
3146 if (match.sk)
3147 sock_put(match.sk);
3148
3149 return err;
3150}
3151
Johan Hedberg744cf192011-11-08 20:40:14 +02003152int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003153{
3154 struct pending_cmd *cmd;
3155 struct mgmt_cp_set_local_name ev;
3156 int err;
3157
3158 memset(&ev, 0, sizeof(ev));
3159 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3160
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003161 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003162 if (!cmd)
3163 goto send_event;
3164
3165 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003166 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003167 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003168 goto failed;
3169 }
3170
Johan Hedberg744cf192011-11-08 20:40:14 +02003171 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003172
Johan Hedberg744cf192011-11-08 20:40:14 +02003173 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003174 sizeof(ev));
3175 if (err < 0)
3176 goto failed;
3177
3178send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003179 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003180 cmd ? cmd->sk : NULL);
3181
3182failed:
3183 if (cmd)
3184 mgmt_pending_remove(cmd);
3185 return err;
3186}
Szymon Jancc35938b2011-03-22 13:12:21 +01003187
Johan Hedberg744cf192011-11-08 20:40:14 +02003188int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3189 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003190{
3191 struct pending_cmd *cmd;
3192 int err;
3193
Johan Hedberg744cf192011-11-08 20:40:14 +02003194 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003195
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003196 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003197 if (!cmd)
3198 return -ENOENT;
3199
3200 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003201 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003202 MGMT_OP_READ_LOCAL_OOB_DATA,
3203 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003204 } else {
3205 struct mgmt_rp_read_local_oob_data rp;
3206
3207 memcpy(rp.hash, hash, sizeof(rp.hash));
3208 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3209
Johan Hedberg744cf192011-11-08 20:40:14 +02003210 err = cmd_complete(cmd->sk, hdev->id,
3211 MGMT_OP_READ_LOCAL_OOB_DATA,
3212 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003213 }
3214
3215 mgmt_pending_remove(cmd);
3216
3217 return err;
3218}
Johan Hedberge17acd42011-03-30 23:57:16 +03003219
Johan Hedberg48264f02011-11-09 13:58:58 +02003220int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003221 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003222 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003223{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003224 char buf[512];
3225 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003226 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003227
Johan Hedberg1dc06092012-01-15 21:01:23 +02003228 /* Leave 5 bytes for a potential CoD field */
3229 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003230 return -EINVAL;
3231
Johan Hedberg1dc06092012-01-15 21:01:23 +02003232 memset(buf, 0, sizeof(buf));
3233
Johan Hedberge319d2e2012-01-15 19:51:59 +02003234 bacpy(&ev->addr.bdaddr, bdaddr);
3235 ev->addr.type = link_to_mgmt(link_type, addr_type);
3236 ev->rssi = rssi;
3237 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003238
Johan Hedberg1dc06092012-01-15 21:01:23 +02003239 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003240 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003241
Johan Hedberg1dc06092012-01-15 21:01:23 +02003242 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3243 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3244 dev_class, 3);
3245
3246 put_unaligned_le16(eir_len, &ev->eir_len);
3247
3248 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003249
Johan Hedberge319d2e2012-01-15 19:51:59 +02003250 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003251}
Johan Hedberga88a9652011-03-30 13:18:12 +03003252
Johan Hedbergb644ba32012-01-17 21:48:47 +02003253int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3254 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003255{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003256 struct mgmt_ev_device_found *ev;
3257 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3258 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003259
Johan Hedbergb644ba32012-01-17 21:48:47 +02003260 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003261
Johan Hedbergb644ba32012-01-17 21:48:47 +02003262 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003263
Johan Hedbergb644ba32012-01-17 21:48:47 +02003264 bacpy(&ev->addr.bdaddr, bdaddr);
3265 ev->addr.type = link_to_mgmt(link_type, addr_type);
3266 ev->rssi = rssi;
3267
3268 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3269 name_len);
3270
3271 put_unaligned_le16(eir_len, &ev->eir_len);
3272
Johan Hedberg053c7e02012-02-04 00:06:00 +02003273 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3274 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003275}
Johan Hedberg314b2382011-04-27 10:29:57 -04003276
Andre Guedes7a135102011-11-09 17:14:25 -03003277int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003278{
3279 struct pending_cmd *cmd;
3280 int err;
3281
Andre Guedes203159d2012-02-13 15:41:01 -03003282 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3283
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003284 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003285 if (!cmd)
3286 return -ENOENT;
3287
Johan Hedbergca69b792011-11-11 18:10:00 +02003288 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003289 mgmt_pending_remove(cmd);
3290
3291 return err;
3292}
3293
Andre Guedese6d465c2011-11-09 17:14:26 -03003294int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3295{
3296 struct pending_cmd *cmd;
3297 int err;
3298
3299 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3300 if (!cmd)
3301 return -ENOENT;
3302
Andre Guedese75a8b0c2012-01-02 16:50:53 -03003303 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02003304 mgmt_pending_remove(cmd);
3305
3306 return err;
3307}
Johan Hedberg314b2382011-04-27 10:29:57 -04003308
Johan Hedberg744cf192011-11-08 20:40:14 +02003309int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003310{
Johan Hedberg164a6e72011-11-01 17:06:44 +02003311 struct pending_cmd *cmd;
3312
Andre Guedes343fb142011-11-22 17:14:19 -03003313 BT_DBG("%s discovering %u", hdev->name, discovering);
3314
Johan Hedberg164a6e72011-11-01 17:06:44 +02003315 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003316 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003317 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003318 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003319
3320 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003321 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003322 mgmt_pending_remove(cmd);
3323 }
3324
Johan Hedberg744cf192011-11-08 20:40:14 +02003325 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04003326 sizeof(discovering), NULL);
3327}
Antti Julku5e762442011-08-25 16:48:02 +03003328
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003329int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003330{
3331 struct pending_cmd *cmd;
3332 struct mgmt_ev_device_blocked ev;
3333
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003334 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003335
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003336 bacpy(&ev.addr.bdaddr, bdaddr);
3337 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003338
Johan Hedberg744cf192011-11-08 20:40:14 +02003339 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3340 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003341}
3342
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003343int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003344{
3345 struct pending_cmd *cmd;
3346 struct mgmt_ev_device_unblocked ev;
3347
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003348 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003349
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003350 bacpy(&ev.addr.bdaddr, bdaddr);
3351 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003352
Johan Hedberg744cf192011-11-08 20:40:14 +02003353 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3354 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003355}