blob: d5dbe402bc03430d769172f8b39138166192ef91 [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 Hedberg84bde9d6c2012-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 Hedberg84bde9d6c2012-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
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300967static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200968{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300969 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200970 struct hci_dev *hdev;
971 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200972 int err;
973
Szymon Janc4e51eae2011-02-25 19:05:48 +0100974 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200975
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100976 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200977 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
978 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100979
Szymon Janc4e51eae2011-02-25 19:05:48 +0100980 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200981 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200982 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
983 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200984
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300985 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200986
987 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
988 if (!uuid) {
989 err = -ENOMEM;
990 goto failed;
991 }
992
993 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200994 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200995
996 list_add(&uuid->list, &hdev->uuids);
997
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200998 err = update_class(hdev);
999 if (err < 0)
1000 goto failed;
1001
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001002 err = update_eir(hdev);
1003 if (err < 0)
1004 goto failed;
1005
Szymon Janc4e51eae2011-02-25 19:05:48 +01001006 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001007
1008failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001009 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001010 hci_dev_put(hdev);
1011
1012 return err;
1013}
1014
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001015static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001016{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001017 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001018 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001019 struct hci_dev *hdev;
1020 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 +02001021 int err, found;
1022
Szymon Janc4e51eae2011-02-25 19:05:48 +01001023 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001024
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001025 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001026 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1027 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001028
Szymon Janc4e51eae2011-02-25 19:05:48 +01001029 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001030 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001031 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1032 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001033
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001034 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001035
1036 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1037 err = hci_uuids_clear(hdev);
1038 goto unlock;
1039 }
1040
1041 found = 0;
1042
1043 list_for_each_safe(p, n, &hdev->uuids) {
1044 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1045
1046 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1047 continue;
1048
1049 list_del(&match->list);
1050 found++;
1051 }
1052
1053 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001054 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1055 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001056 goto unlock;
1057 }
1058
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001059 err = update_class(hdev);
1060 if (err < 0)
1061 goto unlock;
1062
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001063 err = update_eir(hdev);
1064 if (err < 0)
1065 goto unlock;
1066
Szymon Janc4e51eae2011-02-25 19:05:48 +01001067 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001068
1069unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001070 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001071 hci_dev_put(hdev);
1072
1073 return err;
1074}
1075
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001076static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001077{
1078 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001079 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001080 int err;
1081
Szymon Janc4e51eae2011-02-25 19:05:48 +01001082 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +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_SET_DEV_CLASS,
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 Hedberg1aff6f02011-01-13 21:56:52 +02001089 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001090 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1091 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001092
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001093 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001094
1095 hdev->major_class = cp->major;
1096 hdev->minor_class = cp->minor;
1097
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001098 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001099 hci_dev_unlock(hdev);
1100 cancel_delayed_work_sync(&hdev->service_cache);
1101 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001102 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001103 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001104
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001105 err = update_class(hdev);
1106
1107 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001108 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001109
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001110 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001111 hci_dev_put(hdev);
1112
1113 return err;
1114}
1115
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001116static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001117{
1118 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001119 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001120 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001121 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001122
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001123 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001124 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1125 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001126
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001127 key_count = get_unaligned_le16(&cp->key_count);
1128
Johan Hedberg86742e12011-11-07 23:13:38 +02001129 expected_len = sizeof(*cp) + key_count *
1130 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001131 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001132 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001133 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001134 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1135 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001136 }
1137
Szymon Janc4e51eae2011-02-25 19:05:48 +01001138 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001139 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001140 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1141 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001142
Szymon Janc4e51eae2011-02-25 19:05:48 +01001143 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001144 key_count);
1145
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001146 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001147
1148 hci_link_keys_clear(hdev);
1149
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001150 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001151
1152 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001153 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001154 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001155 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001156
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001157 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001158 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001159
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001160 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001161 key->pin_len);
1162 }
1163
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001164 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1165
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001166 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001167 hci_dev_put(hdev);
1168
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001169 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001170}
1171
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001172static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1173 u8 addr_type, struct sock *skip_sk)
1174{
1175 struct mgmt_ev_device_unpaired ev;
1176
1177 bacpy(&ev.addr.bdaddr, bdaddr);
1178 ev.addr.type = addr_type;
1179
1180 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1181 skip_sk);
1182}
1183
Johan Hedberg124f6e32012-02-09 13:50:12 +02001184static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001185{
1186 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001187 struct mgmt_cp_unpair_device *cp = data;
1188 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001189 struct hci_cp_disconnect dc;
1190 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001191 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001192 int err;
1193
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001194 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001195 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001196 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001197
Szymon Janc4e51eae2011-02-25 19:05:48 +01001198 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001199 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001200 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001201 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001202
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001203 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001204
Johan Hedberga8a1d192011-11-10 15:54:38 +02001205 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001206 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1207 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001208
Johan Hedberg124f6e32012-02-09 13:50:12 +02001209 if (cp->addr.type == MGMT_ADDR_BREDR)
1210 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1211 else
1212 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001213
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001214 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001215 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001216 goto unlock;
1217 }
1218
Johan Hedberga8a1d192011-11-10 15:54:38 +02001219 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02001220 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001221 sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001222 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001223 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001224 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001225
Johan Hedberg124f6e32012-02-09 13:50:12 +02001226 if (cp->addr.type == MGMT_ADDR_BREDR)
1227 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1228 &cp->addr.bdaddr);
1229 else
1230 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1231 &cp->addr.bdaddr);
1232
Johan Hedberga8a1d192011-11-10 15:54:38 +02001233 if (!conn) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02001234 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001235 sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001236 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001237 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001238 }
1239
Johan Hedberg124f6e32012-02-09 13:50:12 +02001240 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1241 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001242 if (!cmd) {
1243 err = -ENOMEM;
1244 goto unlock;
1245 }
1246
1247 put_unaligned_le16(conn->handle, &dc.handle);
1248 dc.reason = 0x13; /* Remote User Terminated Connection */
1249 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1250 if (err < 0)
1251 mgmt_pending_remove(cmd);
1252
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001253unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001254 if (err < 0)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001255 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001256 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001257 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001258 hci_dev_put(hdev);
1259
1260 return err;
1261}
1262
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001263static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001264{
1265 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001266 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001267 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001268 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001269 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001270 int err;
1271
1272 BT_DBG("");
1273
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001274 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001275 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1276 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001277
Szymon Janc4e51eae2011-02-25 19:05:48 +01001278 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001279 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001280 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1281 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001282
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001283 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001284
1285 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001286 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1287 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001288 goto failed;
1289 }
1290
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001291 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001292 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1293 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001294 goto failed;
1295 }
1296
Johan Hedberg88c3df12012-02-09 14:27:38 +02001297 if (cp->addr.type == MGMT_ADDR_BREDR)
1298 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1299 else
1300 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001301
Johan Hedberg8962ee72011-01-20 12:40:27 +02001302 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001303 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1304 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001305 goto failed;
1306 }
1307
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001308 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001309 if (!cmd) {
1310 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001311 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001312 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001313
1314 put_unaligned_le16(conn->handle, &dc.handle);
1315 dc.reason = 0x13; /* Remote User Terminated Connection */
1316
1317 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1318 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001319 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001320
1321failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001322 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001323 hci_dev_put(hdev);
1324
1325 return err;
1326}
1327
Johan Hedberg48264f02011-11-09 13:58:58 +02001328static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001329{
1330 switch (link_type) {
1331 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001332 switch (addr_type) {
1333 case ADDR_LE_DEV_PUBLIC:
1334 return MGMT_ADDR_LE_PUBLIC;
1335 case ADDR_LE_DEV_RANDOM:
1336 return MGMT_ADDR_LE_RANDOM;
1337 default:
1338 return MGMT_ADDR_INVALID;
1339 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001340 case ACL_LINK:
1341 return MGMT_ADDR_BREDR;
1342 default:
1343 return MGMT_ADDR_INVALID;
1344 }
1345}
1346
Szymon Janc8ce62842011-03-01 16:55:32 +01001347static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001348{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001349 struct mgmt_rp_get_connections *rp;
1350 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001351 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001352 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001353 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001354 int i, err;
1355
1356 BT_DBG("");
1357
Szymon Janc4e51eae2011-02-25 19:05:48 +01001358 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001359 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001360 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1361 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001362
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001363 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001364
1365 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001366 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1367 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1368 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001369 }
1370
Johan Hedberg4c659c32011-11-07 23:13:39 +02001371 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001372 rp = kmalloc(rp_len, GFP_ATOMIC);
1373 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001374 err = -ENOMEM;
1375 goto unlock;
1376 }
1377
Johan Hedberg2784eb42011-01-21 13:56:35 +02001378 put_unaligned_le16(count, &rp->conn_count);
1379
Johan Hedberg2784eb42011-01-21 13:56:35 +02001380 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001381 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001382 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1383 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001384 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001385 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001386 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1387 continue;
1388 i++;
1389 }
1390
1391 /* Recalculate length in case of filtered SCO connections, etc */
1392 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001393
Szymon Janc4e51eae2011-02-25 19:05:48 +01001394 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001395
1396unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001397 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001398 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001399 hci_dev_put(hdev);
1400 return err;
1401}
1402
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001403static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1404 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1405{
1406 struct pending_cmd *cmd;
1407 int err;
1408
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001409 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001410 sizeof(*cp));
1411 if (!cmd)
1412 return -ENOMEM;
1413
1414 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1415 &cp->bdaddr);
1416 if (err < 0)
1417 mgmt_pending_remove(cmd);
1418
1419 return err;
1420}
1421
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001422static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001423{
1424 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001425 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001426 struct mgmt_cp_pin_code_reply *cp = data;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001427 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001428 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001429 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001430 int err;
1431
1432 BT_DBG("");
1433
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001434 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001435 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1436 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001437
Szymon Janc4e51eae2011-02-25 19:05:48 +01001438 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001439 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001440 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1441 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001442
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001443 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001444
1445 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001446 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1447 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001448 goto failed;
1449 }
1450
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001451 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1452 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001453 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1454 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001455 goto failed;
1456 }
1457
1458 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1459 bacpy(&ncp.bdaddr, &cp->bdaddr);
1460
1461 BT_ERR("PIN code is not 16 bytes long");
1462
1463 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1464 if (err >= 0)
1465 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001466 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001467
1468 goto failed;
1469 }
1470
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001471 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1472 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001473 if (!cmd) {
1474 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001475 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001476 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001477
1478 bacpy(&reply.bdaddr, &cp->bdaddr);
1479 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001480 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001481
1482 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1483 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001484 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001485
1486failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001487 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001488 hci_dev_put(hdev);
1489
1490 return err;
1491}
1492
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001493static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001494{
1495 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001496 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001497 int err;
1498
1499 BT_DBG("");
1500
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001501 if (len != sizeof(*cp))
1502 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001503 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001504
Szymon Janc4e51eae2011-02-25 19:05:48 +01001505 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001506 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001507 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001508 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001509
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001510 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001511
1512 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001513 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001514 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001515 goto failed;
1516 }
1517
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001518 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001519
1520failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001521 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001522 hci_dev_put(hdev);
1523
1524 return err;
1525}
1526
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001527static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001528{
1529 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001530 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001531
1532 BT_DBG("");
1533
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001534 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001535 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1536 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001537
Szymon Janc4e51eae2011-02-25 19:05:48 +01001538 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001539 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001540 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1541 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001542
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001543 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001544
1545 hdev->io_capability = cp->io_capability;
1546
1547 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001548 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001549
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001550 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001551 hci_dev_put(hdev);
1552
Szymon Janc4e51eae2011-02-25 19:05:48 +01001553 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001554}
1555
Johan Hedberge9a416b2011-02-19 12:05:56 -03001556static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1557{
1558 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001559 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001560
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001561 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001562 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1563 continue;
1564
Johan Hedberge9a416b2011-02-19 12:05:56 -03001565 if (cmd->user_data != conn)
1566 continue;
1567
1568 return cmd;
1569 }
1570
1571 return NULL;
1572}
1573
1574static void pairing_complete(struct pending_cmd *cmd, u8 status)
1575{
1576 struct mgmt_rp_pair_device rp;
1577 struct hci_conn *conn = cmd->user_data;
1578
Johan Hedbergba4e5642011-11-11 00:07:34 +02001579 bacpy(&rp.addr.bdaddr, &conn->dst);
1580 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001581 rp.status = status;
1582
Szymon Janc4e51eae2011-02-25 19:05:48 +01001583 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001584
1585 /* So we don't get further callbacks for this connection */
1586 conn->connect_cfm_cb = NULL;
1587 conn->security_cfm_cb = NULL;
1588 conn->disconn_cfm_cb = NULL;
1589
1590 hci_conn_put(conn);
1591
Johan Hedberga664b5b2011-02-19 12:06:02 -03001592 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001593}
1594
1595static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1596{
1597 struct pending_cmd *cmd;
1598
1599 BT_DBG("status %u", status);
1600
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001601 cmd = find_pairing(conn);
1602 if (!cmd)
1603 BT_DBG("Unable to find a pending command");
1604 else
1605 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001606}
1607
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001608static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001609{
1610 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001611 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001612 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001613 struct pending_cmd *cmd;
1614 u8 sec_level, auth_type;
1615 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001616 int err;
1617
1618 BT_DBG("");
1619
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001620 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001621 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1622 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001623
Szymon Janc4e51eae2011-02-25 19:05:48 +01001624 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001625 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001626 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1627 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001628
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001629 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001630
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001631 sec_level = BT_SECURITY_MEDIUM;
1632 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001633 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001634 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001635 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001636
Johan Hedbergba4e5642011-11-11 00:07:34 +02001637 if (cp->addr.type == MGMT_ADDR_BREDR)
1638 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001639 auth_type);
1640 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001641 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001642 auth_type);
1643
Johan Hedberg1425acb2011-11-11 00:07:35 +02001644 memset(&rp, 0, sizeof(rp));
1645 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1646 rp.addr.type = cp->addr.type;
1647
Ville Tervo30e76272011-02-22 16:10:53 -03001648 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001649 rp.status = -PTR_ERR(conn);
1650 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1651 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001652 goto unlock;
1653 }
1654
1655 if (conn->connect_cfm_cb) {
1656 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001657 rp.status = EBUSY;
1658 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1659 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001660 goto unlock;
1661 }
1662
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001663 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001664 if (!cmd) {
1665 err = -ENOMEM;
1666 hci_conn_put(conn);
1667 goto unlock;
1668 }
1669
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001670 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001671 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001672 conn->connect_cfm_cb = pairing_complete_cb;
1673
Johan Hedberge9a416b2011-02-19 12:05:56 -03001674 conn->security_cfm_cb = pairing_complete_cb;
1675 conn->disconn_cfm_cb = pairing_complete_cb;
1676 conn->io_capability = cp->io_cap;
1677 cmd->user_data = conn;
1678
1679 if (conn->state == BT_CONNECTED &&
1680 hci_conn_security(conn, sec_level, auth_type))
1681 pairing_complete(cmd, 0);
1682
1683 err = 0;
1684
1685unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001686 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001687 hci_dev_put(hdev);
1688
1689 return err;
1690}
1691
Johan Hedberg28424702012-02-02 04:02:29 +02001692static int cancel_pair_device(struct sock *sk, u16 index,
1693 unsigned char *data, u16 len)
1694{
1695 struct mgmt_addr_info *addr = (void *) data;
1696 struct hci_dev *hdev;
1697 struct pending_cmd *cmd;
1698 struct hci_conn *conn;
1699 int err;
1700
1701 BT_DBG("");
1702
1703 if (len != sizeof(*addr))
1704 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1705 MGMT_STATUS_INVALID_PARAMS);
1706
1707 hdev = hci_dev_get(index);
1708 if (!hdev)
1709 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1710 MGMT_STATUS_INVALID_PARAMS);
1711
1712 hci_dev_lock(hdev);
1713
1714 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1715 if (!cmd) {
1716 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1717 MGMT_STATUS_INVALID_PARAMS);
1718 goto unlock;
1719 }
1720
1721 conn = cmd->user_data;
1722
1723 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1724 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1725 MGMT_STATUS_INVALID_PARAMS);
1726 goto unlock;
1727 }
1728
1729 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1730
1731 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr,
1732 sizeof(*addr));
1733unlock:
1734 hci_dev_unlock(hdev);
1735 hci_dev_put(hdev);
1736
1737 return err;
1738}
1739
Brian Gix0df4c182011-11-16 13:53:13 -08001740static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001741 u8 type, u16 mgmt_op, u16 hci_op,
1742 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001743{
Johan Hedberga5c29682011-02-19 12:05:57 -03001744 struct pending_cmd *cmd;
1745 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001746 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001747 int err;
1748
Szymon Janc4e51eae2011-02-25 19:05:48 +01001749 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001750 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001751 return cmd_status(sk, index, mgmt_op,
1752 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001753
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001754 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001755
Johan Hedberga5c29682011-02-19 12:05:57 -03001756 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001757 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1758 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001759 }
1760
Johan Hedberg272d90d2012-02-09 15:26:12 +02001761 if (type == MGMT_ADDR_BREDR)
1762 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1763 else
Brian Gix47c15e22011-11-16 13:53:14 -08001764 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001765
Johan Hedberg272d90d2012-02-09 15:26:12 +02001766 if (!conn) {
1767 err = cmd_status(sk, index, mgmt_op,
1768 MGMT_STATUS_NOT_CONNECTED);
1769 goto done;
1770 }
1771
1772 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001773 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001774 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001775
Brian Gix5fe57d92011-12-21 16:12:13 -08001776 if (!err)
1777 err = cmd_status(sk, index, mgmt_op,
1778 MGMT_STATUS_SUCCESS);
1779 else
1780 err = cmd_status(sk, index, mgmt_op,
1781 MGMT_STATUS_FAILED);
1782
Brian Gix47c15e22011-11-16 13:53:14 -08001783 goto done;
1784 }
1785
Brian Gix0df4c182011-11-16 13:53:13 -08001786 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001787 if (!cmd) {
1788 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001789 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001790 }
1791
Brian Gix0df4c182011-11-16 13:53:13 -08001792 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001793 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1794 struct hci_cp_user_passkey_reply cp;
1795
1796 bacpy(&cp.bdaddr, bdaddr);
1797 cp.passkey = passkey;
1798 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1799 } else
1800 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1801
Johan Hedberga664b5b2011-02-19 12:06:02 -03001802 if (err < 0)
1803 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001804
Brian Gix0df4c182011-11-16 13:53:13 -08001805done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001806 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001807 hci_dev_put(hdev);
1808
1809 return err;
1810}
1811
Brian Gix0df4c182011-11-16 13:53:13 -08001812static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1813{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001814 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001815
1816 BT_DBG("");
1817
1818 if (len != sizeof(*cp))
1819 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1820 MGMT_STATUS_INVALID_PARAMS);
1821
Johan Hedberg272d90d2012-02-09 15:26:12 +02001822 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1823 MGMT_OP_USER_CONFIRM_REPLY,
1824 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001825}
1826
1827static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1828 u16 len)
1829{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001830 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001831
1832 BT_DBG("");
1833
1834 if (len != sizeof(*cp))
1835 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1836 MGMT_STATUS_INVALID_PARAMS);
1837
Johan Hedberg272d90d2012-02-09 15:26:12 +02001838 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1839 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1840 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001841}
1842
Brian Gix604086b2011-11-23 08:28:33 -08001843static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1844{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001845 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001846
1847 BT_DBG("");
1848
1849 if (len != sizeof(*cp))
1850 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1851 EINVAL);
1852
Johan Hedberg272d90d2012-02-09 15:26:12 +02001853 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1854 MGMT_OP_USER_PASSKEY_REPLY,
1855 HCI_OP_USER_PASSKEY_REPLY,
1856 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08001857}
1858
1859static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1860 u16 len)
1861{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001862 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001863
1864 BT_DBG("");
1865
1866 if (len != sizeof(*cp))
1867 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1868 EINVAL);
1869
Johan Hedberg272d90d2012-02-09 15:26:12 +02001870 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1871 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1872 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08001873}
1874
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001875static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02001876 u16 len)
1877{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001878 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001879 struct hci_cp_write_local_name hci_cp;
1880 struct hci_dev *hdev;
1881 struct pending_cmd *cmd;
1882 int err;
1883
1884 BT_DBG("");
1885
1886 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001887 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1888 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001889
1890 hdev = hci_dev_get(index);
1891 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001892 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1893 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001894
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001895 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001896
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001897 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
1898 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001899 if (!cmd) {
1900 err = -ENOMEM;
1901 goto failed;
1902 }
1903
1904 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1905 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1906 &hci_cp);
1907 if (err < 0)
1908 mgmt_pending_remove(cmd);
1909
1910failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001911 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001912 hci_dev_put(hdev);
1913
1914 return err;
1915}
1916
Szymon Jancc35938b2011-03-22 13:12:21 +01001917static int read_local_oob_data(struct sock *sk, u16 index)
1918{
1919 struct hci_dev *hdev;
1920 struct pending_cmd *cmd;
1921 int err;
1922
1923 BT_DBG("hci%u", index);
1924
1925 hdev = hci_dev_get(index);
1926 if (!hdev)
1927 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001928 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001929
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001930 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001931
1932 if (!test_bit(HCI_UP, &hdev->flags)) {
1933 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001934 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001935 goto unlock;
1936 }
1937
1938 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1939 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001940 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001941 goto unlock;
1942 }
1943
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001944 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001945 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1946 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001947 goto unlock;
1948 }
1949
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001950 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001951 if (!cmd) {
1952 err = -ENOMEM;
1953 goto unlock;
1954 }
1955
1956 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1957 if (err < 0)
1958 mgmt_pending_remove(cmd);
1959
1960unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001961 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001962 hci_dev_put(hdev);
1963
1964 return err;
1965}
1966
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001967static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
1968 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01001969{
1970 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001971 struct mgmt_cp_add_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01001972 int err;
1973
1974 BT_DBG("hci%u ", index);
1975
1976 if (len != sizeof(*cp))
1977 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001978 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001979
1980 hdev = hci_dev_get(index);
1981 if (!hdev)
1982 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001983 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001984
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001985 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001986
Johan Hedberg664ce4c2012-02-09 15:44:09 +02001987 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01001988 cp->randomizer);
1989 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001990 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1991 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001992 else
1993 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1994 0);
1995
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001996 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001997 hci_dev_put(hdev);
1998
1999 return err;
2000}
2001
2002static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002003 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002004{
2005 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002006 struct mgmt_cp_remove_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01002007 int err;
2008
2009 BT_DBG("hci%u ", index);
2010
2011 if (len != sizeof(*cp))
2012 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002013 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002014
2015 hdev = hci_dev_get(index);
2016 if (!hdev)
2017 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002018 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002019
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002020 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002021
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002022 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002023 if (err < 0)
2024 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002025 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002026 else
2027 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2028 NULL, 0);
2029
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002030 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002031 hci_dev_put(hdev);
2032
2033 return err;
2034}
2035
Johan Hedberg450dfda2011-11-12 11:58:22 +02002036static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002037 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002038{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002039 struct mgmt_cp_start_discovery *cp = data;
Andre Guedes3fd24152012-02-03 17:48:01 -03002040 unsigned long discov_type = cp->type;
Johan Hedberg14a53662011-04-27 10:29:56 -04002041 struct pending_cmd *cmd;
2042 struct hci_dev *hdev;
2043 int err;
2044
2045 BT_DBG("hci%u", index);
2046
Johan Hedberg450dfda2011-11-12 11:58:22 +02002047 if (len != sizeof(*cp))
2048 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2049 MGMT_STATUS_INVALID_PARAMS);
2050
Johan Hedberg14a53662011-04-27 10:29:56 -04002051 hdev = hci_dev_get(index);
2052 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002053 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2054 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002055
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002056 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002057
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002058 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002059 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2060 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002061 goto failed;
2062 }
2063
Johan Hedbergff9ef572012-01-04 14:23:45 +02002064 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2065 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2066 MGMT_STATUS_BUSY);
2067 goto failed;
2068 }
2069
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002070 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002071 if (!cmd) {
2072 err = -ENOMEM;
2073 goto failed;
2074 }
2075
Andre Guedes3fd24152012-02-03 17:48:01 -03002076 if (test_bit(MGMT_ADDR_BREDR, &discov_type))
2077 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2078 else if (test_bit(MGMT_ADDR_LE_PUBLIC, &discov_type) &&
2079 test_bit(MGMT_ADDR_LE_RANDOM, &discov_type))
2080 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2081 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
2082 else
2083 err = -EINVAL;
2084
Johan Hedberg14a53662011-04-27 10:29:56 -04002085 if (err < 0)
2086 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002087 else
2088 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002089
2090failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002091 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002092 hci_dev_put(hdev);
2093
2094 return err;
2095}
2096
2097static int stop_discovery(struct sock *sk, u16 index)
2098{
2099 struct hci_dev *hdev;
2100 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002101 struct hci_cp_remote_name_req_cancel cp;
2102 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002103 int err;
2104
2105 BT_DBG("hci%u", index);
2106
2107 hdev = hci_dev_get(index);
2108 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002109 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2110 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002111
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002112 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002113
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002114 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002115 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2116 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002117 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002118 }
2119
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002120 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002121 if (!cmd) {
2122 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002123 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002124 }
2125
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002126 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
2127 err = hci_cancel_inquiry(hdev);
2128 if (err < 0)
2129 mgmt_pending_remove(cmd);
2130 else
2131 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2132 goto unlock;
2133 }
2134
2135 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2136 if (!e) {
2137 mgmt_pending_remove(cmd);
2138 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2139 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2140 goto unlock;
2141 }
2142
2143 bacpy(&cp.bdaddr, &e->data.bdaddr);
2144 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2145 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002146 if (err < 0)
2147 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002148 else
2149 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002150
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002151unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002152 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002153 hci_dev_put(hdev);
2154
2155 return err;
2156}
2157
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002158static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002159{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002160 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002161 struct inquiry_entry *e;
2162 struct hci_dev *hdev;
2163 int err;
2164
2165 BT_DBG("hci%u", index);
2166
2167 if (len != sizeof(*cp))
2168 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2169 MGMT_STATUS_INVALID_PARAMS);
2170
2171 hdev = hci_dev_get(index);
2172 if (!hdev)
2173 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2174 MGMT_STATUS_INVALID_PARAMS);
2175
2176 hci_dev_lock(hdev);
2177
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002178 if (!hci_discovery_active(hdev)) {
2179 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2180 MGMT_STATUS_FAILED);
2181 goto failed;
2182 }
2183
Johan Hedberg561aafb2012-01-04 13:31:59 +02002184 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr);
2185 if (!e) {
2186 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2187 MGMT_STATUS_INVALID_PARAMS);
2188 goto failed;
2189 }
2190
2191 if (cp->name_known) {
2192 e->name_state = NAME_KNOWN;
2193 list_del(&e->list);
2194 } else {
2195 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002196 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002197 }
2198
2199 err = 0;
2200
2201failed:
2202 hci_dev_unlock(hdev);
2203
2204 return err;
2205}
2206
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002207static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002208{
2209 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002210 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002211 int err;
2212
2213 BT_DBG("hci%u", index);
2214
Antti Julku7fbec222011-06-15 12:01:15 +03002215 if (len != sizeof(*cp))
2216 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002217 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002218
2219 hdev = hci_dev_get(index);
2220 if (!hdev)
2221 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002222 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002223
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002224 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002225
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002226 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002227 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002228 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2229 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002230 else
2231 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2232 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002233
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002234 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002235 hci_dev_put(hdev);
2236
2237 return err;
2238}
2239
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002240static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002241{
2242 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002243 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002244 int err;
2245
2246 BT_DBG("hci%u", index);
2247
Antti Julku7fbec222011-06-15 12:01:15 +03002248 if (len != sizeof(*cp))
2249 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002250 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002251
2252 hdev = hci_dev_get(index);
2253 if (!hdev)
2254 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002255 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002256
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002257 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002258
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002259 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002260
2261 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002262 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2263 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002264 else
2265 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2266 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002267
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002268 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002269 hci_dev_put(hdev);
2270
2271 return err;
2272}
2273
Antti Julkuf6422ec2011-06-22 13:11:56 +03002274static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002275 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002276{
2277 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002278 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002279 struct hci_cp_write_page_scan_activity acp;
2280 u8 type;
2281 int err;
2282
2283 BT_DBG("hci%u", index);
2284
2285 if (len != sizeof(*cp))
2286 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002287 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002288
2289 hdev = hci_dev_get(index);
2290 if (!hdev)
2291 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002292 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002293
2294 hci_dev_lock(hdev);
2295
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002296 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002297 type = PAGE_SCAN_TYPE_INTERLACED;
2298 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2299 } else {
2300 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2301 acp.interval = 0x0800; /* default 1.28 sec page scan */
2302 }
2303
2304 acp.window = 0x0012; /* default 11.25 msec page scan window */
2305
2306 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2307 sizeof(acp), &acp);
2308 if (err < 0) {
2309 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002310 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002311 goto done;
2312 }
2313
2314 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2315 if (err < 0) {
2316 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002317 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002318 goto done;
2319 }
2320
2321 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2322 NULL, 0);
2323done:
2324 hci_dev_unlock(hdev);
2325 hci_dev_put(hdev);
2326
2327 return err;
2328}
2329
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002330static int load_long_term_keys(struct sock *sk, u16 index,
2331 void *cp_data, u16 len)
2332{
2333 struct hci_dev *hdev;
2334 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2335 u16 key_count, expected_len;
2336 int i;
2337
2338 if (len < sizeof(*cp))
2339 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2340 EINVAL);
2341
2342 key_count = get_unaligned_le16(&cp->key_count);
2343
2344 expected_len = sizeof(*cp) + key_count *
2345 sizeof(struct mgmt_ltk_info);
2346 if (expected_len != len) {
2347 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2348 len, expected_len);
2349 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2350 EINVAL);
2351 }
2352
2353 hdev = hci_dev_get(index);
2354 if (!hdev)
2355 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2356 ENODEV);
2357
2358 BT_DBG("hci%u key_count %u", index, key_count);
2359
2360 hci_dev_lock(hdev);
2361
2362 hci_smp_ltks_clear(hdev);
2363
2364 for (i = 0; i < key_count; i++) {
2365 struct mgmt_ltk_info *key = &cp->keys[i];
2366 u8 type;
2367
2368 if (key->master)
2369 type = HCI_SMP_LTK;
2370 else
2371 type = HCI_SMP_LTK_SLAVE;
2372
2373 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2374 type, 0, key->authenticated, key->val,
2375 key->enc_size, key->ediv, key->rand);
2376 }
2377
2378 hci_dev_unlock(hdev);
2379 hci_dev_put(hdev);
2380
2381 return 0;
2382}
2383
Johan Hedberg03811012010-12-08 00:21:06 +02002384int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2385{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002386 void *buf;
2387 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002388 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002389 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002390 int err;
2391
2392 BT_DBG("got %zu bytes", msglen);
2393
2394 if (msglen < sizeof(*hdr))
2395 return -EINVAL;
2396
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002397 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002398 if (!buf)
2399 return -ENOMEM;
2400
2401 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2402 err = -EFAULT;
2403 goto done;
2404 }
2405
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002406 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002407 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002408 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002409 len = get_unaligned_le16(&hdr->len);
2410
2411 if (len != msglen - sizeof(*hdr)) {
2412 err = -EINVAL;
2413 goto done;
2414 }
2415
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002416 cp = buf + sizeof(*hdr);
2417
Johan Hedberg03811012010-12-08 00:21:06 +02002418 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002419 case MGMT_OP_READ_VERSION:
2420 err = read_version(sk);
2421 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002422 case MGMT_OP_READ_COMMANDS:
2423 err = read_commands(sk);
2424 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002425 case MGMT_OP_READ_INDEX_LIST:
2426 err = read_index_list(sk);
2427 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002428 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002429 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002430 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002431 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002432 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002433 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002434 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002435 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002436 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002437 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002438 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002439 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002440 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002441 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002442 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002443 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002444 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002445 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002446 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002447 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002448 break;
2449 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002450 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002451 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002452 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002453 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002454 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002455 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002456 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002457 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002458 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002459 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002460 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002461 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002462 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002463 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002464 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002465 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002466 break;
2467 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002468 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002469 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002470 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002471 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002472 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002473 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002474 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002475 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002476 case MGMT_OP_CANCEL_PAIR_DEVICE:
2477 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2478 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002479 case MGMT_OP_UNPAIR_DEVICE:
2480 err = unpair_device(sk, index, cp, len);
2481 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002482 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002483 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002484 break;
2485 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002486 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002487 break;
Brian Gix604086b2011-11-23 08:28:33 -08002488 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002489 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002490 break;
2491 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002492 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002493 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002494 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002495 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002496 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002497 case MGMT_OP_READ_LOCAL_OOB_DATA:
2498 err = read_local_oob_data(sk, index);
2499 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002500 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002501 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002502 break;
2503 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002504 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002505 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002506 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002507 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002508 break;
2509 case MGMT_OP_STOP_DISCOVERY:
2510 err = stop_discovery(sk, index);
2511 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002512 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002513 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002514 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002515 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002516 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002517 break;
2518 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002519 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002520 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002521 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2522 err = load_long_term_keys(sk, index, cp, len);
2523 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002524 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002525 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002526 err = cmd_status(sk, index, opcode,
2527 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002528 break;
2529 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002530
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002531 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002532 goto done;
2533
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002534 err = msglen;
2535
2536done:
2537 kfree(buf);
2538 return err;
2539}
2540
Johan Hedbergb24752f2011-11-03 14:40:33 +02002541static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2542{
2543 u8 *status = data;
2544
2545 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2546 mgmt_pending_remove(cmd);
2547}
2548
Johan Hedberg744cf192011-11-08 20:40:14 +02002549int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002550{
Johan Hedberg744cf192011-11-08 20:40:14 +02002551 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002552}
2553
Johan Hedberg744cf192011-11-08 20:40:14 +02002554int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002555{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002556 u8 status = ENODEV;
2557
Johan Hedberg744cf192011-11-08 20:40:14 +02002558 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002559
Johan Hedberg744cf192011-11-08 20:40:14 +02002560 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002561}
2562
2563struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002564 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002565 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002566};
2567
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002568static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002569{
Johan Hedberg03811012010-12-08 00:21:06 +02002570 struct cmd_lookup *match = data;
2571
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002572 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002573
2574 list_del(&cmd->list);
2575
2576 if (match->sk == NULL) {
2577 match->sk = cmd->sk;
2578 sock_hold(match->sk);
2579 }
2580
2581 mgmt_pending_free(cmd);
2582}
2583
Johan Hedberg744cf192011-11-08 20:40:14 +02002584int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002585{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002586 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002587 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002588 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002589
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002590 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002591
Johan Hedbergb24752f2011-11-03 14:40:33 +02002592 if (!powered) {
2593 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002594 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002595 }
2596
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002597 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002598
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002599 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002600 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002601
2602 if (match.sk)
2603 sock_put(match.sk);
2604
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002605 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002606}
2607
Johan Hedberg744cf192011-11-08 20:40:14 +02002608int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002609{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002610 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002611 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002612 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002613
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002614 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002615
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002616 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002617
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002618 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002619 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002620 if (match.sk)
2621 sock_put(match.sk);
2622
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002623 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002624}
2625
Johan Hedberg744cf192011-11-08 20:40:14 +02002626int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002627{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002628 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002629 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002630 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002631
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002632 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2633 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002634
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002635 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002636
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002637 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002638
2639 if (match.sk)
2640 sock_put(match.sk);
2641
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002642 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002643}
2644
Johan Hedberg744cf192011-11-08 20:40:14 +02002645int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002646{
Johan Hedbergca69b792011-11-11 18:10:00 +02002647 u8 mgmt_err = mgmt_status(status);
2648
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002649 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002650 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002651 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002652
2653 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002654 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002655 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002656
2657 return 0;
2658}
2659
Johan Hedberg744cf192011-11-08 20:40:14 +02002660int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2661 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002662{
Johan Hedberg86742e12011-11-07 23:13:38 +02002663 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002664
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002665 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002666
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002667 ev.store_hint = persistent;
2668 bacpy(&ev.key.bdaddr, &key->bdaddr);
2669 ev.key.type = key->type;
2670 memcpy(ev.key.val, key->val, 16);
2671 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002672
Johan Hedberg744cf192011-11-08 20:40:14 +02002673 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002674}
Johan Hedbergf7520542011-01-20 12:34:39 +02002675
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002676int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2677{
2678 struct mgmt_ev_new_long_term_key ev;
2679
2680 memset(&ev, 0, sizeof(ev));
2681
2682 ev.store_hint = persistent;
2683 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2684 ev.key.addr.type = key->bdaddr_type;
2685 ev.key.authenticated = key->authenticated;
2686 ev.key.enc_size = key->enc_size;
2687 ev.key.ediv = key->ediv;
2688
2689 if (key->type == HCI_SMP_LTK)
2690 ev.key.master = 1;
2691
2692 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2693 memcpy(ev.key.val, key->val, sizeof(key->val));
2694
2695 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2696 &ev, sizeof(ev), NULL);
2697}
2698
Johan Hedbergafc747a2012-01-15 18:11:07 +02002699int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002700 u8 addr_type, u8 *name, u8 name_len,
2701 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002702{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002703 char buf[512];
2704 struct mgmt_ev_device_connected *ev = (void *) buf;
2705 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002706
Johan Hedbergb644ba32012-01-17 21:48:47 +02002707 bacpy(&ev->addr.bdaddr, bdaddr);
2708 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002709
Johan Hedbergb644ba32012-01-17 21:48:47 +02002710 if (name_len > 0)
2711 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2712 name, name_len);
2713
2714 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2715 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2716 EIR_CLASS_OF_DEV, dev_class, 3);
2717
2718 put_unaligned_le16(eir_len, &ev->eir_len);
2719
2720 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2721 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002722}
2723
Johan Hedberg8962ee72011-01-20 12:40:27 +02002724static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2725{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002726 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002727 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002728 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002729
Johan Hedberg88c3df12012-02-09 14:27:38 +02002730 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2731 rp.addr.type = cp->addr.type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002732 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002733
Szymon Janc4e51eae2011-02-25 19:05:48 +01002734 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002735
2736 *sk = cmd->sk;
2737 sock_hold(*sk);
2738
Johan Hedberga664b5b2011-02-19 12:06:02 -03002739 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002740}
2741
Johan Hedberg124f6e32012-02-09 13:50:12 +02002742static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002743{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002744 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002745 struct mgmt_cp_unpair_device *cp = cmd->param;
2746 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002747
2748 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002749 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2750 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002751
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002752 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2753
2754 cmd_complete(cmd->sk, cmd->index, cmd->opcode, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002755
2756 mgmt_pending_remove(cmd);
2757}
2758
Johan Hedbergafc747a2012-01-15 18:11:07 +02002759int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2760 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002761{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002762 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002763 struct sock *sk = NULL;
2764 int err;
2765
Johan Hedberg744cf192011-11-08 20:40:14 +02002766 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002767
Johan Hedbergf7520542011-01-20 12:34:39 +02002768 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002769 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002770
Johan Hedbergafc747a2012-01-15 18:11:07 +02002771 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2772 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002773
2774 if (sk)
2775 sock_put(sk);
2776
Johan Hedberg124f6e32012-02-09 13:50:12 +02002777 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002778 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002779
Johan Hedberg8962ee72011-01-20 12:40:27 +02002780 return err;
2781}
2782
Johan Hedberg88c3df12012-02-09 14:27:38 +02002783int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
2784 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002785{
Johan Hedberg88c3df12012-02-09 14:27:38 +02002786 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002787 struct pending_cmd *cmd;
2788 int err;
2789
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002790 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002791 if (!cmd)
2792 return -ENOENT;
2793
Johan Hedberg88c3df12012-02-09 14:27:38 +02002794 bacpy(&rp.addr.bdaddr, bdaddr);
2795 rp.addr.type = link_to_mgmt(link_type, addr_type);
2796 rp.status = mgmt_status(status);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002797
Johan Hedberg88c3df12012-02-09 14:27:38 +02002798 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002799 &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002800
Johan Hedberga664b5b2011-02-19 12:06:02 -03002801 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002802
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002803 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
2804 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002805 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002806}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002807
Johan Hedberg48264f02011-11-09 13:58:58 +02002808int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2809 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002810{
2811 struct mgmt_ev_connect_failed ev;
2812
Johan Hedberg4c659c32011-11-07 23:13:39 +02002813 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002814 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002815 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002816
Johan Hedberg744cf192011-11-08 20:40:14 +02002817 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002818}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002819
Johan Hedberg744cf192011-11-08 20:40:14 +02002820int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002821{
2822 struct mgmt_ev_pin_code_request ev;
2823
Johan Hedberg980e1a52011-01-22 06:10:07 +02002824 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002825 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002826
Johan Hedberg744cf192011-11-08 20:40:14 +02002827 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002828 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002829}
2830
Johan Hedberg744cf192011-11-08 20:40:14 +02002831int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2832 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002833{
2834 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002835 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002836 int err;
2837
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002838 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002839 if (!cmd)
2840 return -ENOENT;
2841
Johan Hedbergac56fb12011-02-19 12:05:59 -03002842 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002843 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002844
Johan Hedberg744cf192011-11-08 20:40:14 +02002845 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002846 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002847
Johan Hedberga664b5b2011-02-19 12:06:02 -03002848 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002849
2850 return err;
2851}
2852
Johan Hedberg744cf192011-11-08 20:40:14 +02002853int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2854 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002855{
2856 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002857 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002858 int err;
2859
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002860 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002861 if (!cmd)
2862 return -ENOENT;
2863
Johan Hedbergac56fb12011-02-19 12:05:59 -03002864 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002865 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002866
Johan Hedberg744cf192011-11-08 20:40:14 +02002867 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002868 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002869
Johan Hedberga664b5b2011-02-19 12:06:02 -03002870 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002871
2872 return err;
2873}
Johan Hedberga5c29682011-02-19 12:05:57 -03002874
Johan Hedberg744cf192011-11-08 20:40:14 +02002875int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002876 u8 link_type, u8 addr_type, __le32 value,
2877 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002878{
2879 struct mgmt_ev_user_confirm_request ev;
2880
Johan Hedberg744cf192011-11-08 20:40:14 +02002881 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002882
Johan Hedberg272d90d2012-02-09 15:26:12 +02002883 bacpy(&ev.addr.bdaddr, bdaddr);
2884 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002885 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002886 put_unaligned_le32(value, &ev.value);
2887
Johan Hedberg744cf192011-11-08 20:40:14 +02002888 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002889 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002890}
2891
Johan Hedberg272d90d2012-02-09 15:26:12 +02002892int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2893 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08002894{
2895 struct mgmt_ev_user_passkey_request ev;
2896
2897 BT_DBG("%s", hdev->name);
2898
Johan Hedberg272d90d2012-02-09 15:26:12 +02002899 bacpy(&ev.addr.bdaddr, bdaddr);
2900 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08002901
2902 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2903 NULL);
2904}
2905
Brian Gix0df4c182011-11-16 13:53:13 -08002906static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002907 u8 link_type, u8 addr_type, u8 status,
2908 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002909{
2910 struct pending_cmd *cmd;
2911 struct mgmt_rp_user_confirm_reply rp;
2912 int err;
2913
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002914 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002915 if (!cmd)
2916 return -ENOENT;
2917
Johan Hedberg272d90d2012-02-09 15:26:12 +02002918 bacpy(&rp.addr.bdaddr, bdaddr);
2919 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002920 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002921 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002922
Johan Hedberga664b5b2011-02-19 12:06:02 -03002923 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002924
2925 return err;
2926}
2927
Johan Hedberg744cf192011-11-08 20:40:14 +02002928int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002929 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002930{
Johan Hedberg272d90d2012-02-09 15:26:12 +02002931 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
2932 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03002933}
2934
Johan Hedberg272d90d2012-02-09 15:26:12 +02002935int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2936 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002937{
Johan Hedberg272d90d2012-02-09 15:26:12 +02002938 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
2939 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03002940}
Johan Hedberg2a611692011-02-19 12:06:00 -03002941
Brian Gix604086b2011-11-23 08:28:33 -08002942int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02002943 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08002944{
Johan Hedberg272d90d2012-02-09 15:26:12 +02002945 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
2946 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08002947}
2948
Johan Hedberg272d90d2012-02-09 15:26:12 +02002949int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2950 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08002951{
Johan Hedberg272d90d2012-02-09 15:26:12 +02002952 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
2953 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08002954}
2955
Johan Hedbergbab73cb2012-02-09 16:07:29 +02002956int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2957 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002958{
2959 struct mgmt_ev_auth_failed ev;
2960
Johan Hedbergbab73cb2012-02-09 16:07:29 +02002961 bacpy(&ev.addr.bdaddr, bdaddr);
2962 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002963 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002964
Johan Hedberg744cf192011-11-08 20:40:14 +02002965 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002966}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002967
Johan Hedberg744cf192011-11-08 20:40:14 +02002968int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002969{
2970 struct pending_cmd *cmd;
2971 struct mgmt_cp_set_local_name ev;
2972 int err;
2973
2974 memset(&ev, 0, sizeof(ev));
2975 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2976
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002977 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002978 if (!cmd)
2979 goto send_event;
2980
2981 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002982 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002983 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002984 goto failed;
2985 }
2986
Johan Hedberg744cf192011-11-08 20:40:14 +02002987 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002988
Johan Hedberg744cf192011-11-08 20:40:14 +02002989 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002990 sizeof(ev));
2991 if (err < 0)
2992 goto failed;
2993
2994send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002995 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002996 cmd ? cmd->sk : NULL);
2997
2998failed:
2999 if (cmd)
3000 mgmt_pending_remove(cmd);
3001 return err;
3002}
Szymon Jancc35938b2011-03-22 13:12:21 +01003003
Johan Hedberg744cf192011-11-08 20:40:14 +02003004int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3005 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003006{
3007 struct pending_cmd *cmd;
3008 int err;
3009
Johan Hedberg744cf192011-11-08 20:40:14 +02003010 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003011
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003012 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003013 if (!cmd)
3014 return -ENOENT;
3015
3016 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003017 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003018 MGMT_OP_READ_LOCAL_OOB_DATA,
3019 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003020 } else {
3021 struct mgmt_rp_read_local_oob_data rp;
3022
3023 memcpy(rp.hash, hash, sizeof(rp.hash));
3024 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3025
Johan Hedberg744cf192011-11-08 20:40:14 +02003026 err = cmd_complete(cmd->sk, hdev->id,
3027 MGMT_OP_READ_LOCAL_OOB_DATA,
3028 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003029 }
3030
3031 mgmt_pending_remove(cmd);
3032
3033 return err;
3034}
Johan Hedberge17acd42011-03-30 23:57:16 +03003035
Johan Hedberg48264f02011-11-09 13:58:58 +02003036int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003037 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003038 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003039{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003040 char buf[512];
3041 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003042 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003043
Johan Hedberg1dc06092012-01-15 21:01:23 +02003044 /* Leave 5 bytes for a potential CoD field */
3045 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003046 return -EINVAL;
3047
Johan Hedberg1dc06092012-01-15 21:01:23 +02003048 memset(buf, 0, sizeof(buf));
3049
Johan Hedberge319d2e2012-01-15 19:51:59 +02003050 bacpy(&ev->addr.bdaddr, bdaddr);
3051 ev->addr.type = link_to_mgmt(link_type, addr_type);
3052 ev->rssi = rssi;
3053 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003054
Johan Hedberg1dc06092012-01-15 21:01:23 +02003055 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003056 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003057
Johan Hedberg1dc06092012-01-15 21:01:23 +02003058 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3059 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3060 dev_class, 3);
3061
3062 put_unaligned_le16(eir_len, &ev->eir_len);
3063
3064 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003065
Johan Hedberge319d2e2012-01-15 19:51:59 +02003066 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003067}
Johan Hedberga88a9652011-03-30 13:18:12 +03003068
Johan Hedbergb644ba32012-01-17 21:48:47 +02003069int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3070 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003071{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003072 struct mgmt_ev_device_found *ev;
3073 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3074 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003075
Johan Hedbergb644ba32012-01-17 21:48:47 +02003076 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003077
Johan Hedbergb644ba32012-01-17 21:48:47 +02003078 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003079
Johan Hedbergb644ba32012-01-17 21:48:47 +02003080 bacpy(&ev->addr.bdaddr, bdaddr);
3081 ev->addr.type = link_to_mgmt(link_type, addr_type);
3082 ev->rssi = rssi;
3083
3084 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3085 name_len);
3086
3087 put_unaligned_le16(eir_len, &ev->eir_len);
3088
Johan Hedberg053c7e02012-02-04 00:06:00 +02003089 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3090 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003091}
Johan Hedberg314b2382011-04-27 10:29:57 -04003092
Andre Guedes7a135102011-11-09 17:14:25 -03003093int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003094{
3095 struct pending_cmd *cmd;
3096 int err;
3097
Andre Guedes203159d2012-02-13 15:41:01 -03003098 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3099
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003100 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003101 if (!cmd)
3102 return -ENOENT;
3103
Johan Hedbergca69b792011-11-11 18:10:00 +02003104 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003105 mgmt_pending_remove(cmd);
3106
3107 return err;
3108}
3109
Andre Guedese6d465c2011-11-09 17:14:26 -03003110int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3111{
3112 struct pending_cmd *cmd;
3113 int err;
3114
3115 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3116 if (!cmd)
3117 return -ENOENT;
3118
Andre Guedese75a8b0c2012-01-02 16:50:53 -03003119 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02003120 mgmt_pending_remove(cmd);
3121
3122 return err;
3123}
Johan Hedberg314b2382011-04-27 10:29:57 -04003124
Johan Hedberg744cf192011-11-08 20:40:14 +02003125int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003126{
Johan Hedberg164a6e72011-11-01 17:06:44 +02003127 struct pending_cmd *cmd;
3128
Andre Guedes343fb142011-11-22 17:14:19 -03003129 BT_DBG("%s discovering %u", hdev->name, discovering);
3130
Johan Hedberg164a6e72011-11-01 17:06:44 +02003131 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003132 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003133 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003134 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003135
3136 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003137 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003138 mgmt_pending_remove(cmd);
3139 }
3140
Johan Hedberg744cf192011-11-08 20:40:14 +02003141 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04003142 sizeof(discovering), NULL);
3143}
Antti Julku5e762442011-08-25 16:48:02 +03003144
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003145int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003146{
3147 struct pending_cmd *cmd;
3148 struct mgmt_ev_device_blocked ev;
3149
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003150 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003151
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003152 bacpy(&ev.addr.bdaddr, bdaddr);
3153 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003154
Johan Hedberg744cf192011-11-08 20:40:14 +02003155 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3156 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003157}
3158
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003159int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003160{
3161 struct pending_cmd *cmd;
3162 struct mgmt_ev_device_unblocked ev;
3163
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003164 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003165
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003166 bacpy(&ev.addr.bdaddr, bdaddr);
3167 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003168
Johan Hedberg744cf192011-11-08 20:40:14 +02003169 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3170 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003171}