blob: 0c9fbb45d2e9eb1ca66c19538b774d90c1d9a501 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Johan Hedbergca69b792011-11-11 18:10:00 +020025#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Johan Hedberg02d98122010-12-13 21:07:04 +020035#define MGMT_VERSION 0
36#define MGMT_REVISION 1
37
Johan Hedberge70bb2e2012-02-13 16:59:33 +020038static const u16 mgmt_commands[] = {
39 MGMT_OP_READ_INDEX_LIST,
40 MGMT_OP_READ_INFO,
41 MGMT_OP_SET_POWERED,
42 MGMT_OP_SET_DISCOVERABLE,
43 MGMT_OP_SET_CONNECTABLE,
44 MGMT_OP_SET_FAST_CONNECTABLE,
45 MGMT_OP_SET_PAIRABLE,
46 MGMT_OP_SET_LINK_SECURITY,
47 MGMT_OP_SET_SSP,
48 MGMT_OP_SET_HS,
49 MGMT_OP_SET_LE,
50 MGMT_OP_SET_DEV_CLASS,
51 MGMT_OP_SET_LOCAL_NAME,
52 MGMT_OP_ADD_UUID,
53 MGMT_OP_REMOVE_UUID,
54 MGMT_OP_LOAD_LINK_KEYS,
55 MGMT_OP_LOAD_LONG_TERM_KEYS,
56 MGMT_OP_DISCONNECT,
57 MGMT_OP_GET_CONNECTIONS,
58 MGMT_OP_PIN_CODE_REPLY,
59 MGMT_OP_PIN_CODE_NEG_REPLY,
60 MGMT_OP_SET_IO_CAPABILITY,
61 MGMT_OP_PAIR_DEVICE,
62 MGMT_OP_CANCEL_PAIR_DEVICE,
63 MGMT_OP_UNPAIR_DEVICE,
64 MGMT_OP_USER_CONFIRM_REPLY,
65 MGMT_OP_USER_CONFIRM_NEG_REPLY,
66 MGMT_OP_USER_PASSKEY_REPLY,
67 MGMT_OP_USER_PASSKEY_NEG_REPLY,
68 MGMT_OP_READ_LOCAL_OOB_DATA,
69 MGMT_OP_ADD_REMOTE_OOB_DATA,
70 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
71 MGMT_OP_START_DISCOVERY,
72 MGMT_OP_STOP_DISCOVERY,
73 MGMT_OP_CONFIRM_NAME,
74 MGMT_OP_BLOCK_DEVICE,
75 MGMT_OP_UNBLOCK_DEVICE,
76};
77
78static const u16 mgmt_events[] = {
79 MGMT_EV_CONTROLLER_ERROR,
80 MGMT_EV_INDEX_ADDED,
81 MGMT_EV_INDEX_REMOVED,
82 MGMT_EV_NEW_SETTINGS,
83 MGMT_EV_CLASS_OF_DEV_CHANGED,
84 MGMT_EV_LOCAL_NAME_CHANGED,
85 MGMT_EV_NEW_LINK_KEY,
86 MGMT_EV_NEW_LONG_TERM_KEY,
87 MGMT_EV_DEVICE_CONNECTED,
88 MGMT_EV_DEVICE_DISCONNECTED,
89 MGMT_EV_CONNECT_FAILED,
90 MGMT_EV_PIN_CODE_REQUEST,
91 MGMT_EV_USER_CONFIRM_REQUEST,
92 MGMT_EV_USER_PASSKEY_REQUEST,
93 MGMT_EV_AUTH_FAILED,
94 MGMT_EV_DEVICE_FOUND,
95 MGMT_EV_DISCOVERING,
96 MGMT_EV_DEVICE_BLOCKED,
97 MGMT_EV_DEVICE_UNBLOCKED,
98 MGMT_EV_DEVICE_UNPAIRED,
99};
100
Andre Guedes3fd24152012-02-03 17:48:01 -0300101/*
102 * These LE scan and inquiry parameters were chosen according to LE General
103 * Discovery Procedure specification.
104 */
105#define LE_SCAN_TYPE 0x01
106#define LE_SCAN_WIN 0x12
107#define LE_SCAN_INT 0x12
108#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
109
Andre Guedese8777522012-02-03 17:48:02 -0300110#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300111
Johan Hedberg7d785252011-12-15 00:47:39 +0200112#define SERVICE_CACHE_TIMEOUT (5 * 1000)
113
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200114struct pending_cmd {
115 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200116 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100118 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200119 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300120 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200121};
122
Johan Hedbergca69b792011-11-11 18:10:00 +0200123/* HCI to MGMT error code conversion table */
124static u8 mgmt_status_table[] = {
125 MGMT_STATUS_SUCCESS,
126 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
127 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
128 MGMT_STATUS_FAILED, /* Hardware Failure */
129 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
130 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
131 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
132 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
133 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
134 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
135 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
136 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
137 MGMT_STATUS_BUSY, /* Command Disallowed */
138 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
139 MGMT_STATUS_REJECTED, /* Rejected Security */
140 MGMT_STATUS_REJECTED, /* Rejected Personal */
141 MGMT_STATUS_TIMEOUT, /* Host Timeout */
142 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
143 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
144 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
145 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
146 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
147 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
148 MGMT_STATUS_BUSY, /* Repeated Attempts */
149 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
150 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
151 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
152 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
153 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
154 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
155 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
156 MGMT_STATUS_FAILED, /* Unspecified Error */
157 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
158 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
159 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
160 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
161 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
162 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
163 MGMT_STATUS_FAILED, /* Unit Link Key Used */
164 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
165 MGMT_STATUS_TIMEOUT, /* Instant Passed */
166 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
167 MGMT_STATUS_FAILED, /* Transaction Collision */
168 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
169 MGMT_STATUS_REJECTED, /* QoS Rejected */
170 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
171 MGMT_STATUS_REJECTED, /* Insufficient Security */
172 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
173 MGMT_STATUS_BUSY, /* Role Switch Pending */
174 MGMT_STATUS_FAILED, /* Slot Violation */
175 MGMT_STATUS_FAILED, /* Role Switch Failed */
176 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
177 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
178 MGMT_STATUS_BUSY, /* Host Busy Pairing */
179 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
180 MGMT_STATUS_BUSY, /* Controller Busy */
181 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
182 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
183 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
184 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
185 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
186};
187
188static u8 mgmt_status(u8 hci_status)
189{
190 if (hci_status < ARRAY_SIZE(mgmt_status_table))
191 return mgmt_status_table[hci_status];
192
193 return MGMT_STATUS_FAILED;
194}
195
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200197{
198 struct sk_buff *skb;
199 struct mgmt_hdr *hdr;
200 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300201 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200202
Szymon Janc34eb5252011-02-28 14:10:08 +0100203 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200204
205 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
206 if (!skb)
207 return -ENOMEM;
208
209 hdr = (void *) skb_put(skb, sizeof(*hdr));
210
211 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100212 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200213 hdr->len = cpu_to_le16(sizeof(*ev));
214
215 ev = (void *) skb_put(skb, sizeof(*ev));
216 ev->status = status;
217 put_unaligned_le16(cmd, &ev->opcode);
218
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300219 err = sock_queue_rcv_skb(sk, skb);
220 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200221 kfree_skb(skb);
222
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300223 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200224}
225
Szymon Janc4e51eae2011-02-25 19:05:48 +0100226static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
227 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200228{
229 struct sk_buff *skb;
230 struct mgmt_hdr *hdr;
231 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300232 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200233
234 BT_DBG("sock %p", sk);
235
Johan Hedberga38528f2011-01-22 06:46:43 +0200236 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200237 if (!skb)
238 return -ENOMEM;
239
240 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200241
Johan Hedberg02d98122010-12-13 21:07:04 +0200242 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100243 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
247 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100248
249 if (rp)
250 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300252 err = sock_queue_rcv_skb(sk, skb);
253 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200254 kfree_skb(skb);
255
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300256 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200257}
258
Johan Hedberga38528f2011-01-22 06:46:43 +0200259static int read_version(struct sock *sk)
260{
261 struct mgmt_rp_read_version rp;
262
263 BT_DBG("sock %p", sk);
264
265 rp.version = MGMT_VERSION;
266 put_unaligned_le16(MGMT_REVISION, &rp.revision);
267
Szymon Janc4e51eae2011-02-25 19:05:48 +0100268 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
269 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200270}
271
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200272static int read_commands(struct sock *sk)
273{
274 struct mgmt_rp_read_commands *rp;
275 u16 num_commands = ARRAY_SIZE(mgmt_commands);
276 u16 num_events = ARRAY_SIZE(mgmt_events);
277 u16 *opcode;
278 size_t rp_size;
279 int i, err;
280
281 BT_DBG("sock %p", sk);
282
283 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
284
285 rp = kmalloc(rp_size, GFP_KERNEL);
286 if (!rp)
287 return -ENOMEM;
288
289 put_unaligned_le16(num_commands, &rp->num_commands);
290 put_unaligned_le16(num_events, &rp->num_events);
291
292 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
293 put_unaligned_le16(mgmt_commands[i], opcode);
294
295 for (i = 0; i < num_events; i++, opcode++)
296 put_unaligned_le16(mgmt_events[i], opcode);
297
298 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, rp,
299 rp_size);
300 kfree(rp);
301
302 return err;
303}
304
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200305static int read_index_list(struct sock *sk)
306{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200307 struct mgmt_rp_read_index_list *rp;
308 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200309 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200310 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200312 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313
314 BT_DBG("sock %p", sk);
315
316 read_lock(&hci_dev_list_lock);
317
318 count = 0;
319 list_for_each(p, &hci_dev_list) {
320 count++;
321 }
322
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 rp_len = sizeof(*rp) + (2 * count);
324 rp = kmalloc(rp_len, GFP_ATOMIC);
325 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100326 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100328 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200329
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330 put_unaligned_le16(count, &rp->num_controllers);
331
332 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200333 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200334 if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200335 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200336
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200337 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200338 continue;
339
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340 put_unaligned_le16(d->id, &rp->index[i++]);
341 BT_DBG("Added hci%u", d->id);
342 }
343
344 read_unlock(&hci_dev_list_lock);
345
Szymon Janc4e51eae2011-02-25 19:05:48 +0100346 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
347 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348
Johan Hedberga38528f2011-01-22 06:46:43 +0200349 kfree(rp);
350
351 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352}
353
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200354static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200355{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200356 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200357
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200358 settings |= MGMT_SETTING_POWERED;
359 settings |= MGMT_SETTING_CONNECTABLE;
360 settings |= MGMT_SETTING_FAST_CONNECTABLE;
361 settings |= MGMT_SETTING_DISCOVERABLE;
362 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 if (hdev->features[6] & LMP_SIMPLE_PAIR)
365 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200366
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 if (!(hdev->features[4] & LMP_NO_BREDR)) {
368 settings |= MGMT_SETTING_BREDR;
369 settings |= MGMT_SETTING_LINK_SECURITY;
370 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[4] & LMP_LE)
373 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 return settings;
376}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378static u32 get_current_settings(struct hci_dev *hdev)
379{
380 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200381
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200382 if (test_bit(HCI_UP, &hdev->flags))
383 settings |= MGMT_SETTING_POWERED;
384 else
385 return settings;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200386
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200387 if (test_bit(HCI_PSCAN, &hdev->flags))
388 settings |= MGMT_SETTING_CONNECTABLE;
389
390 if (test_bit(HCI_ISCAN, &hdev->flags))
391 settings |= MGMT_SETTING_DISCOVERABLE;
392
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200393 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394 settings |= MGMT_SETTING_PAIRABLE;
395
396 if (!(hdev->features[4] & LMP_NO_BREDR))
397 settings |= MGMT_SETTING_BREDR;
398
Andre Guedes59e29402011-12-30 10:34:03 -0300399 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200400 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200401
402 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200404
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200405 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200407
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200409}
410
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300411#define PNP_INFO_SVCLASS_ID 0x1200
412
413static u8 bluetooth_base_uuid[] = {
414 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
415 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
416};
417
418static u16 get_uuid16(u8 *uuid128)
419{
420 u32 val;
421 int i;
422
423 for (i = 0; i < 12; i++) {
424 if (bluetooth_base_uuid[i] != uuid128[i])
425 return 0;
426 }
427
428 memcpy(&val, &uuid128[12], 4);
429
430 val = le32_to_cpu(val);
431 if (val > 0xffff)
432 return 0;
433
434 return (u16) val;
435}
436
437static void create_eir(struct hci_dev *hdev, u8 *data)
438{
439 u8 *ptr = data;
440 u16 eir_len = 0;
441 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
442 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200443 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300444 size_t name_len;
445
446 name_len = strlen(hdev->dev_name);
447
448 if (name_len > 0) {
449 /* EIR Data type */
450 if (name_len > 48) {
451 name_len = 48;
452 ptr[1] = EIR_NAME_SHORT;
453 } else
454 ptr[1] = EIR_NAME_COMPLETE;
455
456 /* EIR Data length */
457 ptr[0] = name_len + 1;
458
459 memcpy(ptr + 2, hdev->dev_name, name_len);
460
461 eir_len += (name_len + 2);
462 ptr += (name_len + 2);
463 }
464
465 memset(uuid16_list, 0, sizeof(uuid16_list));
466
467 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200468 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300469 u16 uuid16;
470
471 uuid16 = get_uuid16(uuid->uuid);
472 if (uuid16 == 0)
473 return;
474
475 if (uuid16 < 0x1100)
476 continue;
477
478 if (uuid16 == PNP_INFO_SVCLASS_ID)
479 continue;
480
481 /* Stop if not enough space to put next UUID */
482 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
483 truncated = 1;
484 break;
485 }
486
487 /* Check for duplicates */
488 for (i = 0; uuid16_list[i] != 0; i++)
489 if (uuid16_list[i] == uuid16)
490 break;
491
492 if (uuid16_list[i] == 0) {
493 uuid16_list[i] = uuid16;
494 eir_len += sizeof(u16);
495 }
496 }
497
498 if (uuid16_list[0] != 0) {
499 u8 *length = ptr;
500
501 /* EIR Data type */
502 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
503
504 ptr += 2;
505 eir_len += 2;
506
507 for (i = 0; uuid16_list[i] != 0; i++) {
508 *ptr++ = (uuid16_list[i] & 0x00ff);
509 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
510 }
511
512 /* EIR Data length */
513 *length = (i * sizeof(u16)) + 1;
514 }
515}
516
517static int update_eir(struct hci_dev *hdev)
518{
519 struct hci_cp_write_eir cp;
520
521 if (!(hdev->features[6] & LMP_EXT_INQ))
522 return 0;
523
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200524 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300525 return 0;
526
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200527 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300528 return 0;
529
530 memset(&cp, 0, sizeof(cp));
531
532 create_eir(hdev, cp.data);
533
534 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
535 return 0;
536
537 memcpy(hdev->eir, cp.data, sizeof(cp.data));
538
539 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
540}
541
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200542static u8 get_service_classes(struct hci_dev *hdev)
543{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300544 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200545 u8 val = 0;
546
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300547 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200548 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200549
550 return val;
551}
552
553static int update_class(struct hci_dev *hdev)
554{
555 u8 cod[3];
556
557 BT_DBG("%s", hdev->name);
558
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200559 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200560 return 0;
561
562 cod[0] = hdev->minor_class;
563 cod[1] = hdev->major_class;
564 cod[2] = get_service_classes(hdev);
565
566 if (memcmp(cod, hdev->dev_class, 3) == 0)
567 return 0;
568
569 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
570}
571
Johan Hedberg7d785252011-12-15 00:47:39 +0200572static void service_cache_off(struct work_struct *work)
573{
574 struct hci_dev *hdev = container_of(work, struct hci_dev,
575 service_cache.work);
576
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200577 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200578 return;
579
580 hci_dev_lock(hdev);
581
582 update_eir(hdev);
583 update_class(hdev);
584
585 hci_dev_unlock(hdev);
586}
587
588static void mgmt_init_hdev(struct hci_dev *hdev)
589{
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200590 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200591 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
592
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200593 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200594 schedule_delayed_work(&hdev->service_cache,
595 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
596}
597
Johan Hedberg03811012010-12-08 00:21:06 +0200598static int read_controller_info(struct sock *sk, u16 index)
599{
600 struct mgmt_rp_read_info rp;
601 struct hci_dev *hdev;
602
603 BT_DBG("sock %p hci%u", sk, index);
604
605 hdev = hci_dev_get(index);
606 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200607 return cmd_status(sk, index, MGMT_OP_READ_INFO,
608 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200609
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200610 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
Johan Hedberg03811012010-12-08 00:21:06 +0200611 cancel_delayed_work_sync(&hdev->power_off);
612
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300613 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200614
Johan Hedberg7d785252011-12-15 00:47:39 +0200615 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
616 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200617
618 memset(&rp, 0, sizeof(rp));
619
Johan Hedberg03811012010-12-08 00:21:06 +0200620 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200621
622 rp.version = hdev->hci_ver;
623
Johan Hedberg03811012010-12-08 00:21:06 +0200624 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200625
626 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
627 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
628
629 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200630
631 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
632
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300633 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200634 hci_dev_put(hdev);
635
636 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
637}
638
639static void mgmt_pending_free(struct pending_cmd *cmd)
640{
641 sock_put(cmd->sk);
642 kfree(cmd->param);
643 kfree(cmd);
644}
645
646static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
647 struct hci_dev *hdev,
648 void *data, u16 len)
649{
650 struct pending_cmd *cmd;
651
652 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
653 if (!cmd)
654 return NULL;
655
656 cmd->opcode = opcode;
657 cmd->index = hdev->id;
658
659 cmd->param = kmalloc(len, GFP_ATOMIC);
660 if (!cmd->param) {
661 kfree(cmd);
662 return NULL;
663 }
664
665 if (data)
666 memcpy(cmd->param, data, len);
667
668 cmd->sk = sk;
669 sock_hold(sk);
670
671 list_add(&cmd->list, &hdev->mgmt_pending);
672
673 return cmd;
674}
675
676static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
677 void (*cb)(struct pending_cmd *cmd, void *data),
678 void *data)
679{
680 struct list_head *p, *n;
681
682 list_for_each_safe(p, n, &hdev->mgmt_pending) {
683 struct pending_cmd *cmd;
684
685 cmd = list_entry(p, struct pending_cmd, list);
686
687 if (opcode > 0 && cmd->opcode != opcode)
688 continue;
689
690 cb(cmd, data);
691 }
692}
693
694static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
695{
696 struct pending_cmd *cmd;
697
698 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
699 if (cmd->opcode == opcode)
700 return cmd;
701 }
702
703 return NULL;
704}
705
706static void mgmt_pending_remove(struct pending_cmd *cmd)
707{
708 list_del(&cmd->list);
709 mgmt_pending_free(cmd);
710}
711
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200712static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200713{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200714 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200715
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200716 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200717}
718
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300719static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200720{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300721 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200722 struct hci_dev *hdev;
723 struct pending_cmd *cmd;
724 int err, up;
725
Johan Hedberg03811012010-12-08 00:21:06 +0200726 BT_DBG("request for hci%u", index);
727
728 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200729 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
730 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200731
732 hdev = hci_dev_get(index);
733 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200734 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
735 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200736
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300737 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200738
739 up = test_bit(HCI_UP, &hdev->flags);
740 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200741 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200742 goto failed;
743 }
744
745 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200746 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
747 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200748 goto failed;
749 }
750
751 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
752 if (!cmd) {
753 err = -ENOMEM;
754 goto failed;
755 }
756
757 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200758 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200759 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200760 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200761
762 err = 0;
763
764failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300765 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200766 hci_dev_put(hdev);
767 return err;
768}
769
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300770static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200771{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300772 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200773 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200774 struct pending_cmd *cmd;
775 u8 scan;
776 int err;
777
Johan Hedberg03811012010-12-08 00:21:06 +0200778 BT_DBG("request for hci%u", index);
779
780 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200781 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
782 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200783
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200784 hdev = hci_dev_get(index);
785 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200786 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
787 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200788
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300789 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200790
791 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200792 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
793 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200794 goto failed;
795 }
796
797 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
798 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200799 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
800 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200801 goto failed;
802 }
803
804 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
805 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200806 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200807 goto failed;
808 }
809
810 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
811 if (!cmd) {
812 err = -ENOMEM;
813 goto failed;
814 }
815
816 scan = SCAN_PAGE;
817
818 if (cp->val)
819 scan |= SCAN_INQUIRY;
820 else
821 cancel_delayed_work(&hdev->discov_off);
822
823 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
824 if (err < 0)
825 mgmt_pending_remove(cmd);
826
Johan Hedberg03811012010-12-08 00:21:06 +0200827 if (cp->val)
828 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
829
Johan Hedberge41d8b42010-12-13 21:07:03 +0200830failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300831 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200832 hci_dev_put(hdev);
833
834 return err;
835}
836
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300837static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200838{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300839 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200840 struct hci_dev *hdev;
841 struct pending_cmd *cmd;
842 u8 scan;
843 int err;
844
Johan Hedberge41d8b42010-12-13 21:07:03 +0200845 BT_DBG("request for hci%u", index);
846
Johan Hedberg03811012010-12-08 00:21:06 +0200847 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200848 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
849 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200850
851 hdev = hci_dev_get(index);
852 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200853 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
854 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200855
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300856 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200857
858 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200859 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
860 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200861 goto failed;
862 }
863
864 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
865 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200866 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
867 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200868 goto failed;
869 }
870
871 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200872 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200873 goto failed;
874 }
875
876 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
877 if (!cmd) {
878 err = -ENOMEM;
879 goto failed;
880 }
881
882 if (cp->val)
883 scan = SCAN_PAGE;
884 else
885 scan = 0;
886
887 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
888 if (err < 0)
889 mgmt_pending_remove(cmd);
890
891failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300892 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200893 hci_dev_put(hdev);
894
895 return err;
896}
897
898static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
899 u16 data_len, struct sock *skip_sk)
900{
901 struct sk_buff *skb;
902 struct mgmt_hdr *hdr;
903
904 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
905 if (!skb)
906 return -ENOMEM;
907
908 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
909
910 hdr = (void *) skb_put(skb, sizeof(*hdr));
911 hdr->opcode = cpu_to_le16(event);
912 if (hdev)
913 hdr->index = cpu_to_le16(hdev->id);
914 else
915 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
916 hdr->len = cpu_to_le16(data_len);
917
918 if (data)
919 memcpy(skb_put(skb, data_len), data, data_len);
920
921 hci_send_to_sock(NULL, skb, skip_sk);
922 kfree_skb(skb);
923
924 return 0;
925}
926
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300927static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200928{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300929 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200930 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200931 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200932 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200933
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200934 BT_DBG("request for hci%u", index);
935
936 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200937 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
938 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200939
940 hdev = hci_dev_get(index);
941 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200942 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
943 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200944
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300945 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200946
947 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200948 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200949 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200950 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200951
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200952 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200953 if (err < 0)
954 goto failed;
955
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200956 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200957
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200958 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200959
960failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300961 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200962 hci_dev_put(hdev);
963
964 return err;
965}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200966
Johan Hedberg33ef95e2012-02-16 23:56:27 +0200967static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
968{
969 struct mgmt_mode *cp = data;
970 struct pending_cmd *cmd;
971 struct hci_dev *hdev;
972 uint8_t val;
973 int err;
974
975 BT_DBG("request for hci%u", index);
976
977 if (len != sizeof(*cp))
978 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
979 MGMT_STATUS_INVALID_PARAMS);
980
981 hdev = hci_dev_get(index);
982 if (!hdev)
983 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
984 MGMT_STATUS_INVALID_PARAMS);
985
986 hci_dev_lock(hdev);
987
988 if (!test_bit(HCI_UP, &hdev->flags)) {
989 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
990 MGMT_STATUS_NOT_POWERED);
991 goto failed;
992 }
993
994 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
995 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
996 MGMT_STATUS_BUSY);
997 goto failed;
998 }
999
1000 val = !!cp->val;
1001
1002 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1003 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1004 goto failed;
1005 }
1006
1007 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1008 if (!cmd) {
1009 err = -ENOMEM;
1010 goto failed;
1011 }
1012
1013 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1014 if (err < 0) {
1015 mgmt_pending_remove(cmd);
1016 goto failed;
1017 }
1018
1019failed:
1020 hci_dev_unlock(hdev);
1021 hci_dev_put(hdev);
1022
1023 return err;
1024}
1025
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001026static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001027{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001028 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001029 struct hci_dev *hdev;
1030 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001031 int err;
1032
Szymon Janc4e51eae2011-02-25 19:05:48 +01001033 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001034
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001035 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001036 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1037 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001038
Szymon Janc4e51eae2011-02-25 19:05:48 +01001039 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001040 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001041 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1042 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001043
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001044 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001045
1046 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1047 if (!uuid) {
1048 err = -ENOMEM;
1049 goto failed;
1050 }
1051
1052 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001053 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001054
1055 list_add(&uuid->list, &hdev->uuids);
1056
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001057 err = update_class(hdev);
1058 if (err < 0)
1059 goto failed;
1060
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001061 err = update_eir(hdev);
1062 if (err < 0)
1063 goto failed;
1064
Szymon Janc4e51eae2011-02-25 19:05:48 +01001065 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001066
1067failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001068 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001069 hci_dev_put(hdev);
1070
1071 return err;
1072}
1073
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001074static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001075{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001076 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001077 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001078 struct hci_dev *hdev;
1079 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 +02001080 int err, found;
1081
Szymon Janc4e51eae2011-02-25 19:05:48 +01001082 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001083
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001084 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001085 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1086 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001087
Szymon Janc4e51eae2011-02-25 19:05:48 +01001088 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001089 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001090 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1091 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001092
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001093 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001094
1095 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1096 err = hci_uuids_clear(hdev);
1097 goto unlock;
1098 }
1099
1100 found = 0;
1101
1102 list_for_each_safe(p, n, &hdev->uuids) {
1103 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1104
1105 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1106 continue;
1107
1108 list_del(&match->list);
1109 found++;
1110 }
1111
1112 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001113 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1114 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001115 goto unlock;
1116 }
1117
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001118 err = update_class(hdev);
1119 if (err < 0)
1120 goto unlock;
1121
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001122 err = update_eir(hdev);
1123 if (err < 0)
1124 goto unlock;
1125
Szymon Janc4e51eae2011-02-25 19:05:48 +01001126 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001127
1128unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001129 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001130 hci_dev_put(hdev);
1131
1132 return err;
1133}
1134
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001135static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001136{
1137 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001138 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001139 int err;
1140
Szymon Janc4e51eae2011-02-25 19:05:48 +01001141 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001142
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001143 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001144 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1145 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001146
Szymon Janc4e51eae2011-02-25 19:05:48 +01001147 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001148 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001149 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1150 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001151
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001152 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001153
1154 hdev->major_class = cp->major;
1155 hdev->minor_class = cp->minor;
1156
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001157 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001158 hci_dev_unlock(hdev);
1159 cancel_delayed_work_sync(&hdev->service_cache);
1160 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001161 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001162 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001163
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001164 err = update_class(hdev);
1165
1166 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001167 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001168
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001169 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001170 hci_dev_put(hdev);
1171
1172 return err;
1173}
1174
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001175static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001176{
1177 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001178 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001179 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001180 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001181
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001182 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001183 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1184 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001185
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001186 key_count = get_unaligned_le16(&cp->key_count);
1187
Johan Hedberg86742e12011-11-07 23:13:38 +02001188 expected_len = sizeof(*cp) + key_count *
1189 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001190 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001191 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001192 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001193 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1194 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001195 }
1196
Szymon Janc4e51eae2011-02-25 19:05:48 +01001197 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001198 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001199 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1200 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001201
Szymon Janc4e51eae2011-02-25 19:05:48 +01001202 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001203 key_count);
1204
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001205 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001206
1207 hci_link_keys_clear(hdev);
1208
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001209 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001210
1211 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001212 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001213 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001214 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001215
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001216 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001217 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001218
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001219 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001220 key->pin_len);
1221 }
1222
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001223 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1224
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001225 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001226 hci_dev_put(hdev);
1227
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001228 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001229}
1230
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001231static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1232 u8 addr_type, struct sock *skip_sk)
1233{
1234 struct mgmt_ev_device_unpaired ev;
1235
1236 bacpy(&ev.addr.bdaddr, bdaddr);
1237 ev.addr.type = addr_type;
1238
1239 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1240 skip_sk);
1241}
1242
Johan Hedberg124f6e32012-02-09 13:50:12 +02001243static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001244{
1245 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001246 struct mgmt_cp_unpair_device *cp = data;
1247 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001248 struct hci_cp_disconnect dc;
1249 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001250 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001251 int err;
1252
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001253 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001254 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001255 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001256
Szymon Janc4e51eae2011-02-25 19:05:48 +01001257 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001258 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001259 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001260 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001261
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001262 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001263
Johan Hedberga8a1d192011-11-10 15:54:38 +02001264 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001265 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1266 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001267
Johan Hedberg124f6e32012-02-09 13:50:12 +02001268 if (cp->addr.type == MGMT_ADDR_BREDR)
1269 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1270 else
1271 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001272
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001273 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001274 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001275 goto unlock;
1276 }
1277
Johan Hedberga8a1d192011-11-10 15:54:38 +02001278 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02001279 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001280 sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001281 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001282 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001283 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001284
Johan Hedberg124f6e32012-02-09 13:50:12 +02001285 if (cp->addr.type == MGMT_ADDR_BREDR)
1286 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1287 &cp->addr.bdaddr);
1288 else
1289 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1290 &cp->addr.bdaddr);
1291
Johan Hedberga8a1d192011-11-10 15:54:38 +02001292 if (!conn) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02001293 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001294 sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001295 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001296 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001297 }
1298
Johan Hedberg124f6e32012-02-09 13:50:12 +02001299 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1300 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001301 if (!cmd) {
1302 err = -ENOMEM;
1303 goto unlock;
1304 }
1305
1306 put_unaligned_le16(conn->handle, &dc.handle);
1307 dc.reason = 0x13; /* Remote User Terminated Connection */
1308 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1309 if (err < 0)
1310 mgmt_pending_remove(cmd);
1311
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001312unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001313 if (err < 0)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001314 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001315 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001316 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001317 hci_dev_put(hdev);
1318
1319 return err;
1320}
1321
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001322static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001323{
1324 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001325 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001326 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001327 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001328 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001329 int err;
1330
1331 BT_DBG("");
1332
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001333 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001334 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1335 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001336
Szymon Janc4e51eae2011-02-25 19:05:48 +01001337 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001338 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001339 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1340 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001341
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001342 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001343
1344 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001345 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1346 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001347 goto failed;
1348 }
1349
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001350 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001351 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1352 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001353 goto failed;
1354 }
1355
Johan Hedberg88c3df12012-02-09 14:27:38 +02001356 if (cp->addr.type == MGMT_ADDR_BREDR)
1357 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1358 else
1359 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001360
Johan Hedberg8962ee72011-01-20 12:40:27 +02001361 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001362 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1363 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001364 goto failed;
1365 }
1366
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001367 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001368 if (!cmd) {
1369 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001370 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001371 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001372
1373 put_unaligned_le16(conn->handle, &dc.handle);
1374 dc.reason = 0x13; /* Remote User Terminated Connection */
1375
1376 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1377 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001378 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001379
1380failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001381 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001382 hci_dev_put(hdev);
1383
1384 return err;
1385}
1386
Johan Hedberg48264f02011-11-09 13:58:58 +02001387static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001388{
1389 switch (link_type) {
1390 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001391 switch (addr_type) {
1392 case ADDR_LE_DEV_PUBLIC:
1393 return MGMT_ADDR_LE_PUBLIC;
1394 case ADDR_LE_DEV_RANDOM:
1395 return MGMT_ADDR_LE_RANDOM;
1396 default:
1397 return MGMT_ADDR_INVALID;
1398 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001399 case ACL_LINK:
1400 return MGMT_ADDR_BREDR;
1401 default:
1402 return MGMT_ADDR_INVALID;
1403 }
1404}
1405
Szymon Janc8ce62842011-03-01 16:55:32 +01001406static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001407{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001408 struct mgmt_rp_get_connections *rp;
1409 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001410 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001411 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001412 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001413 int i, err;
1414
1415 BT_DBG("");
1416
Szymon Janc4e51eae2011-02-25 19:05:48 +01001417 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001418 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001419 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1420 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001421
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001422 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001423
1424 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001425 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1426 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1427 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001428 }
1429
Johan Hedberg4c659c32011-11-07 23:13:39 +02001430 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001431 rp = kmalloc(rp_len, GFP_ATOMIC);
1432 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001433 err = -ENOMEM;
1434 goto unlock;
1435 }
1436
Johan Hedberg2784eb42011-01-21 13:56:35 +02001437 put_unaligned_le16(count, &rp->conn_count);
1438
Johan Hedberg2784eb42011-01-21 13:56:35 +02001439 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001440 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001441 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1442 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001443 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001444 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001445 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1446 continue;
1447 i++;
1448 }
1449
1450 /* Recalculate length in case of filtered SCO connections, etc */
1451 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001452
Szymon Janc4e51eae2011-02-25 19:05:48 +01001453 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001454
1455unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001456 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001457 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001458 hci_dev_put(hdev);
1459 return err;
1460}
1461
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001462static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1463 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1464{
1465 struct pending_cmd *cmd;
1466 int err;
1467
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001468 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001469 sizeof(*cp));
1470 if (!cmd)
1471 return -ENOMEM;
1472
1473 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1474 &cp->bdaddr);
1475 if (err < 0)
1476 mgmt_pending_remove(cmd);
1477
1478 return err;
1479}
1480
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001481static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001482{
1483 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001484 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001485 struct mgmt_cp_pin_code_reply *cp = data;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001486 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001487 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001488 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001489 int err;
1490
1491 BT_DBG("");
1492
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001493 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001494 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1495 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001496
Szymon Janc4e51eae2011-02-25 19:05:48 +01001497 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001498 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001499 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1500 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001501
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001502 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001503
1504 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001505 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1506 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001507 goto failed;
1508 }
1509
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001510 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1511 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001512 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1513 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001514 goto failed;
1515 }
1516
1517 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1518 bacpy(&ncp.bdaddr, &cp->bdaddr);
1519
1520 BT_ERR("PIN code is not 16 bytes long");
1521
1522 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1523 if (err >= 0)
1524 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001525 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001526
1527 goto failed;
1528 }
1529
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001530 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1531 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001532 if (!cmd) {
1533 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001534 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001535 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001536
1537 bacpy(&reply.bdaddr, &cp->bdaddr);
1538 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001539 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001540
1541 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1542 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001543 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001544
1545failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001546 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001547 hci_dev_put(hdev);
1548
1549 return err;
1550}
1551
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001552static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001553{
1554 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001555 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001556 int err;
1557
1558 BT_DBG("");
1559
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001560 if (len != sizeof(*cp))
1561 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001562 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001563
Szymon Janc4e51eae2011-02-25 19:05:48 +01001564 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001565 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001566 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001567 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001568
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001569 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001570
1571 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001572 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001573 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001574 goto failed;
1575 }
1576
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001577 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001578
1579failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001580 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001581 hci_dev_put(hdev);
1582
1583 return err;
1584}
1585
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001586static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001587{
1588 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001589 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001590
1591 BT_DBG("");
1592
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001593 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001594 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1595 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001596
Szymon Janc4e51eae2011-02-25 19:05:48 +01001597 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001598 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001599 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1600 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001601
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001602 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001603
1604 hdev->io_capability = cp->io_capability;
1605
1606 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001607 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001608
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001609 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001610 hci_dev_put(hdev);
1611
Szymon Janc4e51eae2011-02-25 19:05:48 +01001612 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001613}
1614
Johan Hedberge9a416b2011-02-19 12:05:56 -03001615static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1616{
1617 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001618 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001619
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001620 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001621 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1622 continue;
1623
Johan Hedberge9a416b2011-02-19 12:05:56 -03001624 if (cmd->user_data != conn)
1625 continue;
1626
1627 return cmd;
1628 }
1629
1630 return NULL;
1631}
1632
1633static void pairing_complete(struct pending_cmd *cmd, u8 status)
1634{
1635 struct mgmt_rp_pair_device rp;
1636 struct hci_conn *conn = cmd->user_data;
1637
Johan Hedbergba4e5642011-11-11 00:07:34 +02001638 bacpy(&rp.addr.bdaddr, &conn->dst);
1639 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001640 rp.status = status;
1641
Szymon Janc4e51eae2011-02-25 19:05:48 +01001642 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001643
1644 /* So we don't get further callbacks for this connection */
1645 conn->connect_cfm_cb = NULL;
1646 conn->security_cfm_cb = NULL;
1647 conn->disconn_cfm_cb = NULL;
1648
1649 hci_conn_put(conn);
1650
Johan Hedberga664b5b2011-02-19 12:06:02 -03001651 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001652}
1653
1654static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1655{
1656 struct pending_cmd *cmd;
1657
1658 BT_DBG("status %u", status);
1659
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001660 cmd = find_pairing(conn);
1661 if (!cmd)
1662 BT_DBG("Unable to find a pending command");
1663 else
1664 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001665}
1666
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001667static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001668{
1669 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001670 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001671 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001672 struct pending_cmd *cmd;
1673 u8 sec_level, auth_type;
1674 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001675 int err;
1676
1677 BT_DBG("");
1678
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001679 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001680 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1681 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001682
Szymon Janc4e51eae2011-02-25 19:05:48 +01001683 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001684 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001685 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1686 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001687
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001688 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001689
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001690 sec_level = BT_SECURITY_MEDIUM;
1691 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001692 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001693 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001694 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001695
Johan Hedbergba4e5642011-11-11 00:07:34 +02001696 if (cp->addr.type == MGMT_ADDR_BREDR)
1697 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001698 auth_type);
1699 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001700 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001701 auth_type);
1702
Johan Hedberg1425acb2011-11-11 00:07:35 +02001703 memset(&rp, 0, sizeof(rp));
1704 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1705 rp.addr.type = cp->addr.type;
1706
Ville Tervo30e76272011-02-22 16:10:53 -03001707 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001708 rp.status = -PTR_ERR(conn);
1709 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1710 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001711 goto unlock;
1712 }
1713
1714 if (conn->connect_cfm_cb) {
1715 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001716 rp.status = EBUSY;
1717 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1718 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001719 goto unlock;
1720 }
1721
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001722 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001723 if (!cmd) {
1724 err = -ENOMEM;
1725 hci_conn_put(conn);
1726 goto unlock;
1727 }
1728
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001729 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001730 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001731 conn->connect_cfm_cb = pairing_complete_cb;
1732
Johan Hedberge9a416b2011-02-19 12:05:56 -03001733 conn->security_cfm_cb = pairing_complete_cb;
1734 conn->disconn_cfm_cb = pairing_complete_cb;
1735 conn->io_capability = cp->io_cap;
1736 cmd->user_data = conn;
1737
1738 if (conn->state == BT_CONNECTED &&
1739 hci_conn_security(conn, sec_level, auth_type))
1740 pairing_complete(cmd, 0);
1741
1742 err = 0;
1743
1744unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001745 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001746 hci_dev_put(hdev);
1747
1748 return err;
1749}
1750
Johan Hedberg28424702012-02-02 04:02:29 +02001751static int cancel_pair_device(struct sock *sk, u16 index,
1752 unsigned char *data, u16 len)
1753{
1754 struct mgmt_addr_info *addr = (void *) data;
1755 struct hci_dev *hdev;
1756 struct pending_cmd *cmd;
1757 struct hci_conn *conn;
1758 int err;
1759
1760 BT_DBG("");
1761
1762 if (len != sizeof(*addr))
1763 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1764 MGMT_STATUS_INVALID_PARAMS);
1765
1766 hdev = hci_dev_get(index);
1767 if (!hdev)
1768 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1769 MGMT_STATUS_INVALID_PARAMS);
1770
1771 hci_dev_lock(hdev);
1772
1773 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1774 if (!cmd) {
1775 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1776 MGMT_STATUS_INVALID_PARAMS);
1777 goto unlock;
1778 }
1779
1780 conn = cmd->user_data;
1781
1782 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1783 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1784 MGMT_STATUS_INVALID_PARAMS);
1785 goto unlock;
1786 }
1787
1788 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1789
1790 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr,
1791 sizeof(*addr));
1792unlock:
1793 hci_dev_unlock(hdev);
1794 hci_dev_put(hdev);
1795
1796 return err;
1797}
1798
Brian Gix0df4c182011-11-16 13:53:13 -08001799static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001800 u8 type, u16 mgmt_op, u16 hci_op,
1801 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001802{
Johan Hedberga5c29682011-02-19 12:05:57 -03001803 struct pending_cmd *cmd;
1804 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001805 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001806 int err;
1807
Szymon Janc4e51eae2011-02-25 19:05:48 +01001808 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001809 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001810 return cmd_status(sk, index, mgmt_op,
1811 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001812
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001813 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001814
Johan Hedberga5c29682011-02-19 12:05:57 -03001815 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001816 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1817 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001818 }
1819
Johan Hedberg272d90d2012-02-09 15:26:12 +02001820 if (type == MGMT_ADDR_BREDR)
1821 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1822 else
Brian Gix47c15e22011-11-16 13:53:14 -08001823 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001824
Johan Hedberg272d90d2012-02-09 15:26:12 +02001825 if (!conn) {
1826 err = cmd_status(sk, index, mgmt_op,
1827 MGMT_STATUS_NOT_CONNECTED);
1828 goto done;
1829 }
1830
1831 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001832 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001833 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001834
Brian Gix5fe57d92011-12-21 16:12:13 -08001835 if (!err)
1836 err = cmd_status(sk, index, mgmt_op,
1837 MGMT_STATUS_SUCCESS);
1838 else
1839 err = cmd_status(sk, index, mgmt_op,
1840 MGMT_STATUS_FAILED);
1841
Brian Gix47c15e22011-11-16 13:53:14 -08001842 goto done;
1843 }
1844
Brian Gix0df4c182011-11-16 13:53:13 -08001845 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001846 if (!cmd) {
1847 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001848 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001849 }
1850
Brian Gix0df4c182011-11-16 13:53:13 -08001851 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001852 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1853 struct hci_cp_user_passkey_reply cp;
1854
1855 bacpy(&cp.bdaddr, bdaddr);
1856 cp.passkey = passkey;
1857 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1858 } else
1859 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1860
Johan Hedberga664b5b2011-02-19 12:06:02 -03001861 if (err < 0)
1862 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001863
Brian Gix0df4c182011-11-16 13:53:13 -08001864done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001865 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001866 hci_dev_put(hdev);
1867
1868 return err;
1869}
1870
Brian Gix0df4c182011-11-16 13:53:13 -08001871static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1872{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001873 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001874
1875 BT_DBG("");
1876
1877 if (len != sizeof(*cp))
1878 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1879 MGMT_STATUS_INVALID_PARAMS);
1880
Johan Hedberg272d90d2012-02-09 15:26:12 +02001881 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1882 MGMT_OP_USER_CONFIRM_REPLY,
1883 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001884}
1885
1886static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1887 u16 len)
1888{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001889 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001890
1891 BT_DBG("");
1892
1893 if (len != sizeof(*cp))
1894 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1895 MGMT_STATUS_INVALID_PARAMS);
1896
Johan Hedberg272d90d2012-02-09 15:26:12 +02001897 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1898 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1899 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001900}
1901
Brian Gix604086b2011-11-23 08:28:33 -08001902static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1903{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001904 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001905
1906 BT_DBG("");
1907
1908 if (len != sizeof(*cp))
1909 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1910 EINVAL);
1911
Johan Hedberg272d90d2012-02-09 15:26:12 +02001912 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1913 MGMT_OP_USER_PASSKEY_REPLY,
1914 HCI_OP_USER_PASSKEY_REPLY,
1915 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08001916}
1917
1918static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1919 u16 len)
1920{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001921 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001922
1923 BT_DBG("");
1924
1925 if (len != sizeof(*cp))
1926 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1927 EINVAL);
1928
Johan Hedberg272d90d2012-02-09 15:26:12 +02001929 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1930 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1931 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08001932}
1933
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001934static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02001935 u16 len)
1936{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001937 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001938 struct hci_cp_write_local_name hci_cp;
1939 struct hci_dev *hdev;
1940 struct pending_cmd *cmd;
1941 int err;
1942
1943 BT_DBG("");
1944
1945 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001946 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1947 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001948
1949 hdev = hci_dev_get(index);
1950 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001951 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1952 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001953
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001954 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001955
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001956 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
1957 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001958 if (!cmd) {
1959 err = -ENOMEM;
1960 goto failed;
1961 }
1962
1963 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1964 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1965 &hci_cp);
1966 if (err < 0)
1967 mgmt_pending_remove(cmd);
1968
1969failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001970 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001971 hci_dev_put(hdev);
1972
1973 return err;
1974}
1975
Szymon Jancc35938b2011-03-22 13:12:21 +01001976static int read_local_oob_data(struct sock *sk, u16 index)
1977{
1978 struct hci_dev *hdev;
1979 struct pending_cmd *cmd;
1980 int err;
1981
1982 BT_DBG("hci%u", index);
1983
1984 hdev = hci_dev_get(index);
1985 if (!hdev)
1986 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001987 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001988
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001989 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001990
1991 if (!test_bit(HCI_UP, &hdev->flags)) {
1992 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001993 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001994 goto unlock;
1995 }
1996
1997 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1998 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001999 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002000 goto unlock;
2001 }
2002
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002003 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002004 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2005 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002006 goto unlock;
2007 }
2008
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002009 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002010 if (!cmd) {
2011 err = -ENOMEM;
2012 goto unlock;
2013 }
2014
2015 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2016 if (err < 0)
2017 mgmt_pending_remove(cmd);
2018
2019unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002020 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002021 hci_dev_put(hdev);
2022
2023 return err;
2024}
2025
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002026static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2027 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002028{
2029 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002030 struct mgmt_cp_add_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01002031 int err;
2032
2033 BT_DBG("hci%u ", index);
2034
2035 if (len != sizeof(*cp))
2036 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002037 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002038
2039 hdev = hci_dev_get(index);
2040 if (!hdev)
2041 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002042 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002043
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002044 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002045
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002046 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002047 cp->randomizer);
2048 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002049 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2050 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01002051 else
2052 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2053 0);
2054
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002055 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002056 hci_dev_put(hdev);
2057
2058 return err;
2059}
2060
2061static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002062 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002063{
2064 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002065 struct mgmt_cp_remove_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01002066 int err;
2067
2068 BT_DBG("hci%u ", index);
2069
2070 if (len != sizeof(*cp))
2071 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002072 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002073
2074 hdev = hci_dev_get(index);
2075 if (!hdev)
2076 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002077 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002078
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002079 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002080
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002081 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002082 if (err < 0)
2083 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002084 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002085 else
2086 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2087 NULL, 0);
2088
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002089 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002090 hci_dev_put(hdev);
2091
2092 return err;
2093}
2094
Johan Hedberg450dfda2011-11-12 11:58:22 +02002095static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002096 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002097{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002098 struct mgmt_cp_start_discovery *cp = data;
Andre Guedes3fd24152012-02-03 17:48:01 -03002099 unsigned long discov_type = cp->type;
Johan Hedberg14a53662011-04-27 10:29:56 -04002100 struct pending_cmd *cmd;
2101 struct hci_dev *hdev;
2102 int err;
2103
2104 BT_DBG("hci%u", index);
2105
Johan Hedberg450dfda2011-11-12 11:58:22 +02002106 if (len != sizeof(*cp))
2107 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2108 MGMT_STATUS_INVALID_PARAMS);
2109
Johan Hedberg14a53662011-04-27 10:29:56 -04002110 hdev = hci_dev_get(index);
2111 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002112 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2113 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002114
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002115 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002116
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002117 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002118 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2119 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002120 goto failed;
2121 }
2122
Johan Hedbergff9ef572012-01-04 14:23:45 +02002123 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2124 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2125 MGMT_STATUS_BUSY);
2126 goto failed;
2127 }
2128
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002129 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002130 if (!cmd) {
2131 err = -ENOMEM;
2132 goto failed;
2133 }
2134
Andre Guedes3fd24152012-02-03 17:48:01 -03002135 if (test_bit(MGMT_ADDR_BREDR, &discov_type))
2136 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2137 else if (test_bit(MGMT_ADDR_LE_PUBLIC, &discov_type) &&
2138 test_bit(MGMT_ADDR_LE_RANDOM, &discov_type))
2139 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2140 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
2141 else
2142 err = -EINVAL;
2143
Johan Hedberg14a53662011-04-27 10:29:56 -04002144 if (err < 0)
2145 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002146 else
2147 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002148
2149failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002150 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002151 hci_dev_put(hdev);
2152
2153 return err;
2154}
2155
2156static int stop_discovery(struct sock *sk, u16 index)
2157{
2158 struct hci_dev *hdev;
2159 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002160 struct hci_cp_remote_name_req_cancel cp;
2161 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002162 int err;
2163
2164 BT_DBG("hci%u", index);
2165
2166 hdev = hci_dev_get(index);
2167 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002168 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2169 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002170
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002171 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002172
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002173 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002174 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2175 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002176 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002177 }
2178
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002179 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002180 if (!cmd) {
2181 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002182 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002183 }
2184
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002185 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
2186 err = hci_cancel_inquiry(hdev);
2187 if (err < 0)
2188 mgmt_pending_remove(cmd);
2189 else
2190 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2191 goto unlock;
2192 }
2193
2194 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2195 if (!e) {
2196 mgmt_pending_remove(cmd);
2197 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2198 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2199 goto unlock;
2200 }
2201
2202 bacpy(&cp.bdaddr, &e->data.bdaddr);
2203 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2204 sizeof(cp), &cp);
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_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002209
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002210unlock:
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
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002217static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002218{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002219 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002220 struct inquiry_entry *e;
2221 struct hci_dev *hdev;
2222 int err;
2223
2224 BT_DBG("hci%u", index);
2225
2226 if (len != sizeof(*cp))
2227 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2228 MGMT_STATUS_INVALID_PARAMS);
2229
2230 hdev = hci_dev_get(index);
2231 if (!hdev)
2232 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2233 MGMT_STATUS_INVALID_PARAMS);
2234
2235 hci_dev_lock(hdev);
2236
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002237 if (!hci_discovery_active(hdev)) {
2238 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2239 MGMT_STATUS_FAILED);
2240 goto failed;
2241 }
2242
Johan Hedberg561aafb2012-01-04 13:31:59 +02002243 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr);
2244 if (!e) {
2245 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2246 MGMT_STATUS_INVALID_PARAMS);
2247 goto failed;
2248 }
2249
2250 if (cp->name_known) {
2251 e->name_state = NAME_KNOWN;
2252 list_del(&e->list);
2253 } else {
2254 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002255 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002256 }
2257
2258 err = 0;
2259
2260failed:
2261 hci_dev_unlock(hdev);
2262
2263 return err;
2264}
2265
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002266static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002267{
2268 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002269 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002270 int err;
2271
2272 BT_DBG("hci%u", index);
2273
Antti Julku7fbec222011-06-15 12:01:15 +03002274 if (len != sizeof(*cp))
2275 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002276 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002277
2278 hdev = hci_dev_get(index);
2279 if (!hdev)
2280 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002281 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002282
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002283 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002284
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002285 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002286 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002287 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2288 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002289 else
2290 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2291 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002292
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002293 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002294 hci_dev_put(hdev);
2295
2296 return err;
2297}
2298
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002299static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002300{
2301 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002302 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002303 int err;
2304
2305 BT_DBG("hci%u", index);
2306
Antti Julku7fbec222011-06-15 12:01:15 +03002307 if (len != sizeof(*cp))
2308 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002309 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002310
2311 hdev = hci_dev_get(index);
2312 if (!hdev)
2313 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002314 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002315
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002316 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002317
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002318 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002319
2320 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002321 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2322 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002323 else
2324 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2325 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002326
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002327 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002328 hci_dev_put(hdev);
2329
2330 return err;
2331}
2332
Antti Julkuf6422ec2011-06-22 13:11:56 +03002333static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002334 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002335{
2336 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002337 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002338 struct hci_cp_write_page_scan_activity acp;
2339 u8 type;
2340 int err;
2341
2342 BT_DBG("hci%u", index);
2343
2344 if (len != sizeof(*cp))
2345 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002346 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002347
2348 hdev = hci_dev_get(index);
2349 if (!hdev)
2350 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002351 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002352
2353 hci_dev_lock(hdev);
2354
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002355 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002356 type = PAGE_SCAN_TYPE_INTERLACED;
2357 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2358 } else {
2359 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2360 acp.interval = 0x0800; /* default 1.28 sec page scan */
2361 }
2362
2363 acp.window = 0x0012; /* default 11.25 msec page scan window */
2364
2365 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2366 sizeof(acp), &acp);
2367 if (err < 0) {
2368 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002369 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002370 goto done;
2371 }
2372
2373 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2374 if (err < 0) {
2375 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002376 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002377 goto done;
2378 }
2379
2380 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2381 NULL, 0);
2382done:
2383 hci_dev_unlock(hdev);
2384 hci_dev_put(hdev);
2385
2386 return err;
2387}
2388
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002389static int load_long_term_keys(struct sock *sk, u16 index,
2390 void *cp_data, u16 len)
2391{
2392 struct hci_dev *hdev;
2393 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2394 u16 key_count, expected_len;
2395 int i;
2396
2397 if (len < sizeof(*cp))
2398 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2399 EINVAL);
2400
2401 key_count = get_unaligned_le16(&cp->key_count);
2402
2403 expected_len = sizeof(*cp) + key_count *
2404 sizeof(struct mgmt_ltk_info);
2405 if (expected_len != len) {
2406 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2407 len, expected_len);
2408 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2409 EINVAL);
2410 }
2411
2412 hdev = hci_dev_get(index);
2413 if (!hdev)
2414 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2415 ENODEV);
2416
2417 BT_DBG("hci%u key_count %u", index, key_count);
2418
2419 hci_dev_lock(hdev);
2420
2421 hci_smp_ltks_clear(hdev);
2422
2423 for (i = 0; i < key_count; i++) {
2424 struct mgmt_ltk_info *key = &cp->keys[i];
2425 u8 type;
2426
2427 if (key->master)
2428 type = HCI_SMP_LTK;
2429 else
2430 type = HCI_SMP_LTK_SLAVE;
2431
2432 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2433 type, 0, key->authenticated, key->val,
2434 key->enc_size, key->ediv, key->rand);
2435 }
2436
2437 hci_dev_unlock(hdev);
2438 hci_dev_put(hdev);
2439
2440 return 0;
2441}
2442
Johan Hedberg03811012010-12-08 00:21:06 +02002443int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2444{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002445 void *buf;
2446 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002447 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002448 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002449 int err;
2450
2451 BT_DBG("got %zu bytes", msglen);
2452
2453 if (msglen < sizeof(*hdr))
2454 return -EINVAL;
2455
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002456 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002457 if (!buf)
2458 return -ENOMEM;
2459
2460 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2461 err = -EFAULT;
2462 goto done;
2463 }
2464
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002465 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002466 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002467 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002468 len = get_unaligned_le16(&hdr->len);
2469
2470 if (len != msglen - sizeof(*hdr)) {
2471 err = -EINVAL;
2472 goto done;
2473 }
2474
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002475 cp = buf + sizeof(*hdr);
2476
Johan Hedberg03811012010-12-08 00:21:06 +02002477 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002478 case MGMT_OP_READ_VERSION:
2479 err = read_version(sk);
2480 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002481 case MGMT_OP_READ_COMMANDS:
2482 err = read_commands(sk);
2483 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002484 case MGMT_OP_READ_INDEX_LIST:
2485 err = read_index_list(sk);
2486 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002487 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002488 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002489 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002490 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002491 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002492 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002493 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002494 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002495 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002496 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002497 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002498 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002499 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002500 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002501 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002502 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002503 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002504 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002505 case MGMT_OP_SET_LINK_SECURITY:
2506 err = set_link_security(sk, index, cp, len);
2507 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002508 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002509 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002510 break;
2511 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002512 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002513 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002514 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002515 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002516 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002517 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002518 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002519 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002520 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002521 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002522 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002523 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002524 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002525 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002526 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002527 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002528 break;
2529 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002530 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002531 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002532 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002533 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002534 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002535 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002536 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002537 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002538 case MGMT_OP_CANCEL_PAIR_DEVICE:
2539 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2540 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002541 case MGMT_OP_UNPAIR_DEVICE:
2542 err = unpair_device(sk, index, cp, len);
2543 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002544 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002545 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002546 break;
2547 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002548 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002549 break;
Brian Gix604086b2011-11-23 08:28:33 -08002550 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002551 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002552 break;
2553 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002554 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002555 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002556 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002557 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002558 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002559 case MGMT_OP_READ_LOCAL_OOB_DATA:
2560 err = read_local_oob_data(sk, index);
2561 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002562 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002563 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002564 break;
2565 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002566 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002567 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002568 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002569 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002570 break;
2571 case MGMT_OP_STOP_DISCOVERY:
2572 err = stop_discovery(sk, index);
2573 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002574 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002575 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002576 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002577 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002578 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002579 break;
2580 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002581 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002582 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002583 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2584 err = load_long_term_keys(sk, index, cp, len);
2585 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002586 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002587 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002588 err = cmd_status(sk, index, opcode,
2589 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002590 break;
2591 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002592
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002593 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002594 goto done;
2595
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002596 err = msglen;
2597
2598done:
2599 kfree(buf);
2600 return err;
2601}
2602
Johan Hedbergb24752f2011-11-03 14:40:33 +02002603static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2604{
2605 u8 *status = data;
2606
2607 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2608 mgmt_pending_remove(cmd);
2609}
2610
Johan Hedberg744cf192011-11-08 20:40:14 +02002611int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002612{
Johan Hedberg744cf192011-11-08 20:40:14 +02002613 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002614}
2615
Johan Hedberg744cf192011-11-08 20:40:14 +02002616int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002617{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002618 u8 status = ENODEV;
2619
Johan Hedberg744cf192011-11-08 20:40:14 +02002620 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002621
Johan Hedberg744cf192011-11-08 20:40:14 +02002622 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002623}
2624
2625struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002626 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002627 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002628};
2629
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002630static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002631{
Johan Hedberg03811012010-12-08 00:21:06 +02002632 struct cmd_lookup *match = data;
2633
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002634 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002635
2636 list_del(&cmd->list);
2637
2638 if (match->sk == NULL) {
2639 match->sk = cmd->sk;
2640 sock_hold(match->sk);
2641 }
2642
2643 mgmt_pending_free(cmd);
2644}
2645
Johan Hedberg744cf192011-11-08 20:40:14 +02002646int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002647{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002648 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002649 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002650 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002651
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002652 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002653
Johan Hedbergb24752f2011-11-03 14:40:33 +02002654 if (!powered) {
2655 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002656 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002657 }
2658
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002659 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002660
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002661 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002662 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002663
2664 if (match.sk)
2665 sock_put(match.sk);
2666
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002667 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002668}
2669
Johan Hedberg744cf192011-11-08 20:40:14 +02002670int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002671{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002672 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002673 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002674 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002675
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002676 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002677
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002678 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002679
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002680 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002681 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002682 if (match.sk)
2683 sock_put(match.sk);
2684
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002685 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002686}
2687
Johan Hedberg744cf192011-11-08 20:40:14 +02002688int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002689{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002690 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002691 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002692 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002693
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002694 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2695 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002696
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002697 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002698
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002699 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002700
2701 if (match.sk)
2702 sock_put(match.sk);
2703
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002704 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002705}
2706
Johan Hedberg744cf192011-11-08 20:40:14 +02002707int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002708{
Johan Hedbergca69b792011-11-11 18:10:00 +02002709 u8 mgmt_err = mgmt_status(status);
2710
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002711 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002712 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002713 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002714
2715 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002716 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002717 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002718
2719 return 0;
2720}
2721
Johan Hedberg744cf192011-11-08 20:40:14 +02002722int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2723 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002724{
Johan Hedberg86742e12011-11-07 23:13:38 +02002725 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002726
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002727 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002728
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002729 ev.store_hint = persistent;
2730 bacpy(&ev.key.bdaddr, &key->bdaddr);
2731 ev.key.type = key->type;
2732 memcpy(ev.key.val, key->val, 16);
2733 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002734
Johan Hedberg744cf192011-11-08 20:40:14 +02002735 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002736}
Johan Hedbergf7520542011-01-20 12:34:39 +02002737
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002738int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2739{
2740 struct mgmt_ev_new_long_term_key ev;
2741
2742 memset(&ev, 0, sizeof(ev));
2743
2744 ev.store_hint = persistent;
2745 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2746 ev.key.addr.type = key->bdaddr_type;
2747 ev.key.authenticated = key->authenticated;
2748 ev.key.enc_size = key->enc_size;
2749 ev.key.ediv = key->ediv;
2750
2751 if (key->type == HCI_SMP_LTK)
2752 ev.key.master = 1;
2753
2754 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2755 memcpy(ev.key.val, key->val, sizeof(key->val));
2756
2757 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2758 &ev, sizeof(ev), NULL);
2759}
2760
Johan Hedbergafc747a2012-01-15 18:11:07 +02002761int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002762 u8 addr_type, u8 *name, u8 name_len,
2763 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002764{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002765 char buf[512];
2766 struct mgmt_ev_device_connected *ev = (void *) buf;
2767 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002768
Johan Hedbergb644ba32012-01-17 21:48:47 +02002769 bacpy(&ev->addr.bdaddr, bdaddr);
2770 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002771
Johan Hedbergb644ba32012-01-17 21:48:47 +02002772 if (name_len > 0)
2773 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2774 name, name_len);
2775
2776 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2777 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2778 EIR_CLASS_OF_DEV, dev_class, 3);
2779
2780 put_unaligned_le16(eir_len, &ev->eir_len);
2781
2782 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2783 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002784}
2785
Johan Hedberg8962ee72011-01-20 12:40:27 +02002786static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2787{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002788 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002789 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002790 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002791
Johan Hedberg88c3df12012-02-09 14:27:38 +02002792 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2793 rp.addr.type = cp->addr.type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002794 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002795
Szymon Janc4e51eae2011-02-25 19:05:48 +01002796 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002797
2798 *sk = cmd->sk;
2799 sock_hold(*sk);
2800
Johan Hedberga664b5b2011-02-19 12:06:02 -03002801 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002802}
2803
Johan Hedberg124f6e32012-02-09 13:50:12 +02002804static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002805{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002806 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002807 struct mgmt_cp_unpair_device *cp = cmd->param;
2808 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002809
2810 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002811 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2812 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002813
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002814 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2815
2816 cmd_complete(cmd->sk, cmd->index, cmd->opcode, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002817
2818 mgmt_pending_remove(cmd);
2819}
2820
Johan Hedbergafc747a2012-01-15 18:11:07 +02002821int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2822 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002823{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002824 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002825 struct sock *sk = NULL;
2826 int err;
2827
Johan Hedberg744cf192011-11-08 20:40:14 +02002828 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002829
Johan Hedbergf7520542011-01-20 12:34:39 +02002830 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002831 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002832
Johan Hedbergafc747a2012-01-15 18:11:07 +02002833 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2834 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002835
2836 if (sk)
2837 sock_put(sk);
2838
Johan Hedberg124f6e32012-02-09 13:50:12 +02002839 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002840 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002841
Johan Hedberg8962ee72011-01-20 12:40:27 +02002842 return err;
2843}
2844
Johan Hedberg88c3df12012-02-09 14:27:38 +02002845int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
2846 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002847{
Johan Hedberg88c3df12012-02-09 14:27:38 +02002848 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002849 struct pending_cmd *cmd;
2850 int err;
2851
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002852 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002853 if (!cmd)
2854 return -ENOENT;
2855
Johan Hedberg88c3df12012-02-09 14:27:38 +02002856 bacpy(&rp.addr.bdaddr, bdaddr);
2857 rp.addr.type = link_to_mgmt(link_type, addr_type);
2858 rp.status = mgmt_status(status);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002859
Johan Hedberg88c3df12012-02-09 14:27:38 +02002860 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002861 &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002862
Johan Hedberga664b5b2011-02-19 12:06:02 -03002863 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002864
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002865 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
2866 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002867 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002868}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002869
Johan Hedberg48264f02011-11-09 13:58:58 +02002870int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2871 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002872{
2873 struct mgmt_ev_connect_failed ev;
2874
Johan Hedberg4c659c32011-11-07 23:13:39 +02002875 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002876 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002877 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002878
Johan Hedberg744cf192011-11-08 20:40:14 +02002879 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002880}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002881
Johan Hedberg744cf192011-11-08 20:40:14 +02002882int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002883{
2884 struct mgmt_ev_pin_code_request ev;
2885
Johan Hedberg980e1a52011-01-22 06:10:07 +02002886 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002887 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002888
Johan Hedberg744cf192011-11-08 20:40:14 +02002889 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002890 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002891}
2892
Johan Hedberg744cf192011-11-08 20:40:14 +02002893int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2894 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002895{
2896 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002897 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002898 int err;
2899
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002900 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002901 if (!cmd)
2902 return -ENOENT;
2903
Johan Hedbergac56fb12011-02-19 12:05:59 -03002904 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002905 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002906
Johan Hedberg744cf192011-11-08 20:40:14 +02002907 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002908 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002909
Johan Hedberga664b5b2011-02-19 12:06:02 -03002910 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002911
2912 return err;
2913}
2914
Johan Hedberg744cf192011-11-08 20:40:14 +02002915int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2916 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002917{
2918 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002919 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002920 int err;
2921
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002922 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002923 if (!cmd)
2924 return -ENOENT;
2925
Johan Hedbergac56fb12011-02-19 12:05:59 -03002926 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002927 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002928
Johan Hedberg744cf192011-11-08 20:40:14 +02002929 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002930 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002931
Johan Hedberga664b5b2011-02-19 12:06:02 -03002932 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002933
2934 return err;
2935}
Johan Hedberga5c29682011-02-19 12:05:57 -03002936
Johan Hedberg744cf192011-11-08 20:40:14 +02002937int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002938 u8 link_type, u8 addr_type, __le32 value,
2939 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002940{
2941 struct mgmt_ev_user_confirm_request ev;
2942
Johan Hedberg744cf192011-11-08 20:40:14 +02002943 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002944
Johan Hedberg272d90d2012-02-09 15:26:12 +02002945 bacpy(&ev.addr.bdaddr, bdaddr);
2946 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002947 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002948 put_unaligned_le32(value, &ev.value);
2949
Johan Hedberg744cf192011-11-08 20:40:14 +02002950 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002951 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002952}
2953
Johan Hedberg272d90d2012-02-09 15:26:12 +02002954int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2955 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08002956{
2957 struct mgmt_ev_user_passkey_request ev;
2958
2959 BT_DBG("%s", hdev->name);
2960
Johan Hedberg272d90d2012-02-09 15:26:12 +02002961 bacpy(&ev.addr.bdaddr, bdaddr);
2962 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08002963
2964 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2965 NULL);
2966}
2967
Brian Gix0df4c182011-11-16 13:53:13 -08002968static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002969 u8 link_type, u8 addr_type, u8 status,
2970 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002971{
2972 struct pending_cmd *cmd;
2973 struct mgmt_rp_user_confirm_reply rp;
2974 int err;
2975
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002976 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002977 if (!cmd)
2978 return -ENOENT;
2979
Johan Hedberg272d90d2012-02-09 15:26:12 +02002980 bacpy(&rp.addr.bdaddr, bdaddr);
2981 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002982 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002983 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002984
Johan Hedberga664b5b2011-02-19 12:06:02 -03002985 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002986
2987 return err;
2988}
2989
Johan Hedberg744cf192011-11-08 20:40:14 +02002990int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002991 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002992{
Johan Hedberg272d90d2012-02-09 15:26:12 +02002993 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
2994 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03002995}
2996
Johan Hedberg272d90d2012-02-09 15:26:12 +02002997int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2998 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002999{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003000 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3001 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003002}
Johan Hedberg2a611692011-02-19 12:06:00 -03003003
Brian Gix604086b2011-11-23 08:28:33 -08003004int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003005 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003006{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003007 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3008 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003009}
3010
Johan Hedberg272d90d2012-02-09 15:26:12 +02003011int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3012 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003013{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003014 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3015 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003016}
3017
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003018int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3019 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003020{
3021 struct mgmt_ev_auth_failed ev;
3022
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003023 bacpy(&ev.addr.bdaddr, bdaddr);
3024 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003025 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003026
Johan Hedberg744cf192011-11-08 20:40:14 +02003027 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003028}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003029
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003030int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3031{
3032 struct cmd_lookup match = { NULL, hdev };
3033 __le32 ev;
3034 int err;
3035
3036 if (status) {
3037 u8 mgmt_err = mgmt_status(status);
3038 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3039 cmd_status_rsp, &mgmt_err);
3040 return 0;
3041 }
3042
3043 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3044 &match);
3045
3046 ev = cpu_to_le32(get_current_settings(hdev));
3047 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3048
3049 if (match.sk)
3050 sock_put(match.sk);
3051
3052 return err;
3053}
3054
Johan Hedberg744cf192011-11-08 20:40:14 +02003055int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003056{
3057 struct pending_cmd *cmd;
3058 struct mgmt_cp_set_local_name ev;
3059 int err;
3060
3061 memset(&ev, 0, sizeof(ev));
3062 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3063
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003064 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003065 if (!cmd)
3066 goto send_event;
3067
3068 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003069 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003070 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003071 goto failed;
3072 }
3073
Johan Hedberg744cf192011-11-08 20:40:14 +02003074 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003075
Johan Hedberg744cf192011-11-08 20:40:14 +02003076 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003077 sizeof(ev));
3078 if (err < 0)
3079 goto failed;
3080
3081send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003082 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003083 cmd ? cmd->sk : NULL);
3084
3085failed:
3086 if (cmd)
3087 mgmt_pending_remove(cmd);
3088 return err;
3089}
Szymon Jancc35938b2011-03-22 13:12:21 +01003090
Johan Hedberg744cf192011-11-08 20:40:14 +02003091int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3092 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003093{
3094 struct pending_cmd *cmd;
3095 int err;
3096
Johan Hedberg744cf192011-11-08 20:40:14 +02003097 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003098
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003099 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003100 if (!cmd)
3101 return -ENOENT;
3102
3103 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003104 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003105 MGMT_OP_READ_LOCAL_OOB_DATA,
3106 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003107 } else {
3108 struct mgmt_rp_read_local_oob_data rp;
3109
3110 memcpy(rp.hash, hash, sizeof(rp.hash));
3111 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3112
Johan Hedberg744cf192011-11-08 20:40:14 +02003113 err = cmd_complete(cmd->sk, hdev->id,
3114 MGMT_OP_READ_LOCAL_OOB_DATA,
3115 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003116 }
3117
3118 mgmt_pending_remove(cmd);
3119
3120 return err;
3121}
Johan Hedberge17acd42011-03-30 23:57:16 +03003122
Johan Hedberg48264f02011-11-09 13:58:58 +02003123int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003124 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003125 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003126{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003127 char buf[512];
3128 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003129 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003130
Johan Hedberg1dc06092012-01-15 21:01:23 +02003131 /* Leave 5 bytes for a potential CoD field */
3132 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003133 return -EINVAL;
3134
Johan Hedberg1dc06092012-01-15 21:01:23 +02003135 memset(buf, 0, sizeof(buf));
3136
Johan Hedberge319d2e2012-01-15 19:51:59 +02003137 bacpy(&ev->addr.bdaddr, bdaddr);
3138 ev->addr.type = link_to_mgmt(link_type, addr_type);
3139 ev->rssi = rssi;
3140 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003141
Johan Hedberg1dc06092012-01-15 21:01:23 +02003142 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003143 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003144
Johan Hedberg1dc06092012-01-15 21:01:23 +02003145 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3146 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3147 dev_class, 3);
3148
3149 put_unaligned_le16(eir_len, &ev->eir_len);
3150
3151 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003152
Johan Hedberge319d2e2012-01-15 19:51:59 +02003153 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003154}
Johan Hedberga88a9652011-03-30 13:18:12 +03003155
Johan Hedbergb644ba32012-01-17 21:48:47 +02003156int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3157 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003158{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003159 struct mgmt_ev_device_found *ev;
3160 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3161 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003162
Johan Hedbergb644ba32012-01-17 21:48:47 +02003163 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003164
Johan Hedbergb644ba32012-01-17 21:48:47 +02003165 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003166
Johan Hedbergb644ba32012-01-17 21:48:47 +02003167 bacpy(&ev->addr.bdaddr, bdaddr);
3168 ev->addr.type = link_to_mgmt(link_type, addr_type);
3169 ev->rssi = rssi;
3170
3171 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3172 name_len);
3173
3174 put_unaligned_le16(eir_len, &ev->eir_len);
3175
Johan Hedberg053c7e02012-02-04 00:06:00 +02003176 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3177 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003178}
Johan Hedberg314b2382011-04-27 10:29:57 -04003179
Andre Guedes7a135102011-11-09 17:14:25 -03003180int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003181{
3182 struct pending_cmd *cmd;
3183 int err;
3184
Andre Guedes203159d2012-02-13 15:41:01 -03003185 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3186
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003187 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003188 if (!cmd)
3189 return -ENOENT;
3190
Johan Hedbergca69b792011-11-11 18:10:00 +02003191 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003192 mgmt_pending_remove(cmd);
3193
3194 return err;
3195}
3196
Andre Guedese6d465c2011-11-09 17:14:26 -03003197int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3198{
3199 struct pending_cmd *cmd;
3200 int err;
3201
3202 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3203 if (!cmd)
3204 return -ENOENT;
3205
Andre Guedese75a8b0c2012-01-02 16:50:53 -03003206 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02003207 mgmt_pending_remove(cmd);
3208
3209 return err;
3210}
Johan Hedberg314b2382011-04-27 10:29:57 -04003211
Johan Hedberg744cf192011-11-08 20:40:14 +02003212int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003213{
Johan Hedberg164a6e72011-11-01 17:06:44 +02003214 struct pending_cmd *cmd;
3215
Andre Guedes343fb142011-11-22 17:14:19 -03003216 BT_DBG("%s discovering %u", hdev->name, discovering);
3217
Johan Hedberg164a6e72011-11-01 17:06:44 +02003218 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003219 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003220 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003221 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003222
3223 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003224 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003225 mgmt_pending_remove(cmd);
3226 }
3227
Johan Hedberg744cf192011-11-08 20:40:14 +02003228 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04003229 sizeof(discovering), NULL);
3230}
Antti Julku5e762442011-08-25 16:48:02 +03003231
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003232int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003233{
3234 struct pending_cmd *cmd;
3235 struct mgmt_ev_device_blocked ev;
3236
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003237 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003238
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003239 bacpy(&ev.addr.bdaddr, bdaddr);
3240 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003241
Johan Hedberg744cf192011-11-08 20:40:14 +02003242 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3243 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003244}
3245
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003246int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003247{
3248 struct pending_cmd *cmd;
3249 struct mgmt_ev_device_unblocked ev;
3250
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003251 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003252
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003253 bacpy(&ev.addr.bdaddr, bdaddr);
3254 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003255
Johan Hedberg744cf192011-11-08 20:40:14 +02003256 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3257 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003258}