blob: f9f3e4c44150daaa3e5a8b423d3c9fa7a963e1be [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;
Andre Guedes3fd24152012-02-03 17:48:01 -03002160 unsigned long discov_type = cp->type;
Johan Hedberg14a53662011-04-27 10:29:56 -04002161 struct pending_cmd *cmd;
2162 struct hci_dev *hdev;
2163 int err;
2164
2165 BT_DBG("hci%u", index);
2166
Johan Hedberg450dfda2011-11-12 11:58:22 +02002167 if (len != sizeof(*cp))
2168 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2169 MGMT_STATUS_INVALID_PARAMS);
2170
Johan Hedberg14a53662011-04-27 10:29:56 -04002171 hdev = hci_dev_get(index);
2172 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002173 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2174 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002175
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002176 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002177
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002178 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002179 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2180 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002181 goto failed;
2182 }
2183
Johan Hedbergff9ef572012-01-04 14:23:45 +02002184 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2185 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2186 MGMT_STATUS_BUSY);
2187 goto failed;
2188 }
2189
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002190 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002191 if (!cmd) {
2192 err = -ENOMEM;
2193 goto failed;
2194 }
2195
Andre Guedes3fd24152012-02-03 17:48:01 -03002196 if (test_bit(MGMT_ADDR_BREDR, &discov_type))
2197 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2198 else if (test_bit(MGMT_ADDR_LE_PUBLIC, &discov_type) &&
2199 test_bit(MGMT_ADDR_LE_RANDOM, &discov_type))
2200 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2201 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
2202 else
2203 err = -EINVAL;
2204
Johan Hedberg14a53662011-04-27 10:29:56 -04002205 if (err < 0)
2206 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002207 else
2208 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002209
2210failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002211 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002212 hci_dev_put(hdev);
2213
2214 return err;
2215}
2216
2217static int stop_discovery(struct sock *sk, u16 index)
2218{
2219 struct hci_dev *hdev;
2220 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002221 struct hci_cp_remote_name_req_cancel cp;
2222 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002223 int err;
2224
2225 BT_DBG("hci%u", index);
2226
2227 hdev = hci_dev_get(index);
2228 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002229 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2230 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002231
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002232 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002233
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002234 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002235 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2236 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002237 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002238 }
2239
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002240 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002241 if (!cmd) {
2242 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002243 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002244 }
2245
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002246 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
2247 err = hci_cancel_inquiry(hdev);
2248 if (err < 0)
2249 mgmt_pending_remove(cmd);
2250 else
2251 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2252 goto unlock;
2253 }
2254
2255 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2256 if (!e) {
2257 mgmt_pending_remove(cmd);
2258 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2259 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2260 goto unlock;
2261 }
2262
2263 bacpy(&cp.bdaddr, &e->data.bdaddr);
2264 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2265 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002266 if (err < 0)
2267 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002268 else
2269 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002270
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002271unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002272 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002273 hci_dev_put(hdev);
2274
2275 return err;
2276}
2277
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002278static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002279{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002280 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002281 struct inquiry_entry *e;
2282 struct hci_dev *hdev;
2283 int err;
2284
2285 BT_DBG("hci%u", index);
2286
2287 if (len != sizeof(*cp))
2288 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2289 MGMT_STATUS_INVALID_PARAMS);
2290
2291 hdev = hci_dev_get(index);
2292 if (!hdev)
2293 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2294 MGMT_STATUS_INVALID_PARAMS);
2295
2296 hci_dev_lock(hdev);
2297
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002298 if (!hci_discovery_active(hdev)) {
2299 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2300 MGMT_STATUS_FAILED);
2301 goto failed;
2302 }
2303
Johan Hedberga198e7b2012-02-17 14:27:06 +02002304 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002305 if (!e) {
2306 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2307 MGMT_STATUS_INVALID_PARAMS);
2308 goto failed;
2309 }
2310
2311 if (cp->name_known) {
2312 e->name_state = NAME_KNOWN;
2313 list_del(&e->list);
2314 } else {
2315 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002316 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002317 }
2318
2319 err = 0;
2320
2321failed:
2322 hci_dev_unlock(hdev);
2323
2324 return err;
2325}
2326
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002327static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002328{
2329 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002330 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002331 int err;
2332
2333 BT_DBG("hci%u", index);
2334
Antti Julku7fbec222011-06-15 12:01:15 +03002335 if (len != sizeof(*cp))
2336 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002337 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002338
2339 hdev = hci_dev_get(index);
2340 if (!hdev)
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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002344 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002345
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002346 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002347 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002348 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2349 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002350 else
2351 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2352 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002353
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002354 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002355 hci_dev_put(hdev);
2356
2357 return err;
2358}
2359
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002360static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002361{
2362 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002363 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002364 int err;
2365
2366 BT_DBG("hci%u", index);
2367
Antti Julku7fbec222011-06-15 12:01:15 +03002368 if (len != sizeof(*cp))
2369 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002370 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002371
2372 hdev = hci_dev_get(index);
2373 if (!hdev)
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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002377 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002378
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002379 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002380
2381 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002382 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2383 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002384 else
2385 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2386 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002387
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002388 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002389 hci_dev_put(hdev);
2390
2391 return err;
2392}
2393
Antti Julkuf6422ec2011-06-22 13:11:56 +03002394static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002395 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002396{
2397 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002398 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002399 struct hci_cp_write_page_scan_activity acp;
2400 u8 type;
2401 int err;
2402
2403 BT_DBG("hci%u", index);
2404
2405 if (len != sizeof(*cp))
2406 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002407 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002408
2409 hdev = hci_dev_get(index);
2410 if (!hdev)
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 hci_dev_lock(hdev);
2415
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002416 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002417 type = PAGE_SCAN_TYPE_INTERLACED;
2418 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2419 } else {
2420 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2421 acp.interval = 0x0800; /* default 1.28 sec page scan */
2422 }
2423
2424 acp.window = 0x0012; /* default 11.25 msec page scan window */
2425
2426 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2427 sizeof(acp), &acp);
2428 if (err < 0) {
2429 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002430 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002431 goto done;
2432 }
2433
2434 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2435 if (err < 0) {
2436 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002437 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002438 goto done;
2439 }
2440
2441 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2442 NULL, 0);
2443done:
2444 hci_dev_unlock(hdev);
2445 hci_dev_put(hdev);
2446
2447 return err;
2448}
2449
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002450static int load_long_term_keys(struct sock *sk, u16 index,
2451 void *cp_data, u16 len)
2452{
2453 struct hci_dev *hdev;
2454 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2455 u16 key_count, expected_len;
2456 int i;
2457
2458 if (len < sizeof(*cp))
2459 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2460 EINVAL);
2461
2462 key_count = get_unaligned_le16(&cp->key_count);
2463
2464 expected_len = sizeof(*cp) + key_count *
2465 sizeof(struct mgmt_ltk_info);
2466 if (expected_len != len) {
2467 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2468 len, expected_len);
2469 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2470 EINVAL);
2471 }
2472
2473 hdev = hci_dev_get(index);
2474 if (!hdev)
2475 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2476 ENODEV);
2477
2478 BT_DBG("hci%u key_count %u", index, key_count);
2479
2480 hci_dev_lock(hdev);
2481
2482 hci_smp_ltks_clear(hdev);
2483
2484 for (i = 0; i < key_count; i++) {
2485 struct mgmt_ltk_info *key = &cp->keys[i];
2486 u8 type;
2487
2488 if (key->master)
2489 type = HCI_SMP_LTK;
2490 else
2491 type = HCI_SMP_LTK_SLAVE;
2492
2493 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2494 type, 0, key->authenticated, key->val,
2495 key->enc_size, key->ediv, key->rand);
2496 }
2497
2498 hci_dev_unlock(hdev);
2499 hci_dev_put(hdev);
2500
2501 return 0;
2502}
2503
Johan Hedberg03811012010-12-08 00:21:06 +02002504int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2505{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002506 void *buf;
2507 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002508 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002509 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002510 int err;
2511
2512 BT_DBG("got %zu bytes", msglen);
2513
2514 if (msglen < sizeof(*hdr))
2515 return -EINVAL;
2516
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002517 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002518 if (!buf)
2519 return -ENOMEM;
2520
2521 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2522 err = -EFAULT;
2523 goto done;
2524 }
2525
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002526 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002527 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002528 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002529 len = get_unaligned_le16(&hdr->len);
2530
2531 if (len != msglen - sizeof(*hdr)) {
2532 err = -EINVAL;
2533 goto done;
2534 }
2535
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002536 cp = buf + sizeof(*hdr);
2537
Johan Hedberg03811012010-12-08 00:21:06 +02002538 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002539 case MGMT_OP_READ_VERSION:
2540 err = read_version(sk);
2541 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002542 case MGMT_OP_READ_COMMANDS:
2543 err = read_commands(sk);
2544 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002545 case MGMT_OP_READ_INDEX_LIST:
2546 err = read_index_list(sk);
2547 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002548 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002549 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002550 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002551 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002552 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002553 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002554 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002555 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002556 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002557 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002558 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002559 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002560 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002561 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002562 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002563 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002564 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002565 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002566 case MGMT_OP_SET_LINK_SECURITY:
2567 err = set_link_security(sk, index, cp, len);
2568 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002569 case MGMT_OP_SET_SSP:
2570 err = set_ssp(sk, index, cp, len);
2571 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002572 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002573 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002574 break;
2575 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002576 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002577 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002578 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002579 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002580 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002581 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002582 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002583 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002584 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002585 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002586 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002587 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002588 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002589 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002590 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002591 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002592 break;
2593 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002594 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002595 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002596 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002597 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002598 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002599 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002600 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002601 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002602 case MGMT_OP_CANCEL_PAIR_DEVICE:
2603 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2604 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002605 case MGMT_OP_UNPAIR_DEVICE:
2606 err = unpair_device(sk, index, cp, len);
2607 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002608 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002609 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002610 break;
2611 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002612 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002613 break;
Brian Gix604086b2011-11-23 08:28:33 -08002614 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002615 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002616 break;
2617 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002618 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002619 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002620 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002621 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002622 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002623 case MGMT_OP_READ_LOCAL_OOB_DATA:
2624 err = read_local_oob_data(sk, index);
2625 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002626 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002627 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002628 break;
2629 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002630 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002631 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002632 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002633 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002634 break;
2635 case MGMT_OP_STOP_DISCOVERY:
2636 err = stop_discovery(sk, index);
2637 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002638 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002639 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002640 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002641 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002642 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002643 break;
2644 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002645 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002646 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002647 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2648 err = load_long_term_keys(sk, index, cp, len);
2649 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002650 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002651 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002652 err = cmd_status(sk, index, opcode,
2653 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002654 break;
2655 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002656
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002657 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002658 goto done;
2659
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002660 err = msglen;
2661
2662done:
2663 kfree(buf);
2664 return err;
2665}
2666
Johan Hedbergb24752f2011-11-03 14:40:33 +02002667static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2668{
2669 u8 *status = data;
2670
2671 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2672 mgmt_pending_remove(cmd);
2673}
2674
Johan Hedberg744cf192011-11-08 20:40:14 +02002675int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002676{
Johan Hedberg744cf192011-11-08 20:40:14 +02002677 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002678}
2679
Johan Hedberg744cf192011-11-08 20:40:14 +02002680int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002681{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002682 u8 status = ENODEV;
2683
Johan Hedberg744cf192011-11-08 20:40:14 +02002684 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002685
Johan Hedberg744cf192011-11-08 20:40:14 +02002686 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002687}
2688
2689struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002690 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002691 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002692};
2693
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002694static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002695{
Johan Hedberg03811012010-12-08 00:21:06 +02002696 struct cmd_lookup *match = data;
2697
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002698 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002699
2700 list_del(&cmd->list);
2701
2702 if (match->sk == NULL) {
2703 match->sk = cmd->sk;
2704 sock_hold(match->sk);
2705 }
2706
2707 mgmt_pending_free(cmd);
2708}
2709
Johan Hedberg744cf192011-11-08 20:40:14 +02002710int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002711{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002712 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002713 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002714 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002715
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002716 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002717
Johan Hedbergb24752f2011-11-03 14:40:33 +02002718 if (!powered) {
2719 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002720 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002721 }
2722
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002723 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002724
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002725 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002726 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002727
2728 if (match.sk)
2729 sock_put(match.sk);
2730
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002731 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002732}
2733
Johan Hedberg744cf192011-11-08 20:40:14 +02002734int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002735{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002736 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002737 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002738 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002739
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002740 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002741
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002742 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002743
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002744 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002745 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002746 if (match.sk)
2747 sock_put(match.sk);
2748
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002749 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002750}
2751
Johan Hedberg744cf192011-11-08 20:40:14 +02002752int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002753{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002754 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002755 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002756 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002757
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002758 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2759 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002760
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002761 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002762
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002763 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002764
2765 if (match.sk)
2766 sock_put(match.sk);
2767
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002768 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002769}
2770
Johan Hedberg744cf192011-11-08 20:40:14 +02002771int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002772{
Johan Hedbergca69b792011-11-11 18:10:00 +02002773 u8 mgmt_err = mgmt_status(status);
2774
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002775 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002776 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002777 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002778
2779 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002780 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002781 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002782
2783 return 0;
2784}
2785
Johan Hedberg744cf192011-11-08 20:40:14 +02002786int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2787 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002788{
Johan Hedberg86742e12011-11-07 23:13:38 +02002789 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002790
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002791 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002792
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002793 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002794 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2795 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002796 ev.key.type = key->type;
2797 memcpy(ev.key.val, key->val, 16);
2798 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002799
Johan Hedberg744cf192011-11-08 20:40:14 +02002800 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002801}
Johan Hedbergf7520542011-01-20 12:34:39 +02002802
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002803int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2804{
2805 struct mgmt_ev_new_long_term_key ev;
2806
2807 memset(&ev, 0, sizeof(ev));
2808
2809 ev.store_hint = persistent;
2810 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2811 ev.key.addr.type = key->bdaddr_type;
2812 ev.key.authenticated = key->authenticated;
2813 ev.key.enc_size = key->enc_size;
2814 ev.key.ediv = key->ediv;
2815
2816 if (key->type == HCI_SMP_LTK)
2817 ev.key.master = 1;
2818
2819 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2820 memcpy(ev.key.val, key->val, sizeof(key->val));
2821
2822 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2823 &ev, sizeof(ev), NULL);
2824}
2825
Johan Hedbergafc747a2012-01-15 18:11:07 +02002826int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002827 u8 addr_type, u8 *name, u8 name_len,
2828 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002829{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002830 char buf[512];
2831 struct mgmt_ev_device_connected *ev = (void *) buf;
2832 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002833
Johan Hedbergb644ba32012-01-17 21:48:47 +02002834 bacpy(&ev->addr.bdaddr, bdaddr);
2835 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002836
Johan Hedbergb644ba32012-01-17 21:48:47 +02002837 if (name_len > 0)
2838 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2839 name, name_len);
2840
2841 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2842 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2843 EIR_CLASS_OF_DEV, dev_class, 3);
2844
2845 put_unaligned_le16(eir_len, &ev->eir_len);
2846
2847 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2848 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002849}
2850
Johan Hedberg8962ee72011-01-20 12:40:27 +02002851static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2852{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002853 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002854 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002855 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002856
Johan Hedberg88c3df12012-02-09 14:27:38 +02002857 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2858 rp.addr.type = cp->addr.type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002859 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002860
Szymon Janc4e51eae2011-02-25 19:05:48 +01002861 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002862
2863 *sk = cmd->sk;
2864 sock_hold(*sk);
2865
Johan Hedberga664b5b2011-02-19 12:06:02 -03002866 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002867}
2868
Johan Hedberg124f6e32012-02-09 13:50:12 +02002869static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002870{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002871 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002872 struct mgmt_cp_unpair_device *cp = cmd->param;
2873 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002874
2875 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002876 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2877 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002878
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002879 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2880
2881 cmd_complete(cmd->sk, cmd->index, cmd->opcode, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002882
2883 mgmt_pending_remove(cmd);
2884}
2885
Johan Hedbergafc747a2012-01-15 18:11:07 +02002886int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2887 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002888{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002889 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002890 struct sock *sk = NULL;
2891 int err;
2892
Johan Hedberg744cf192011-11-08 20:40:14 +02002893 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002894
Johan Hedbergf7520542011-01-20 12:34:39 +02002895 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002896 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002897
Johan Hedbergafc747a2012-01-15 18:11:07 +02002898 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2899 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002900
2901 if (sk)
2902 sock_put(sk);
2903
Johan Hedberg124f6e32012-02-09 13:50:12 +02002904 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002905 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002906
Johan Hedberg8962ee72011-01-20 12:40:27 +02002907 return err;
2908}
2909
Johan Hedberg88c3df12012-02-09 14:27:38 +02002910int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
2911 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002912{
Johan Hedberg88c3df12012-02-09 14:27:38 +02002913 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002914 struct pending_cmd *cmd;
2915 int err;
2916
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002917 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002918 if (!cmd)
2919 return -ENOENT;
2920
Johan Hedberg88c3df12012-02-09 14:27:38 +02002921 bacpy(&rp.addr.bdaddr, bdaddr);
2922 rp.addr.type = link_to_mgmt(link_type, addr_type);
2923 rp.status = mgmt_status(status);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002924
Johan Hedberg88c3df12012-02-09 14:27:38 +02002925 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002926 &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002927
Johan Hedberga664b5b2011-02-19 12:06:02 -03002928 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002929
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002930 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
2931 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002932 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002933}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002934
Johan Hedberg48264f02011-11-09 13:58:58 +02002935int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2936 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002937{
2938 struct mgmt_ev_connect_failed ev;
2939
Johan Hedberg4c659c32011-11-07 23:13:39 +02002940 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002941 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002942 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002943
Johan Hedberg744cf192011-11-08 20:40:14 +02002944 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002945}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002946
Johan Hedberg744cf192011-11-08 20:40:14 +02002947int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002948{
2949 struct mgmt_ev_pin_code_request ev;
2950
Johan Hedbergd8457692012-02-17 14:24:57 +02002951 bacpy(&ev.addr.bdaddr, bdaddr);
2952 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002953 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002954
Johan Hedberg744cf192011-11-08 20:40:14 +02002955 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002956 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002957}
2958
Johan Hedberg744cf192011-11-08 20:40:14 +02002959int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2960 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002961{
2962 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002963 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002964 int err;
2965
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002966 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002967 if (!cmd)
2968 return -ENOENT;
2969
Johan Hedbergd8457692012-02-17 14:24:57 +02002970 bacpy(&rp.addr.bdaddr, bdaddr);
2971 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergca69b792011-11-11 18:10:00 +02002972 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002973
Johan Hedberg744cf192011-11-08 20:40:14 +02002974 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002975 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002976
Johan Hedberga664b5b2011-02-19 12:06:02 -03002977 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002978
2979 return err;
2980}
2981
Johan Hedberg744cf192011-11-08 20:40:14 +02002982int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2983 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002984{
2985 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002986 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002987 int err;
2988
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002989 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002990 if (!cmd)
2991 return -ENOENT;
2992
Johan Hedbergd8457692012-02-17 14:24:57 +02002993 bacpy(&rp.addr.bdaddr, bdaddr);
2994 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergca69b792011-11-11 18:10:00 +02002995 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002996
Johan Hedberg744cf192011-11-08 20:40:14 +02002997 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002998 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002999
Johan Hedberga664b5b2011-02-19 12:06:02 -03003000 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003001
3002 return err;
3003}
Johan Hedberga5c29682011-02-19 12:05:57 -03003004
Johan Hedberg744cf192011-11-08 20:40:14 +02003005int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003006 u8 link_type, u8 addr_type, __le32 value,
3007 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003008{
3009 struct mgmt_ev_user_confirm_request ev;
3010
Johan Hedberg744cf192011-11-08 20:40:14 +02003011 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003012
Johan Hedberg272d90d2012-02-09 15:26:12 +02003013 bacpy(&ev.addr.bdaddr, bdaddr);
3014 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003015 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003016 put_unaligned_le32(value, &ev.value);
3017
Johan Hedberg744cf192011-11-08 20:40:14 +02003018 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003019 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003020}
3021
Johan Hedberg272d90d2012-02-09 15:26:12 +02003022int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3023 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003024{
3025 struct mgmt_ev_user_passkey_request ev;
3026
3027 BT_DBG("%s", hdev->name);
3028
Johan Hedberg272d90d2012-02-09 15:26:12 +02003029 bacpy(&ev.addr.bdaddr, bdaddr);
3030 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003031
3032 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3033 NULL);
3034}
3035
Brian Gix0df4c182011-11-16 13:53:13 -08003036static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003037 u8 link_type, u8 addr_type, u8 status,
3038 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003039{
3040 struct pending_cmd *cmd;
3041 struct mgmt_rp_user_confirm_reply rp;
3042 int err;
3043
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003044 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003045 if (!cmd)
3046 return -ENOENT;
3047
Johan Hedberg272d90d2012-02-09 15:26:12 +02003048 bacpy(&rp.addr.bdaddr, bdaddr);
3049 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003050 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02003051 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003052
Johan Hedberga664b5b2011-02-19 12:06:02 -03003053 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003054
3055 return err;
3056}
3057
Johan Hedberg744cf192011-11-08 20:40:14 +02003058int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003059 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003060{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003061 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3062 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003063}
3064
Johan Hedberg272d90d2012-02-09 15:26:12 +02003065int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3066 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003067{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003068 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3069 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003070}
Johan Hedberg2a611692011-02-19 12:06:00 -03003071
Brian Gix604086b2011-11-23 08:28:33 -08003072int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003073 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003074{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003075 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3076 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003077}
3078
Johan Hedberg272d90d2012-02-09 15:26:12 +02003079int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3080 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003081{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003082 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3083 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003084}
3085
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003086int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3087 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003088{
3089 struct mgmt_ev_auth_failed ev;
3090
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003091 bacpy(&ev.addr.bdaddr, bdaddr);
3092 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003093 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003094
Johan Hedberg744cf192011-11-08 20:40:14 +02003095 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003096}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003097
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003098int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3099{
3100 struct cmd_lookup match = { NULL, hdev };
3101 __le32 ev;
3102 int err;
3103
3104 if (status) {
3105 u8 mgmt_err = mgmt_status(status);
3106 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3107 cmd_status_rsp, &mgmt_err);
3108 return 0;
3109 }
3110
3111 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3112 &match);
3113
3114 ev = cpu_to_le32(get_current_settings(hdev));
3115 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3116
3117 if (match.sk)
3118 sock_put(match.sk);
3119
3120 return err;
3121}
3122
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003123int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3124{
3125 struct cmd_lookup match = { NULL, hdev };
3126 __le32 ev;
3127 int err;
3128
3129 if (status) {
3130 u8 mgmt_err = mgmt_status(status);
3131 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3132 cmd_status_rsp, &mgmt_err);
3133 return 0;
3134 }
3135
3136 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3137
3138 ev = cpu_to_le32(get_current_settings(hdev));
3139 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3140
3141 if (match.sk)
3142 sock_put(match.sk);
3143
3144 return err;
3145}
3146
Johan Hedberg744cf192011-11-08 20:40:14 +02003147int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003148{
3149 struct pending_cmd *cmd;
3150 struct mgmt_cp_set_local_name ev;
3151 int err;
3152
3153 memset(&ev, 0, sizeof(ev));
3154 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3155
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003156 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003157 if (!cmd)
3158 goto send_event;
3159
3160 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003161 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003162 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003163 goto failed;
3164 }
3165
Johan Hedberg744cf192011-11-08 20:40:14 +02003166 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003167
Johan Hedberg744cf192011-11-08 20:40:14 +02003168 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003169 sizeof(ev));
3170 if (err < 0)
3171 goto failed;
3172
3173send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003174 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003175 cmd ? cmd->sk : NULL);
3176
3177failed:
3178 if (cmd)
3179 mgmt_pending_remove(cmd);
3180 return err;
3181}
Szymon Jancc35938b2011-03-22 13:12:21 +01003182
Johan Hedberg744cf192011-11-08 20:40:14 +02003183int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3184 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003185{
3186 struct pending_cmd *cmd;
3187 int err;
3188
Johan Hedberg744cf192011-11-08 20:40:14 +02003189 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003190
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003191 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003192 if (!cmd)
3193 return -ENOENT;
3194
3195 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003196 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003197 MGMT_OP_READ_LOCAL_OOB_DATA,
3198 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003199 } else {
3200 struct mgmt_rp_read_local_oob_data rp;
3201
3202 memcpy(rp.hash, hash, sizeof(rp.hash));
3203 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3204
Johan Hedberg744cf192011-11-08 20:40:14 +02003205 err = cmd_complete(cmd->sk, hdev->id,
3206 MGMT_OP_READ_LOCAL_OOB_DATA,
3207 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003208 }
3209
3210 mgmt_pending_remove(cmd);
3211
3212 return err;
3213}
Johan Hedberge17acd42011-03-30 23:57:16 +03003214
Johan Hedberg48264f02011-11-09 13:58:58 +02003215int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003216 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003217 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003218{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003219 char buf[512];
3220 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003221 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003222
Johan Hedberg1dc06092012-01-15 21:01:23 +02003223 /* Leave 5 bytes for a potential CoD field */
3224 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003225 return -EINVAL;
3226
Johan Hedberg1dc06092012-01-15 21:01:23 +02003227 memset(buf, 0, sizeof(buf));
3228
Johan Hedberge319d2e2012-01-15 19:51:59 +02003229 bacpy(&ev->addr.bdaddr, bdaddr);
3230 ev->addr.type = link_to_mgmt(link_type, addr_type);
3231 ev->rssi = rssi;
3232 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003233
Johan Hedberg1dc06092012-01-15 21:01:23 +02003234 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003235 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003236
Johan Hedberg1dc06092012-01-15 21:01:23 +02003237 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3238 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3239 dev_class, 3);
3240
3241 put_unaligned_le16(eir_len, &ev->eir_len);
3242
3243 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003244
Johan Hedberge319d2e2012-01-15 19:51:59 +02003245 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003246}
Johan Hedberga88a9652011-03-30 13:18:12 +03003247
Johan Hedbergb644ba32012-01-17 21:48:47 +02003248int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3249 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003250{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003251 struct mgmt_ev_device_found *ev;
3252 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3253 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003254
Johan Hedbergb644ba32012-01-17 21:48:47 +02003255 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003256
Johan Hedbergb644ba32012-01-17 21:48:47 +02003257 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003258
Johan Hedbergb644ba32012-01-17 21:48:47 +02003259 bacpy(&ev->addr.bdaddr, bdaddr);
3260 ev->addr.type = link_to_mgmt(link_type, addr_type);
3261 ev->rssi = rssi;
3262
3263 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3264 name_len);
3265
3266 put_unaligned_le16(eir_len, &ev->eir_len);
3267
Johan Hedberg053c7e02012-02-04 00:06:00 +02003268 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3269 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003270}
Johan Hedberg314b2382011-04-27 10:29:57 -04003271
Andre Guedes7a135102011-11-09 17:14:25 -03003272int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003273{
3274 struct pending_cmd *cmd;
3275 int err;
3276
Andre Guedes203159d2012-02-13 15:41:01 -03003277 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3278
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003279 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003280 if (!cmd)
3281 return -ENOENT;
3282
Johan Hedbergca69b792011-11-11 18:10:00 +02003283 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003284 mgmt_pending_remove(cmd);
3285
3286 return err;
3287}
3288
Andre Guedese6d465c2011-11-09 17:14:26 -03003289int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3290{
3291 struct pending_cmd *cmd;
3292 int err;
3293
3294 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3295 if (!cmd)
3296 return -ENOENT;
3297
Andre Guedese75a8b0c2012-01-02 16:50:53 -03003298 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02003299 mgmt_pending_remove(cmd);
3300
3301 return err;
3302}
Johan Hedberg314b2382011-04-27 10:29:57 -04003303
Johan Hedberg744cf192011-11-08 20:40:14 +02003304int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003305{
Johan Hedberg164a6e72011-11-01 17:06:44 +02003306 struct pending_cmd *cmd;
3307
Andre Guedes343fb142011-11-22 17:14:19 -03003308 BT_DBG("%s discovering %u", hdev->name, discovering);
3309
Johan Hedberg164a6e72011-11-01 17:06:44 +02003310 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003311 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003312 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003313 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003314
3315 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003316 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003317 mgmt_pending_remove(cmd);
3318 }
3319
Johan Hedberg744cf192011-11-08 20:40:14 +02003320 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04003321 sizeof(discovering), NULL);
3322}
Antti Julku5e762442011-08-25 16:48:02 +03003323
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003324int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003325{
3326 struct pending_cmd *cmd;
3327 struct mgmt_ev_device_blocked ev;
3328
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003329 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003330
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003331 bacpy(&ev.addr.bdaddr, bdaddr);
3332 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003333
Johan Hedberg744cf192011-11-08 20:40:14 +02003334 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3335 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003336}
3337
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003338int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003339{
3340 struct pending_cmd *cmd;
3341 struct mgmt_ev_device_unblocked ev;
3342
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003343 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003344
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003345 bacpy(&ev.addr.bdaddr, bdaddr);
3346 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003347
Johan Hedberg744cf192011-11-08 20:40:14 +02003348 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3349 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003350}