blob: 01c8d6239a4b087e6975c2df6dc1de285ae6aa05 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Johan Hedbergca69b792011-11-11 18:10:00 +020025#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Johan Hedberg02d98122010-12-13 21:07:04 +020035#define MGMT_VERSION 0
36#define MGMT_REVISION 1
37
Johan Hedberge70bb2e2012-02-13 16:59:33 +020038static const u16 mgmt_commands[] = {
39 MGMT_OP_READ_INDEX_LIST,
40 MGMT_OP_READ_INFO,
41 MGMT_OP_SET_POWERED,
42 MGMT_OP_SET_DISCOVERABLE,
43 MGMT_OP_SET_CONNECTABLE,
44 MGMT_OP_SET_FAST_CONNECTABLE,
45 MGMT_OP_SET_PAIRABLE,
46 MGMT_OP_SET_LINK_SECURITY,
47 MGMT_OP_SET_SSP,
48 MGMT_OP_SET_HS,
49 MGMT_OP_SET_LE,
50 MGMT_OP_SET_DEV_CLASS,
51 MGMT_OP_SET_LOCAL_NAME,
52 MGMT_OP_ADD_UUID,
53 MGMT_OP_REMOVE_UUID,
54 MGMT_OP_LOAD_LINK_KEYS,
55 MGMT_OP_LOAD_LONG_TERM_KEYS,
56 MGMT_OP_DISCONNECT,
57 MGMT_OP_GET_CONNECTIONS,
58 MGMT_OP_PIN_CODE_REPLY,
59 MGMT_OP_PIN_CODE_NEG_REPLY,
60 MGMT_OP_SET_IO_CAPABILITY,
61 MGMT_OP_PAIR_DEVICE,
62 MGMT_OP_CANCEL_PAIR_DEVICE,
63 MGMT_OP_UNPAIR_DEVICE,
64 MGMT_OP_USER_CONFIRM_REPLY,
65 MGMT_OP_USER_CONFIRM_NEG_REPLY,
66 MGMT_OP_USER_PASSKEY_REPLY,
67 MGMT_OP_USER_PASSKEY_NEG_REPLY,
68 MGMT_OP_READ_LOCAL_OOB_DATA,
69 MGMT_OP_ADD_REMOTE_OOB_DATA,
70 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
71 MGMT_OP_START_DISCOVERY,
72 MGMT_OP_STOP_DISCOVERY,
73 MGMT_OP_CONFIRM_NAME,
74 MGMT_OP_BLOCK_DEVICE,
75 MGMT_OP_UNBLOCK_DEVICE,
76};
77
78static const u16 mgmt_events[] = {
79 MGMT_EV_CONTROLLER_ERROR,
80 MGMT_EV_INDEX_ADDED,
81 MGMT_EV_INDEX_REMOVED,
82 MGMT_EV_NEW_SETTINGS,
83 MGMT_EV_CLASS_OF_DEV_CHANGED,
84 MGMT_EV_LOCAL_NAME_CHANGED,
85 MGMT_EV_NEW_LINK_KEY,
86 MGMT_EV_NEW_LONG_TERM_KEY,
87 MGMT_EV_DEVICE_CONNECTED,
88 MGMT_EV_DEVICE_DISCONNECTED,
89 MGMT_EV_CONNECT_FAILED,
90 MGMT_EV_PIN_CODE_REQUEST,
91 MGMT_EV_USER_CONFIRM_REQUEST,
92 MGMT_EV_USER_PASSKEY_REQUEST,
93 MGMT_EV_AUTH_FAILED,
94 MGMT_EV_DEVICE_FOUND,
95 MGMT_EV_DISCOVERING,
96 MGMT_EV_DEVICE_BLOCKED,
97 MGMT_EV_DEVICE_UNBLOCKED,
98 MGMT_EV_DEVICE_UNPAIRED,
99};
100
Andre Guedes3fd24152012-02-03 17:48:01 -0300101/*
102 * These LE scan and inquiry parameters were chosen according to LE General
103 * Discovery Procedure specification.
104 */
105#define LE_SCAN_TYPE 0x01
106#define LE_SCAN_WIN 0x12
107#define LE_SCAN_INT 0x12
108#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
109
Andre Guedese8777522012-02-03 17:48:02 -0300110#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300111
Johan Hedberg7d785252011-12-15 00:47:39 +0200112#define SERVICE_CACHE_TIMEOUT (5 * 1000)
113
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200114struct pending_cmd {
115 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200116 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200117 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100118 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200119 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300120 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200121};
122
Johan Hedbergca69b792011-11-11 18:10:00 +0200123/* HCI to MGMT error code conversion table */
124static u8 mgmt_status_table[] = {
125 MGMT_STATUS_SUCCESS,
126 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
127 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
128 MGMT_STATUS_FAILED, /* Hardware Failure */
129 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
130 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
131 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
132 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
133 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
134 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
135 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
136 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
137 MGMT_STATUS_BUSY, /* Command Disallowed */
138 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
139 MGMT_STATUS_REJECTED, /* Rejected Security */
140 MGMT_STATUS_REJECTED, /* Rejected Personal */
141 MGMT_STATUS_TIMEOUT, /* Host Timeout */
142 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
143 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
144 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
145 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
146 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
147 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
148 MGMT_STATUS_BUSY, /* Repeated Attempts */
149 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
150 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
151 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
152 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
153 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
154 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
155 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
156 MGMT_STATUS_FAILED, /* Unspecified Error */
157 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
158 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
159 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
160 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
161 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
162 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
163 MGMT_STATUS_FAILED, /* Unit Link Key Used */
164 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
165 MGMT_STATUS_TIMEOUT, /* Instant Passed */
166 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
167 MGMT_STATUS_FAILED, /* Transaction Collision */
168 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
169 MGMT_STATUS_REJECTED, /* QoS Rejected */
170 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
171 MGMT_STATUS_REJECTED, /* Insufficient Security */
172 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
173 MGMT_STATUS_BUSY, /* Role Switch Pending */
174 MGMT_STATUS_FAILED, /* Slot Violation */
175 MGMT_STATUS_FAILED, /* Role Switch Failed */
176 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
177 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
178 MGMT_STATUS_BUSY, /* Host Busy Pairing */
179 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
180 MGMT_STATUS_BUSY, /* Controller Busy */
181 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
182 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
183 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
184 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
185 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
186};
187
188static u8 mgmt_status(u8 hci_status)
189{
190 if (hci_status < ARRAY_SIZE(mgmt_status_table))
191 return mgmt_status_table[hci_status];
192
193 return MGMT_STATUS_FAILED;
194}
195
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200197{
198 struct sk_buff *skb;
199 struct mgmt_hdr *hdr;
200 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300201 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200202
Szymon Janc34eb5252011-02-28 14:10:08 +0100203 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200204
205 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
206 if (!skb)
207 return -ENOMEM;
208
209 hdr = (void *) skb_put(skb, sizeof(*hdr));
210
211 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100212 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200213 hdr->len = cpu_to_le16(sizeof(*ev));
214
215 ev = (void *) skb_put(skb, sizeof(*ev));
216 ev->status = status;
217 put_unaligned_le16(cmd, &ev->opcode);
218
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300219 err = sock_queue_rcv_skb(sk, skb);
220 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200221 kfree_skb(skb);
222
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300223 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200224}
225
Szymon Janc4e51eae2011-02-25 19:05:48 +0100226static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
227 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200228{
229 struct sk_buff *skb;
230 struct mgmt_hdr *hdr;
231 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300232 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200233
234 BT_DBG("sock %p", sk);
235
Johan Hedberga38528f2011-01-22 06:46:43 +0200236 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200237 if (!skb)
238 return -ENOMEM;
239
240 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200241
Johan Hedberg02d98122010-12-13 21:07:04 +0200242 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100243 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
247 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100248
249 if (rp)
250 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200251
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300252 err = sock_queue_rcv_skb(sk, skb);
253 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200254 kfree_skb(skb);
255
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300256 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200257}
258
Johan Hedberga38528f2011-01-22 06:46:43 +0200259static int read_version(struct sock *sk)
260{
261 struct mgmt_rp_read_version rp;
262
263 BT_DBG("sock %p", sk);
264
265 rp.version = MGMT_VERSION;
266 put_unaligned_le16(MGMT_REVISION, &rp.revision);
267
Szymon Janc4e51eae2011-02-25 19:05:48 +0100268 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
269 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200270}
271
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200272static int read_commands(struct sock *sk)
273{
274 struct mgmt_rp_read_commands *rp;
275 u16 num_commands = ARRAY_SIZE(mgmt_commands);
276 u16 num_events = ARRAY_SIZE(mgmt_events);
277 u16 *opcode;
278 size_t rp_size;
279 int i, err;
280
281 BT_DBG("sock %p", sk);
282
283 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
284
285 rp = kmalloc(rp_size, GFP_KERNEL);
286 if (!rp)
287 return -ENOMEM;
288
289 put_unaligned_le16(num_commands, &rp->num_commands);
290 put_unaligned_le16(num_events, &rp->num_events);
291
292 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
293 put_unaligned_le16(mgmt_commands[i], opcode);
294
295 for (i = 0; i < num_events; i++, opcode++)
296 put_unaligned_le16(mgmt_events[i], opcode);
297
298 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, rp,
299 rp_size);
300 kfree(rp);
301
302 return err;
303}
304
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200305static int read_index_list(struct sock *sk)
306{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200307 struct mgmt_rp_read_index_list *rp;
308 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200309 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200310 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200311 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200312 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200313
314 BT_DBG("sock %p", sk);
315
316 read_lock(&hci_dev_list_lock);
317
318 count = 0;
319 list_for_each(p, &hci_dev_list) {
320 count++;
321 }
322
Johan Hedberga38528f2011-01-22 06:46:43 +0200323 rp_len = sizeof(*rp) + (2 * count);
324 rp = kmalloc(rp_len, GFP_ATOMIC);
325 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100326 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100328 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200329
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200330 put_unaligned_le16(count, &rp->num_controllers);
331
332 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200333 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200334 if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200335 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200336
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200337 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200338 continue;
339
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200340 put_unaligned_le16(d->id, &rp->index[i++]);
341 BT_DBG("Added hci%u", d->id);
342 }
343
344 read_unlock(&hci_dev_list_lock);
345
Szymon Janc4e51eae2011-02-25 19:05:48 +0100346 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
347 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200348
Johan Hedberga38528f2011-01-22 06:46:43 +0200349 kfree(rp);
350
351 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352}
353
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200354static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200355{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200356 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200357
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200358 settings |= MGMT_SETTING_POWERED;
359 settings |= MGMT_SETTING_CONNECTABLE;
360 settings |= MGMT_SETTING_FAST_CONNECTABLE;
361 settings |= MGMT_SETTING_DISCOVERABLE;
362 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200363
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200364 if (hdev->features[6] & LMP_SIMPLE_PAIR)
365 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200366
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 if (!(hdev->features[4] & LMP_NO_BREDR)) {
368 settings |= MGMT_SETTING_BREDR;
369 settings |= MGMT_SETTING_LINK_SECURITY;
370 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (hdev->features[4] & LMP_LE)
373 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 return settings;
376}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378static u32 get_current_settings(struct hci_dev *hdev)
379{
380 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200381
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200382 if (test_bit(HCI_UP, &hdev->flags))
383 settings |= MGMT_SETTING_POWERED;
384 else
385 return settings;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200386
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200387 if (test_bit(HCI_PSCAN, &hdev->flags))
388 settings |= MGMT_SETTING_CONNECTABLE;
389
390 if (test_bit(HCI_ISCAN, &hdev->flags))
391 settings |= MGMT_SETTING_DISCOVERABLE;
392
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200393 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200394 settings |= MGMT_SETTING_PAIRABLE;
395
396 if (!(hdev->features[4] & LMP_NO_BREDR))
397 settings |= MGMT_SETTING_BREDR;
398
Andre Guedes59e29402011-12-30 10:34:03 -0300399 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200400 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200401
402 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200404
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200405 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200407
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200409}
410
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300411#define PNP_INFO_SVCLASS_ID 0x1200
412
413static u8 bluetooth_base_uuid[] = {
414 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
415 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
416};
417
418static u16 get_uuid16(u8 *uuid128)
419{
420 u32 val;
421 int i;
422
423 for (i = 0; i < 12; i++) {
424 if (bluetooth_base_uuid[i] != uuid128[i])
425 return 0;
426 }
427
428 memcpy(&val, &uuid128[12], 4);
429
430 val = le32_to_cpu(val);
431 if (val > 0xffff)
432 return 0;
433
434 return (u16) val;
435}
436
437static void create_eir(struct hci_dev *hdev, u8 *data)
438{
439 u8 *ptr = data;
440 u16 eir_len = 0;
441 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
442 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200443 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300444 size_t name_len;
445
446 name_len = strlen(hdev->dev_name);
447
448 if (name_len > 0) {
449 /* EIR Data type */
450 if (name_len > 48) {
451 name_len = 48;
452 ptr[1] = EIR_NAME_SHORT;
453 } else
454 ptr[1] = EIR_NAME_COMPLETE;
455
456 /* EIR Data length */
457 ptr[0] = name_len + 1;
458
459 memcpy(ptr + 2, hdev->dev_name, name_len);
460
461 eir_len += (name_len + 2);
462 ptr += (name_len + 2);
463 }
464
465 memset(uuid16_list, 0, sizeof(uuid16_list));
466
467 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200468 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300469 u16 uuid16;
470
471 uuid16 = get_uuid16(uuid->uuid);
472 if (uuid16 == 0)
473 return;
474
475 if (uuid16 < 0x1100)
476 continue;
477
478 if (uuid16 == PNP_INFO_SVCLASS_ID)
479 continue;
480
481 /* Stop if not enough space to put next UUID */
482 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
483 truncated = 1;
484 break;
485 }
486
487 /* Check for duplicates */
488 for (i = 0; uuid16_list[i] != 0; i++)
489 if (uuid16_list[i] == uuid16)
490 break;
491
492 if (uuid16_list[i] == 0) {
493 uuid16_list[i] = uuid16;
494 eir_len += sizeof(u16);
495 }
496 }
497
498 if (uuid16_list[0] != 0) {
499 u8 *length = ptr;
500
501 /* EIR Data type */
502 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
503
504 ptr += 2;
505 eir_len += 2;
506
507 for (i = 0; uuid16_list[i] != 0; i++) {
508 *ptr++ = (uuid16_list[i] & 0x00ff);
509 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
510 }
511
512 /* EIR Data length */
513 *length = (i * sizeof(u16)) + 1;
514 }
515}
516
517static int update_eir(struct hci_dev *hdev)
518{
519 struct hci_cp_write_eir cp;
520
521 if (!(hdev->features[6] & LMP_EXT_INQ))
522 return 0;
523
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200524 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300525 return 0;
526
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200527 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300528 return 0;
529
530 memset(&cp, 0, sizeof(cp));
531
532 create_eir(hdev, cp.data);
533
534 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
535 return 0;
536
537 memcpy(hdev->eir, cp.data, sizeof(cp.data));
538
539 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
540}
541
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200542static u8 get_service_classes(struct hci_dev *hdev)
543{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300544 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200545 u8 val = 0;
546
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300547 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200548 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200549
550 return val;
551}
552
553static int update_class(struct hci_dev *hdev)
554{
555 u8 cod[3];
556
557 BT_DBG("%s", hdev->name);
558
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200559 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200560 return 0;
561
562 cod[0] = hdev->minor_class;
563 cod[1] = hdev->major_class;
564 cod[2] = get_service_classes(hdev);
565
566 if (memcmp(cod, hdev->dev_class, 3) == 0)
567 return 0;
568
569 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
570}
571
Johan Hedberg7d785252011-12-15 00:47:39 +0200572static void service_cache_off(struct work_struct *work)
573{
574 struct hci_dev *hdev = container_of(work, struct hci_dev,
575 service_cache.work);
576
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200577 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200578 return;
579
580 hci_dev_lock(hdev);
581
582 update_eir(hdev);
583 update_class(hdev);
584
585 hci_dev_unlock(hdev);
586}
587
588static void mgmt_init_hdev(struct hci_dev *hdev)
589{
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200590 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200591 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
592
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200593 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200594 schedule_delayed_work(&hdev->service_cache,
595 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
596}
597
Johan Hedberg03811012010-12-08 00:21:06 +0200598static int read_controller_info(struct sock *sk, u16 index)
599{
600 struct mgmt_rp_read_info rp;
601 struct hci_dev *hdev;
602
603 BT_DBG("sock %p hci%u", sk, index);
604
605 hdev = hci_dev_get(index);
606 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200607 return cmd_status(sk, index, MGMT_OP_READ_INFO,
608 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200609
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200610 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
Johan Hedberg03811012010-12-08 00:21:06 +0200611 cancel_delayed_work_sync(&hdev->power_off);
612
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300613 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200614
Johan Hedberg7d785252011-12-15 00:47:39 +0200615 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
616 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200617
618 memset(&rp, 0, sizeof(rp));
619
Johan Hedberg03811012010-12-08 00:21:06 +0200620 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200621
622 rp.version = hdev->hci_ver;
623
Johan Hedberg03811012010-12-08 00:21:06 +0200624 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200625
626 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
627 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
628
629 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200630
631 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
632
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300633 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200634 hci_dev_put(hdev);
635
636 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
637}
638
639static void mgmt_pending_free(struct pending_cmd *cmd)
640{
641 sock_put(cmd->sk);
642 kfree(cmd->param);
643 kfree(cmd);
644}
645
646static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
647 struct hci_dev *hdev,
648 void *data, u16 len)
649{
650 struct pending_cmd *cmd;
651
652 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
653 if (!cmd)
654 return NULL;
655
656 cmd->opcode = opcode;
657 cmd->index = hdev->id;
658
659 cmd->param = kmalloc(len, GFP_ATOMIC);
660 if (!cmd->param) {
661 kfree(cmd);
662 return NULL;
663 }
664
665 if (data)
666 memcpy(cmd->param, data, len);
667
668 cmd->sk = sk;
669 sock_hold(sk);
670
671 list_add(&cmd->list, &hdev->mgmt_pending);
672
673 return cmd;
674}
675
676static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
677 void (*cb)(struct pending_cmd *cmd, void *data),
678 void *data)
679{
680 struct list_head *p, *n;
681
682 list_for_each_safe(p, n, &hdev->mgmt_pending) {
683 struct pending_cmd *cmd;
684
685 cmd = list_entry(p, struct pending_cmd, list);
686
687 if (opcode > 0 && cmd->opcode != opcode)
688 continue;
689
690 cb(cmd, data);
691 }
692}
693
694static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
695{
696 struct pending_cmd *cmd;
697
698 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
699 if (cmd->opcode == opcode)
700 return cmd;
701 }
702
703 return NULL;
704}
705
706static void mgmt_pending_remove(struct pending_cmd *cmd)
707{
708 list_del(&cmd->list);
709 mgmt_pending_free(cmd);
710}
711
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200712static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200713{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200714 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200715
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200716 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200717}
718
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300719static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200720{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300721 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200722 struct hci_dev *hdev;
723 struct pending_cmd *cmd;
724 int err, up;
725
Johan Hedberg03811012010-12-08 00:21:06 +0200726 BT_DBG("request for hci%u", index);
727
728 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200729 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
730 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200731
732 hdev = hci_dev_get(index);
733 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200734 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
735 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200736
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300737 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200738
739 up = test_bit(HCI_UP, &hdev->flags);
740 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200741 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200742 goto failed;
743 }
744
745 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200746 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
747 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200748 goto failed;
749 }
750
751 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
752 if (!cmd) {
753 err = -ENOMEM;
754 goto failed;
755 }
756
757 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200758 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200759 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200760 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200761
762 err = 0;
763
764failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300765 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200766 hci_dev_put(hdev);
767 return err;
768}
769
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300770static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200771{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300772 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200773 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200774 struct pending_cmd *cmd;
775 u8 scan;
776 int err;
777
Johan Hedberg03811012010-12-08 00:21:06 +0200778 BT_DBG("request for hci%u", index);
779
780 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200781 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
782 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200783
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200784 hdev = hci_dev_get(index);
785 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200786 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
787 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200788
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300789 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200790
791 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200792 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
793 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200794 goto failed;
795 }
796
797 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
798 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200799 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
800 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200801 goto failed;
802 }
803
804 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
805 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200806 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200807 goto failed;
808 }
809
810 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
811 if (!cmd) {
812 err = -ENOMEM;
813 goto failed;
814 }
815
816 scan = SCAN_PAGE;
817
818 if (cp->val)
819 scan |= SCAN_INQUIRY;
820 else
821 cancel_delayed_work(&hdev->discov_off);
822
823 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
824 if (err < 0)
825 mgmt_pending_remove(cmd);
826
Johan Hedberg03811012010-12-08 00:21:06 +0200827 if (cp->val)
828 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
829
Johan Hedberge41d8b42010-12-13 21:07:03 +0200830failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300831 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200832 hci_dev_put(hdev);
833
834 return err;
835}
836
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300837static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200838{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300839 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200840 struct hci_dev *hdev;
841 struct pending_cmd *cmd;
842 u8 scan;
843 int err;
844
Johan Hedberge41d8b42010-12-13 21:07:03 +0200845 BT_DBG("request for hci%u", index);
846
Johan Hedberg03811012010-12-08 00:21:06 +0200847 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200848 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
849 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200850
851 hdev = hci_dev_get(index);
852 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200853 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
854 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200855
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300856 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200857
858 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200859 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
860 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200861 goto failed;
862 }
863
864 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
865 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200866 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
867 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200868 goto failed;
869 }
870
871 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200872 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200873 goto failed;
874 }
875
876 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
877 if (!cmd) {
878 err = -ENOMEM;
879 goto failed;
880 }
881
882 if (cp->val)
883 scan = SCAN_PAGE;
884 else
885 scan = 0;
886
887 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
888 if (err < 0)
889 mgmt_pending_remove(cmd);
890
891failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300892 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200893 hci_dev_put(hdev);
894
895 return err;
896}
897
898static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
899 u16 data_len, struct sock *skip_sk)
900{
901 struct sk_buff *skb;
902 struct mgmt_hdr *hdr;
903
904 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
905 if (!skb)
906 return -ENOMEM;
907
908 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
909
910 hdr = (void *) skb_put(skb, sizeof(*hdr));
911 hdr->opcode = cpu_to_le16(event);
912 if (hdev)
913 hdr->index = cpu_to_le16(hdev->id);
914 else
915 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
916 hdr->len = cpu_to_le16(data_len);
917
918 if (data)
919 memcpy(skb_put(skb, data_len), data, data_len);
920
921 hci_send_to_sock(NULL, skb, skip_sk);
922 kfree_skb(skb);
923
924 return 0;
925}
926
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300927static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200928{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300929 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200930 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200931 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200932 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200933
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200934 BT_DBG("request for hci%u", index);
935
936 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200937 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
938 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200939
940 hdev = hci_dev_get(index);
941 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200942 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
943 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200944
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300945 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200946
947 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200948 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200949 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200950 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200951
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200952 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200953 if (err < 0)
954 goto failed;
955
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200956 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200957
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200958 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200959
960failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300961 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200962 hci_dev_put(hdev);
963
964 return err;
965}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200966
Johan Hedberg33ef95e2012-02-16 23:56:27 +0200967static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
968{
969 struct mgmt_mode *cp = data;
970 struct pending_cmd *cmd;
971 struct hci_dev *hdev;
972 uint8_t val;
973 int err;
974
975 BT_DBG("request for hci%u", index);
976
977 if (len != sizeof(*cp))
978 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
979 MGMT_STATUS_INVALID_PARAMS);
980
981 hdev = hci_dev_get(index);
982 if (!hdev)
983 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
984 MGMT_STATUS_INVALID_PARAMS);
985
986 hci_dev_lock(hdev);
987
988 if (!test_bit(HCI_UP, &hdev->flags)) {
989 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
990 MGMT_STATUS_NOT_POWERED);
991 goto failed;
992 }
993
994 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
995 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
996 MGMT_STATUS_BUSY);
997 goto failed;
998 }
999
1000 val = !!cp->val;
1001
1002 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1003 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1004 goto failed;
1005 }
1006
1007 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1008 if (!cmd) {
1009 err = -ENOMEM;
1010 goto failed;
1011 }
1012
1013 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1014 if (err < 0) {
1015 mgmt_pending_remove(cmd);
1016 goto failed;
1017 }
1018
1019failed:
1020 hci_dev_unlock(hdev);
1021 hci_dev_put(hdev);
1022
1023 return err;
1024}
1025
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001026static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1027{
1028 struct mgmt_mode *cp = data;
1029 struct pending_cmd *cmd;
1030 struct hci_dev *hdev;
1031 uint8_t val;
1032 int err;
1033
1034 BT_DBG("request for hci%u", index);
1035
1036 if (len != sizeof(*cp))
1037 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1038 MGMT_STATUS_INVALID_PARAMS);
1039
1040 hdev = hci_dev_get(index);
1041 if (!hdev)
1042 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1043 MGMT_STATUS_INVALID_PARAMS);
1044
1045 hci_dev_lock(hdev);
1046
1047 if (!test_bit(HCI_UP, &hdev->flags)) {
1048 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1049 MGMT_STATUS_NOT_POWERED);
1050 goto failed;
1051 }
1052
1053 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1054 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1055 goto failed;
1056 }
1057
1058 val = !!cp->val;
1059
1060 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1061 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1062 goto failed;
1063 }
1064
1065 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1066 if (!cmd) {
1067 err = -ENOMEM;
1068 goto failed;
1069 }
1070
1071 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1072 if (err < 0) {
1073 mgmt_pending_remove(cmd);
1074 goto failed;
1075 }
1076
1077failed:
1078 hci_dev_unlock(hdev);
1079 hci_dev_put(hdev);
1080
1081 return err;
1082}
1083
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001084static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001085{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001086 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001087 struct hci_dev *hdev;
1088 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001089 int err;
1090
Szymon Janc4e51eae2011-02-25 19:05:48 +01001091 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001092
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001093 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001094 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1095 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001096
Szymon Janc4e51eae2011-02-25 19:05:48 +01001097 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001098 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001099 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1100 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001101
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001102 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001103
1104 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1105 if (!uuid) {
1106 err = -ENOMEM;
1107 goto failed;
1108 }
1109
1110 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001111 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001112
1113 list_add(&uuid->list, &hdev->uuids);
1114
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001115 err = update_class(hdev);
1116 if (err < 0)
1117 goto failed;
1118
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001119 err = update_eir(hdev);
1120 if (err < 0)
1121 goto failed;
1122
Szymon Janc4e51eae2011-02-25 19:05:48 +01001123 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001124
1125failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001126 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001127 hci_dev_put(hdev);
1128
1129 return err;
1130}
1131
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001132static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001133{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001134 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001135 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001136 struct hci_dev *hdev;
1137 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 +02001138 int err, found;
1139
Szymon Janc4e51eae2011-02-25 19:05:48 +01001140 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001141
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001142 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001143 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1144 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001145
Szymon Janc4e51eae2011-02-25 19:05:48 +01001146 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001147 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001148 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1149 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001150
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001151 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001152
1153 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1154 err = hci_uuids_clear(hdev);
1155 goto unlock;
1156 }
1157
1158 found = 0;
1159
1160 list_for_each_safe(p, n, &hdev->uuids) {
1161 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1162
1163 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1164 continue;
1165
1166 list_del(&match->list);
1167 found++;
1168 }
1169
1170 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001171 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1172 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001173 goto unlock;
1174 }
1175
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001176 err = update_class(hdev);
1177 if (err < 0)
1178 goto unlock;
1179
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001180 err = update_eir(hdev);
1181 if (err < 0)
1182 goto unlock;
1183
Szymon Janc4e51eae2011-02-25 19:05:48 +01001184 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001185
1186unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001187 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001188 hci_dev_put(hdev);
1189
1190 return err;
1191}
1192
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001193static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001194{
1195 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001196 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001197 int err;
1198
Szymon Janc4e51eae2011-02-25 19:05:48 +01001199 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001200
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001201 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001202 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1203 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001204
Szymon Janc4e51eae2011-02-25 19:05:48 +01001205 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001206 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001207 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1208 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001209
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001210 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001211
1212 hdev->major_class = cp->major;
1213 hdev->minor_class = cp->minor;
1214
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001215 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001216 hci_dev_unlock(hdev);
1217 cancel_delayed_work_sync(&hdev->service_cache);
1218 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001219 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001220 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001221
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001222 err = update_class(hdev);
1223
1224 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001225 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001226
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001227 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001228 hci_dev_put(hdev);
1229
1230 return err;
1231}
1232
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001233static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001234{
1235 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001236 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001237 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001238 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001239
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001240 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001241 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1242 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001243
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001244 key_count = get_unaligned_le16(&cp->key_count);
1245
Johan Hedberg86742e12011-11-07 23:13:38 +02001246 expected_len = sizeof(*cp) + key_count *
1247 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001248 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001249 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001250 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001251 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1252 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001253 }
1254
Szymon Janc4e51eae2011-02-25 19:05:48 +01001255 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001256 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001257 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1258 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001259
Szymon Janc4e51eae2011-02-25 19:05:48 +01001260 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001261 key_count);
1262
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001263 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001264
1265 hci_link_keys_clear(hdev);
1266
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001267 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001268
1269 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001270 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001271 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001272 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001273
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001274 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001275 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001276
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001277 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1278 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001279 }
1280
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001281 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1282
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001283 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001284 hci_dev_put(hdev);
1285
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001286 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001287}
1288
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001289static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1290 u8 addr_type, struct sock *skip_sk)
1291{
1292 struct mgmt_ev_device_unpaired ev;
1293
1294 bacpy(&ev.addr.bdaddr, bdaddr);
1295 ev.addr.type = addr_type;
1296
1297 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1298 skip_sk);
1299}
1300
Johan Hedberg124f6e32012-02-09 13:50:12 +02001301static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001302{
1303 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001304 struct mgmt_cp_unpair_device *cp = data;
1305 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001306 struct hci_cp_disconnect dc;
1307 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001308 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001309 int err;
1310
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001311 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001312 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001313 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001314
Szymon Janc4e51eae2011-02-25 19:05:48 +01001315 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001316 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001317 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001318 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001319
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001320 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001321
Johan Hedberga8a1d192011-11-10 15:54:38 +02001322 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001323 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1324 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001325
Johan Hedberg124f6e32012-02-09 13:50:12 +02001326 if (cp->addr.type == MGMT_ADDR_BREDR)
1327 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1328 else
1329 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001330
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001331 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001332 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001333 goto unlock;
1334 }
1335
Johan Hedberga8a1d192011-11-10 15:54:38 +02001336 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02001337 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001338 sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001339 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001340 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001341 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001342
Johan Hedberg124f6e32012-02-09 13:50:12 +02001343 if (cp->addr.type == MGMT_ADDR_BREDR)
1344 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1345 &cp->addr.bdaddr);
1346 else
1347 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1348 &cp->addr.bdaddr);
1349
Johan Hedberga8a1d192011-11-10 15:54:38 +02001350 if (!conn) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02001351 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001352 sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001353 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001354 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001355 }
1356
Johan Hedberg124f6e32012-02-09 13:50:12 +02001357 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1358 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001359 if (!cmd) {
1360 err = -ENOMEM;
1361 goto unlock;
1362 }
1363
1364 put_unaligned_le16(conn->handle, &dc.handle);
1365 dc.reason = 0x13; /* Remote User Terminated Connection */
1366 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1367 if (err < 0)
1368 mgmt_pending_remove(cmd);
1369
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001370unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001371 if (err < 0)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001372 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001373 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001374 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001375 hci_dev_put(hdev);
1376
1377 return err;
1378}
1379
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001380static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001381{
1382 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001383 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001384 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001385 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001386 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001387 int err;
1388
1389 BT_DBG("");
1390
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001391 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001392 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1393 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001394
Szymon Janc4e51eae2011-02-25 19:05:48 +01001395 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001396 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001397 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1398 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001399
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001400 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001401
1402 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001403 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1404 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001405 goto failed;
1406 }
1407
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001408 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001409 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1410 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001411 goto failed;
1412 }
1413
Johan Hedberg88c3df12012-02-09 14:27:38 +02001414 if (cp->addr.type == MGMT_ADDR_BREDR)
1415 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1416 else
1417 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001418
Johan Hedberg8962ee72011-01-20 12:40:27 +02001419 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001420 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1421 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001422 goto failed;
1423 }
1424
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001425 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001426 if (!cmd) {
1427 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001428 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001429 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001430
1431 put_unaligned_le16(conn->handle, &dc.handle);
1432 dc.reason = 0x13; /* Remote User Terminated Connection */
1433
1434 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1435 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001436 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001437
1438failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001439 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001440 hci_dev_put(hdev);
1441
1442 return err;
1443}
1444
Johan Hedberg48264f02011-11-09 13:58:58 +02001445static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001446{
1447 switch (link_type) {
1448 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001449 switch (addr_type) {
1450 case ADDR_LE_DEV_PUBLIC:
1451 return MGMT_ADDR_LE_PUBLIC;
1452 case ADDR_LE_DEV_RANDOM:
1453 return MGMT_ADDR_LE_RANDOM;
1454 default:
1455 return MGMT_ADDR_INVALID;
1456 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001457 case ACL_LINK:
1458 return MGMT_ADDR_BREDR;
1459 default:
1460 return MGMT_ADDR_INVALID;
1461 }
1462}
1463
Szymon Janc8ce62842011-03-01 16:55:32 +01001464static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001465{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001466 struct mgmt_rp_get_connections *rp;
1467 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001468 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001469 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001470 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001471 int i, err;
1472
1473 BT_DBG("");
1474
Szymon Janc4e51eae2011-02-25 19:05:48 +01001475 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001476 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001477 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1478 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001479
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001480 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001481
1482 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001483 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1484 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1485 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001486 }
1487
Johan Hedberg4c659c32011-11-07 23:13:39 +02001488 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001489 rp = kmalloc(rp_len, GFP_ATOMIC);
1490 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001491 err = -ENOMEM;
1492 goto unlock;
1493 }
1494
Johan Hedberg2784eb42011-01-21 13:56:35 +02001495 put_unaligned_le16(count, &rp->conn_count);
1496
Johan Hedberg2784eb42011-01-21 13:56:35 +02001497 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001498 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001499 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1500 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001501 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001502 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001503 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1504 continue;
1505 i++;
1506 }
1507
1508 /* Recalculate length in case of filtered SCO connections, etc */
1509 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001510
Szymon Janc4e51eae2011-02-25 19:05:48 +01001511 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001512
1513unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001514 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001515 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001516 hci_dev_put(hdev);
1517 return err;
1518}
1519
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001520static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1521 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1522{
1523 struct pending_cmd *cmd;
1524 int err;
1525
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001526 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001527 sizeof(*cp));
1528 if (!cmd)
1529 return -ENOMEM;
1530
Johan Hedbergd8457692012-02-17 14:24:57 +02001531 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1532 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001533 if (err < 0)
1534 mgmt_pending_remove(cmd);
1535
1536 return err;
1537}
1538
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001539static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001540{
1541 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001542 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001543 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001544 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001545 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001546 int err;
1547
1548 BT_DBG("");
1549
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001550 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001551 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1552 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001553
Szymon Janc4e51eae2011-02-25 19:05:48 +01001554 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001555 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001556 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1557 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001558
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001559 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001560
1561 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001562 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1563 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001564 goto failed;
1565 }
1566
Johan Hedbergd8457692012-02-17 14:24:57 +02001567 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001568 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001569 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1570 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001571 goto failed;
1572 }
1573
1574 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001575 struct mgmt_cp_pin_code_neg_reply ncp;
1576
1577 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001578
1579 BT_ERR("PIN code is not 16 bytes long");
1580
1581 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1582 if (err >= 0)
1583 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001584 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001585
1586 goto failed;
1587 }
1588
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001589 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1590 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001591 if (!cmd) {
1592 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001593 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001594 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001595
Johan Hedbergd8457692012-02-17 14:24:57 +02001596 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001597 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001598 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001599
1600 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1601 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001602 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001603
1604failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001605 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001606 hci_dev_put(hdev);
1607
1608 return err;
1609}
1610
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001611static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001612{
1613 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001614 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001615 int err;
1616
1617 BT_DBG("");
1618
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001619 if (len != sizeof(*cp))
1620 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001621 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001622
Szymon Janc4e51eae2011-02-25 19:05:48 +01001623 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001624 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001625 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001626 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001627
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001628 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001629
1630 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001631 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001632 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001633 goto failed;
1634 }
1635
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001636 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001637
1638failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001639 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001640 hci_dev_put(hdev);
1641
1642 return err;
1643}
1644
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001645static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001646{
1647 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001648 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001649
1650 BT_DBG("");
1651
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001652 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001653 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1654 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001655
Szymon Janc4e51eae2011-02-25 19:05:48 +01001656 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001657 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001658 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1659 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001660
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001661 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001662
1663 hdev->io_capability = cp->io_capability;
1664
1665 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001666 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001667
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001668 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001669 hci_dev_put(hdev);
1670
Szymon Janc4e51eae2011-02-25 19:05:48 +01001671 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001672}
1673
Johan Hedberge9a416b2011-02-19 12:05:56 -03001674static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1675{
1676 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001677 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001678
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001679 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001680 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1681 continue;
1682
Johan Hedberge9a416b2011-02-19 12:05:56 -03001683 if (cmd->user_data != conn)
1684 continue;
1685
1686 return cmd;
1687 }
1688
1689 return NULL;
1690}
1691
1692static void pairing_complete(struct pending_cmd *cmd, u8 status)
1693{
1694 struct mgmt_rp_pair_device rp;
1695 struct hci_conn *conn = cmd->user_data;
1696
Johan Hedbergba4e5642011-11-11 00:07:34 +02001697 bacpy(&rp.addr.bdaddr, &conn->dst);
1698 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001699 rp.status = status;
1700
Szymon Janc4e51eae2011-02-25 19:05:48 +01001701 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001702
1703 /* So we don't get further callbacks for this connection */
1704 conn->connect_cfm_cb = NULL;
1705 conn->security_cfm_cb = NULL;
1706 conn->disconn_cfm_cb = NULL;
1707
1708 hci_conn_put(conn);
1709
Johan Hedberga664b5b2011-02-19 12:06:02 -03001710 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001711}
1712
1713static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1714{
1715 struct pending_cmd *cmd;
1716
1717 BT_DBG("status %u", status);
1718
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001719 cmd = find_pairing(conn);
1720 if (!cmd)
1721 BT_DBG("Unable to find a pending command");
1722 else
1723 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001724}
1725
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001726static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001727{
1728 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001729 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001730 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001731 struct pending_cmd *cmd;
1732 u8 sec_level, auth_type;
1733 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001734 int err;
1735
1736 BT_DBG("");
1737
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001738 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001739 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1740 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001741
Szymon Janc4e51eae2011-02-25 19:05:48 +01001742 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001743 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001744 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1745 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001746
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001747 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001748
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001749 sec_level = BT_SECURITY_MEDIUM;
1750 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001751 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001752 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001753 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001754
Johan Hedbergba4e5642011-11-11 00:07:34 +02001755 if (cp->addr.type == MGMT_ADDR_BREDR)
1756 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001757 auth_type);
1758 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001759 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001760 auth_type);
1761
Johan Hedberg1425acb2011-11-11 00:07:35 +02001762 memset(&rp, 0, sizeof(rp));
1763 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1764 rp.addr.type = cp->addr.type;
1765
Ville Tervo30e76272011-02-22 16:10:53 -03001766 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001767 rp.status = -PTR_ERR(conn);
1768 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1769 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001770 goto unlock;
1771 }
1772
1773 if (conn->connect_cfm_cb) {
1774 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001775 rp.status = EBUSY;
1776 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1777 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001778 goto unlock;
1779 }
1780
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001781 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001782 if (!cmd) {
1783 err = -ENOMEM;
1784 hci_conn_put(conn);
1785 goto unlock;
1786 }
1787
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001788 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001789 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001790 conn->connect_cfm_cb = pairing_complete_cb;
1791
Johan Hedberge9a416b2011-02-19 12:05:56 -03001792 conn->security_cfm_cb = pairing_complete_cb;
1793 conn->disconn_cfm_cb = pairing_complete_cb;
1794 conn->io_capability = cp->io_cap;
1795 cmd->user_data = conn;
1796
1797 if (conn->state == BT_CONNECTED &&
1798 hci_conn_security(conn, sec_level, auth_type))
1799 pairing_complete(cmd, 0);
1800
1801 err = 0;
1802
1803unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001804 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001805 hci_dev_put(hdev);
1806
1807 return err;
1808}
1809
Johan Hedberg28424702012-02-02 04:02:29 +02001810static int cancel_pair_device(struct sock *sk, u16 index,
1811 unsigned char *data, u16 len)
1812{
1813 struct mgmt_addr_info *addr = (void *) data;
1814 struct hci_dev *hdev;
1815 struct pending_cmd *cmd;
1816 struct hci_conn *conn;
1817 int err;
1818
1819 BT_DBG("");
1820
1821 if (len != sizeof(*addr))
1822 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1823 MGMT_STATUS_INVALID_PARAMS);
1824
1825 hdev = hci_dev_get(index);
1826 if (!hdev)
1827 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1828 MGMT_STATUS_INVALID_PARAMS);
1829
1830 hci_dev_lock(hdev);
1831
1832 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1833 if (!cmd) {
1834 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1835 MGMT_STATUS_INVALID_PARAMS);
1836 goto unlock;
1837 }
1838
1839 conn = cmd->user_data;
1840
1841 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1842 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1843 MGMT_STATUS_INVALID_PARAMS);
1844 goto unlock;
1845 }
1846
1847 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1848
1849 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr,
1850 sizeof(*addr));
1851unlock:
1852 hci_dev_unlock(hdev);
1853 hci_dev_put(hdev);
1854
1855 return err;
1856}
1857
Brian Gix0df4c182011-11-16 13:53:13 -08001858static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001859 u8 type, u16 mgmt_op, u16 hci_op,
1860 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001861{
Johan Hedberga5c29682011-02-19 12:05:57 -03001862 struct pending_cmd *cmd;
1863 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001864 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001865 int err;
1866
Szymon Janc4e51eae2011-02-25 19:05:48 +01001867 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001868 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001869 return cmd_status(sk, index, mgmt_op,
1870 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001871
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001872 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001873
Johan Hedberga5c29682011-02-19 12:05:57 -03001874 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001875 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1876 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001877 }
1878
Johan Hedberg272d90d2012-02-09 15:26:12 +02001879 if (type == MGMT_ADDR_BREDR)
1880 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1881 else
Brian Gix47c15e22011-11-16 13:53:14 -08001882 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001883
Johan Hedberg272d90d2012-02-09 15:26:12 +02001884 if (!conn) {
1885 err = cmd_status(sk, index, mgmt_op,
1886 MGMT_STATUS_NOT_CONNECTED);
1887 goto done;
1888 }
1889
1890 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001891 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001892 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001893
Brian Gix5fe57d92011-12-21 16:12:13 -08001894 if (!err)
1895 err = cmd_status(sk, index, mgmt_op,
1896 MGMT_STATUS_SUCCESS);
1897 else
1898 err = cmd_status(sk, index, mgmt_op,
1899 MGMT_STATUS_FAILED);
1900
Brian Gix47c15e22011-11-16 13:53:14 -08001901 goto done;
1902 }
1903
Brian Gix0df4c182011-11-16 13:53:13 -08001904 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001905 if (!cmd) {
1906 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001907 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001908 }
1909
Brian Gix0df4c182011-11-16 13:53:13 -08001910 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001911 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1912 struct hci_cp_user_passkey_reply cp;
1913
1914 bacpy(&cp.bdaddr, bdaddr);
1915 cp.passkey = passkey;
1916 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1917 } else
1918 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1919
Johan Hedberga664b5b2011-02-19 12:06:02 -03001920 if (err < 0)
1921 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001922
Brian Gix0df4c182011-11-16 13:53:13 -08001923done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001924 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001925 hci_dev_put(hdev);
1926
1927 return err;
1928}
1929
Brian Gix0df4c182011-11-16 13:53:13 -08001930static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1931{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001932 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001933
1934 BT_DBG("");
1935
1936 if (len != sizeof(*cp))
1937 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1938 MGMT_STATUS_INVALID_PARAMS);
1939
Johan Hedberg272d90d2012-02-09 15:26:12 +02001940 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1941 MGMT_OP_USER_CONFIRM_REPLY,
1942 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001943}
1944
1945static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1946 u16 len)
1947{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001948 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001949
1950 BT_DBG("");
1951
1952 if (len != sizeof(*cp))
1953 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1954 MGMT_STATUS_INVALID_PARAMS);
1955
Johan Hedberg272d90d2012-02-09 15:26:12 +02001956 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1957 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1958 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001959}
1960
Brian Gix604086b2011-11-23 08:28:33 -08001961static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1962{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001963 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001964
1965 BT_DBG("");
1966
1967 if (len != sizeof(*cp))
1968 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1969 EINVAL);
1970
Johan Hedberg272d90d2012-02-09 15:26:12 +02001971 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1972 MGMT_OP_USER_PASSKEY_REPLY,
1973 HCI_OP_USER_PASSKEY_REPLY,
1974 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08001975}
1976
1977static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1978 u16 len)
1979{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001980 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001981
1982 BT_DBG("");
1983
1984 if (len != sizeof(*cp))
1985 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1986 EINVAL);
1987
Johan Hedberg272d90d2012-02-09 15:26:12 +02001988 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1989 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1990 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08001991}
1992
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001993static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02001994 u16 len)
1995{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001996 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001997 struct hci_cp_write_local_name hci_cp;
1998 struct hci_dev *hdev;
1999 struct pending_cmd *cmd;
2000 int err;
2001
2002 BT_DBG("");
2003
2004 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002005 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2006 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002007
2008 hdev = hci_dev_get(index);
2009 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002010 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2011 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002012
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002013 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002014
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002015 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2016 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002017 if (!cmd) {
2018 err = -ENOMEM;
2019 goto failed;
2020 }
2021
2022 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2023 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2024 &hci_cp);
2025 if (err < 0)
2026 mgmt_pending_remove(cmd);
2027
2028failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002029 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002030 hci_dev_put(hdev);
2031
2032 return err;
2033}
2034
Szymon Jancc35938b2011-03-22 13:12:21 +01002035static int read_local_oob_data(struct sock *sk, u16 index)
2036{
2037 struct hci_dev *hdev;
2038 struct pending_cmd *cmd;
2039 int err;
2040
2041 BT_DBG("hci%u", index);
2042
2043 hdev = hci_dev_get(index);
2044 if (!hdev)
2045 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002046 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002047
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002048 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002049
2050 if (!test_bit(HCI_UP, &hdev->flags)) {
2051 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002052 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002053 goto unlock;
2054 }
2055
2056 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2057 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002058 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002059 goto unlock;
2060 }
2061
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002062 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002063 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2064 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002065 goto unlock;
2066 }
2067
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002068 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002069 if (!cmd) {
2070 err = -ENOMEM;
2071 goto unlock;
2072 }
2073
2074 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2075 if (err < 0)
2076 mgmt_pending_remove(cmd);
2077
2078unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002079 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002080 hci_dev_put(hdev);
2081
2082 return err;
2083}
2084
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002085static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2086 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002087{
2088 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002089 struct mgmt_cp_add_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01002090 int err;
2091
2092 BT_DBG("hci%u ", index);
2093
2094 if (len != sizeof(*cp))
2095 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002096 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002097
2098 hdev = hci_dev_get(index);
2099 if (!hdev)
2100 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002101 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002102
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002103 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002104
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002105 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002106 cp->randomizer);
2107 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002108 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2109 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01002110 else
2111 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2112 0);
2113
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002114 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002115 hci_dev_put(hdev);
2116
2117 return err;
2118}
2119
2120static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002121 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002122{
2123 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002124 struct mgmt_cp_remove_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01002125 int err;
2126
2127 BT_DBG("hci%u ", index);
2128
2129 if (len != sizeof(*cp))
2130 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002131 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002132
2133 hdev = hci_dev_get(index);
2134 if (!hdev)
2135 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002136 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002137
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002138 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002139
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002140 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002141 if (err < 0)
2142 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002143 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002144 else
2145 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2146 NULL, 0);
2147
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002148 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002149 hci_dev_put(hdev);
2150
2151 return err;
2152}
2153
Johan Hedberg450dfda2011-11-12 11:58:22 +02002154static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002155 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002156{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002157 struct mgmt_cp_start_discovery *cp = data;
Andre Guedes3fd24152012-02-03 17:48:01 -03002158 unsigned long discov_type = cp->type;
Johan Hedberg14a53662011-04-27 10:29:56 -04002159 struct pending_cmd *cmd;
2160 struct hci_dev *hdev;
2161 int err;
2162
2163 BT_DBG("hci%u", index);
2164
Johan Hedberg450dfda2011-11-12 11:58:22 +02002165 if (len != sizeof(*cp))
2166 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2167 MGMT_STATUS_INVALID_PARAMS);
2168
Johan Hedberg14a53662011-04-27 10:29:56 -04002169 hdev = hci_dev_get(index);
2170 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002171 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2172 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002173
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002174 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002175
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002176 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002177 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2178 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002179 goto failed;
2180 }
2181
Johan Hedbergff9ef572012-01-04 14:23:45 +02002182 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2183 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2184 MGMT_STATUS_BUSY);
2185 goto failed;
2186 }
2187
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002188 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002189 if (!cmd) {
2190 err = -ENOMEM;
2191 goto failed;
2192 }
2193
Andre Guedes3fd24152012-02-03 17:48:01 -03002194 if (test_bit(MGMT_ADDR_BREDR, &discov_type))
2195 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2196 else if (test_bit(MGMT_ADDR_LE_PUBLIC, &discov_type) &&
2197 test_bit(MGMT_ADDR_LE_RANDOM, &discov_type))
2198 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2199 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
2200 else
2201 err = -EINVAL;
2202
Johan Hedberg14a53662011-04-27 10:29:56 -04002203 if (err < 0)
2204 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002205 else
2206 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002207
2208failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002209 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002210 hci_dev_put(hdev);
2211
2212 return err;
2213}
2214
2215static int stop_discovery(struct sock *sk, u16 index)
2216{
2217 struct hci_dev *hdev;
2218 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002219 struct hci_cp_remote_name_req_cancel cp;
2220 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002221 int err;
2222
2223 BT_DBG("hci%u", index);
2224
2225 hdev = hci_dev_get(index);
2226 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002227 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2228 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002229
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002230 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002231
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002232 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002233 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2234 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002235 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002236 }
2237
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002238 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002239 if (!cmd) {
2240 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002241 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002242 }
2243
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002244 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
2245 err = hci_cancel_inquiry(hdev);
2246 if (err < 0)
2247 mgmt_pending_remove(cmd);
2248 else
2249 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2250 goto unlock;
2251 }
2252
2253 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2254 if (!e) {
2255 mgmt_pending_remove(cmd);
2256 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2257 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2258 goto unlock;
2259 }
2260
2261 bacpy(&cp.bdaddr, &e->data.bdaddr);
2262 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2263 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002264 if (err < 0)
2265 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002266 else
2267 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002268
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002269unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002270 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002271 hci_dev_put(hdev);
2272
2273 return err;
2274}
2275
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002276static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002277{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002278 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002279 struct inquiry_entry *e;
2280 struct hci_dev *hdev;
2281 int err;
2282
2283 BT_DBG("hci%u", index);
2284
2285 if (len != sizeof(*cp))
2286 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2287 MGMT_STATUS_INVALID_PARAMS);
2288
2289 hdev = hci_dev_get(index);
2290 if (!hdev)
2291 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2292 MGMT_STATUS_INVALID_PARAMS);
2293
2294 hci_dev_lock(hdev);
2295
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002296 if (!hci_discovery_active(hdev)) {
2297 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2298 MGMT_STATUS_FAILED);
2299 goto failed;
2300 }
2301
Johan Hedberga198e7b2012-02-17 14:27:06 +02002302 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002303 if (!e) {
2304 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2305 MGMT_STATUS_INVALID_PARAMS);
2306 goto failed;
2307 }
2308
2309 if (cp->name_known) {
2310 e->name_state = NAME_KNOWN;
2311 list_del(&e->list);
2312 } else {
2313 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002314 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002315 }
2316
2317 err = 0;
2318
2319failed:
2320 hci_dev_unlock(hdev);
2321
2322 return err;
2323}
2324
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002325static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002326{
2327 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002328 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002329 int err;
2330
2331 BT_DBG("hci%u", index);
2332
Antti Julku7fbec222011-06-15 12:01:15 +03002333 if (len != sizeof(*cp))
2334 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002335 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002336
2337 hdev = hci_dev_get(index);
2338 if (!hdev)
2339 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002340 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002341
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002342 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002343
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002344 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002345 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002346 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2347 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002348 else
2349 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2350 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002351
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002352 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002353 hci_dev_put(hdev);
2354
2355 return err;
2356}
2357
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002358static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002359{
2360 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002361 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002362 int err;
2363
2364 BT_DBG("hci%u", index);
2365
Antti Julku7fbec222011-06-15 12:01:15 +03002366 if (len != sizeof(*cp))
2367 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002368 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002369
2370 hdev = hci_dev_get(index);
2371 if (!hdev)
2372 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002373 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002374
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002375 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002376
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002377 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002378
2379 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002380 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2381 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002382 else
2383 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2384 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002385
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002386 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002387 hci_dev_put(hdev);
2388
2389 return err;
2390}
2391
Antti Julkuf6422ec2011-06-22 13:11:56 +03002392static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002393 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002394{
2395 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002396 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002397 struct hci_cp_write_page_scan_activity acp;
2398 u8 type;
2399 int err;
2400
2401 BT_DBG("hci%u", index);
2402
2403 if (len != sizeof(*cp))
2404 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002405 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002406
2407 hdev = hci_dev_get(index);
2408 if (!hdev)
2409 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002410 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002411
2412 hci_dev_lock(hdev);
2413
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002414 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002415 type = PAGE_SCAN_TYPE_INTERLACED;
2416 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2417 } else {
2418 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2419 acp.interval = 0x0800; /* default 1.28 sec page scan */
2420 }
2421
2422 acp.window = 0x0012; /* default 11.25 msec page scan window */
2423
2424 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2425 sizeof(acp), &acp);
2426 if (err < 0) {
2427 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002428 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002429 goto done;
2430 }
2431
2432 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2433 if (err < 0) {
2434 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002435 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002436 goto done;
2437 }
2438
2439 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2440 NULL, 0);
2441done:
2442 hci_dev_unlock(hdev);
2443 hci_dev_put(hdev);
2444
2445 return err;
2446}
2447
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002448static int load_long_term_keys(struct sock *sk, u16 index,
2449 void *cp_data, u16 len)
2450{
2451 struct hci_dev *hdev;
2452 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2453 u16 key_count, expected_len;
2454 int i;
2455
2456 if (len < sizeof(*cp))
2457 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2458 EINVAL);
2459
2460 key_count = get_unaligned_le16(&cp->key_count);
2461
2462 expected_len = sizeof(*cp) + key_count *
2463 sizeof(struct mgmt_ltk_info);
2464 if (expected_len != len) {
2465 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2466 len, expected_len);
2467 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2468 EINVAL);
2469 }
2470
2471 hdev = hci_dev_get(index);
2472 if (!hdev)
2473 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2474 ENODEV);
2475
2476 BT_DBG("hci%u key_count %u", index, key_count);
2477
2478 hci_dev_lock(hdev);
2479
2480 hci_smp_ltks_clear(hdev);
2481
2482 for (i = 0; i < key_count; i++) {
2483 struct mgmt_ltk_info *key = &cp->keys[i];
2484 u8 type;
2485
2486 if (key->master)
2487 type = HCI_SMP_LTK;
2488 else
2489 type = HCI_SMP_LTK_SLAVE;
2490
2491 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2492 type, 0, key->authenticated, key->val,
2493 key->enc_size, key->ediv, key->rand);
2494 }
2495
2496 hci_dev_unlock(hdev);
2497 hci_dev_put(hdev);
2498
2499 return 0;
2500}
2501
Johan Hedberg03811012010-12-08 00:21:06 +02002502int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2503{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002504 void *buf;
2505 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002506 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002507 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002508 int err;
2509
2510 BT_DBG("got %zu bytes", msglen);
2511
2512 if (msglen < sizeof(*hdr))
2513 return -EINVAL;
2514
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002515 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002516 if (!buf)
2517 return -ENOMEM;
2518
2519 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2520 err = -EFAULT;
2521 goto done;
2522 }
2523
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002524 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002525 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002526 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002527 len = get_unaligned_le16(&hdr->len);
2528
2529 if (len != msglen - sizeof(*hdr)) {
2530 err = -EINVAL;
2531 goto done;
2532 }
2533
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002534 cp = buf + sizeof(*hdr);
2535
Johan Hedberg03811012010-12-08 00:21:06 +02002536 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002537 case MGMT_OP_READ_VERSION:
2538 err = read_version(sk);
2539 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002540 case MGMT_OP_READ_COMMANDS:
2541 err = read_commands(sk);
2542 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002543 case MGMT_OP_READ_INDEX_LIST:
2544 err = read_index_list(sk);
2545 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002546 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002547 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002548 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002549 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002550 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002551 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002552 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002553 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002554 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002555 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002556 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002557 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002558 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002559 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002560 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002561 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002562 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002563 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002564 case MGMT_OP_SET_LINK_SECURITY:
2565 err = set_link_security(sk, index, cp, len);
2566 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002567 case MGMT_OP_SET_SSP:
2568 err = set_ssp(sk, index, cp, len);
2569 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002570 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002571 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002572 break;
2573 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002574 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002575 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002576 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002577 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002578 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002579 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002580 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002581 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002582 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002583 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002584 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002585 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002586 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002587 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002588 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002589 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002590 break;
2591 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002592 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002593 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002594 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002595 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002596 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002597 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002598 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002599 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002600 case MGMT_OP_CANCEL_PAIR_DEVICE:
2601 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2602 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002603 case MGMT_OP_UNPAIR_DEVICE:
2604 err = unpair_device(sk, index, cp, len);
2605 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002606 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002607 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002608 break;
2609 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002610 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002611 break;
Brian Gix604086b2011-11-23 08:28:33 -08002612 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002613 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002614 break;
2615 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002616 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002617 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002618 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002619 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002620 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002621 case MGMT_OP_READ_LOCAL_OOB_DATA:
2622 err = read_local_oob_data(sk, index);
2623 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002624 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002625 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002626 break;
2627 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002628 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002629 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002630 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002631 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002632 break;
2633 case MGMT_OP_STOP_DISCOVERY:
2634 err = stop_discovery(sk, index);
2635 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002636 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002637 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002638 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002639 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002640 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002641 break;
2642 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002643 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002644 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002645 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2646 err = load_long_term_keys(sk, index, cp, len);
2647 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002648 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002649 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002650 err = cmd_status(sk, index, opcode,
2651 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002652 break;
2653 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002654
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002655 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002656 goto done;
2657
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002658 err = msglen;
2659
2660done:
2661 kfree(buf);
2662 return err;
2663}
2664
Johan Hedbergb24752f2011-11-03 14:40:33 +02002665static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2666{
2667 u8 *status = data;
2668
2669 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2670 mgmt_pending_remove(cmd);
2671}
2672
Johan Hedberg744cf192011-11-08 20:40:14 +02002673int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002674{
Johan Hedberg744cf192011-11-08 20:40:14 +02002675 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002676}
2677
Johan Hedberg744cf192011-11-08 20:40:14 +02002678int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002679{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002680 u8 status = ENODEV;
2681
Johan Hedberg744cf192011-11-08 20:40:14 +02002682 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002683
Johan Hedberg744cf192011-11-08 20:40:14 +02002684 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002685}
2686
2687struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002688 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002689 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002690};
2691
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002692static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002693{
Johan Hedberg03811012010-12-08 00:21:06 +02002694 struct cmd_lookup *match = data;
2695
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002696 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002697
2698 list_del(&cmd->list);
2699
2700 if (match->sk == NULL) {
2701 match->sk = cmd->sk;
2702 sock_hold(match->sk);
2703 }
2704
2705 mgmt_pending_free(cmd);
2706}
2707
Johan Hedberg744cf192011-11-08 20:40:14 +02002708int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002709{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002710 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002711 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002712 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002713
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002714 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002715
Johan Hedbergb24752f2011-11-03 14:40:33 +02002716 if (!powered) {
2717 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002718 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002719 }
2720
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002721 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002722
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002723 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002724 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002725
2726 if (match.sk)
2727 sock_put(match.sk);
2728
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002729 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002730}
2731
Johan Hedberg744cf192011-11-08 20:40:14 +02002732int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002733{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002734 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002735 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002736 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002737
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002738 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002739
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002740 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002741
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002742 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002743 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002744 if (match.sk)
2745 sock_put(match.sk);
2746
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002747 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002748}
2749
Johan Hedberg744cf192011-11-08 20:40:14 +02002750int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002751{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002752 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002753 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002754 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002755
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002756 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2757 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002758
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002759 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002760
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002761 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002762
2763 if (match.sk)
2764 sock_put(match.sk);
2765
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002766 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002767}
2768
Johan Hedberg744cf192011-11-08 20:40:14 +02002769int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002770{
Johan Hedbergca69b792011-11-11 18:10:00 +02002771 u8 mgmt_err = mgmt_status(status);
2772
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002773 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002774 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002775 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002776
2777 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002778 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002779 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002780
2781 return 0;
2782}
2783
Johan Hedberg744cf192011-11-08 20:40:14 +02002784int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2785 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002786{
Johan Hedberg86742e12011-11-07 23:13:38 +02002787 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002788
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002789 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002790
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002791 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002792 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2793 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002794 ev.key.type = key->type;
2795 memcpy(ev.key.val, key->val, 16);
2796 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002797
Johan Hedberg744cf192011-11-08 20:40:14 +02002798 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002799}
Johan Hedbergf7520542011-01-20 12:34:39 +02002800
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002801int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2802{
2803 struct mgmt_ev_new_long_term_key ev;
2804
2805 memset(&ev, 0, sizeof(ev));
2806
2807 ev.store_hint = persistent;
2808 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2809 ev.key.addr.type = key->bdaddr_type;
2810 ev.key.authenticated = key->authenticated;
2811 ev.key.enc_size = key->enc_size;
2812 ev.key.ediv = key->ediv;
2813
2814 if (key->type == HCI_SMP_LTK)
2815 ev.key.master = 1;
2816
2817 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2818 memcpy(ev.key.val, key->val, sizeof(key->val));
2819
2820 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2821 &ev, sizeof(ev), NULL);
2822}
2823
Johan Hedbergafc747a2012-01-15 18:11:07 +02002824int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002825 u8 addr_type, u8 *name, u8 name_len,
2826 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002827{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002828 char buf[512];
2829 struct mgmt_ev_device_connected *ev = (void *) buf;
2830 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002831
Johan Hedbergb644ba32012-01-17 21:48:47 +02002832 bacpy(&ev->addr.bdaddr, bdaddr);
2833 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002834
Johan Hedbergb644ba32012-01-17 21:48:47 +02002835 if (name_len > 0)
2836 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2837 name, name_len);
2838
2839 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2840 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2841 EIR_CLASS_OF_DEV, dev_class, 3);
2842
2843 put_unaligned_le16(eir_len, &ev->eir_len);
2844
2845 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2846 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002847}
2848
Johan Hedberg8962ee72011-01-20 12:40:27 +02002849static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2850{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002851 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002852 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002853 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002854
Johan Hedberg88c3df12012-02-09 14:27:38 +02002855 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2856 rp.addr.type = cp->addr.type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002857 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002858
Szymon Janc4e51eae2011-02-25 19:05:48 +01002859 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002860
2861 *sk = cmd->sk;
2862 sock_hold(*sk);
2863
Johan Hedberga664b5b2011-02-19 12:06:02 -03002864 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002865}
2866
Johan Hedberg124f6e32012-02-09 13:50:12 +02002867static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002868{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002869 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002870 struct mgmt_cp_unpair_device *cp = cmd->param;
2871 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002872
2873 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002874 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2875 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002876
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002877 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2878
2879 cmd_complete(cmd->sk, cmd->index, cmd->opcode, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002880
2881 mgmt_pending_remove(cmd);
2882}
2883
Johan Hedbergafc747a2012-01-15 18:11:07 +02002884int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2885 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002886{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002887 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002888 struct sock *sk = NULL;
2889 int err;
2890
Johan Hedberg744cf192011-11-08 20:40:14 +02002891 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002892
Johan Hedbergf7520542011-01-20 12:34:39 +02002893 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002894 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002895
Johan Hedbergafc747a2012-01-15 18:11:07 +02002896 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2897 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002898
2899 if (sk)
2900 sock_put(sk);
2901
Johan Hedberg124f6e32012-02-09 13:50:12 +02002902 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002903 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002904
Johan Hedberg8962ee72011-01-20 12:40:27 +02002905 return err;
2906}
2907
Johan Hedberg88c3df12012-02-09 14:27:38 +02002908int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
2909 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002910{
Johan Hedberg88c3df12012-02-09 14:27:38 +02002911 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002912 struct pending_cmd *cmd;
2913 int err;
2914
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002915 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002916 if (!cmd)
2917 return -ENOENT;
2918
Johan Hedberg88c3df12012-02-09 14:27:38 +02002919 bacpy(&rp.addr.bdaddr, bdaddr);
2920 rp.addr.type = link_to_mgmt(link_type, addr_type);
2921 rp.status = mgmt_status(status);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002922
Johan Hedberg88c3df12012-02-09 14:27:38 +02002923 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002924 &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002925
Johan Hedberga664b5b2011-02-19 12:06:02 -03002926 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002927
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002928 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
2929 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002930 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002931}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002932
Johan Hedberg48264f02011-11-09 13:58:58 +02002933int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2934 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002935{
2936 struct mgmt_ev_connect_failed ev;
2937
Johan Hedberg4c659c32011-11-07 23:13:39 +02002938 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002939 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002940 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002941
Johan Hedberg744cf192011-11-08 20:40:14 +02002942 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002943}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002944
Johan Hedberg744cf192011-11-08 20:40:14 +02002945int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002946{
2947 struct mgmt_ev_pin_code_request ev;
2948
Johan Hedbergd8457692012-02-17 14:24:57 +02002949 bacpy(&ev.addr.bdaddr, bdaddr);
2950 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002951 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002952
Johan Hedberg744cf192011-11-08 20:40:14 +02002953 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002954 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002955}
2956
Johan Hedberg744cf192011-11-08 20:40:14 +02002957int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2958 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002959{
2960 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002961 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002962 int err;
2963
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002964 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002965 if (!cmd)
2966 return -ENOENT;
2967
Johan Hedbergd8457692012-02-17 14:24:57 +02002968 bacpy(&rp.addr.bdaddr, bdaddr);
2969 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergca69b792011-11-11 18:10:00 +02002970 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002971
Johan Hedberg744cf192011-11-08 20:40:14 +02002972 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002973 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002974
Johan Hedberga664b5b2011-02-19 12:06:02 -03002975 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002976
2977 return err;
2978}
2979
Johan Hedberg744cf192011-11-08 20:40:14 +02002980int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2981 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002982{
2983 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002984 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002985 int err;
2986
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002987 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002988 if (!cmd)
2989 return -ENOENT;
2990
Johan Hedbergd8457692012-02-17 14:24:57 +02002991 bacpy(&rp.addr.bdaddr, bdaddr);
2992 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergca69b792011-11-11 18:10:00 +02002993 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002994
Johan Hedberg744cf192011-11-08 20:40:14 +02002995 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002996 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002997
Johan Hedberga664b5b2011-02-19 12:06:02 -03002998 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002999
3000 return err;
3001}
Johan Hedberga5c29682011-02-19 12:05:57 -03003002
Johan Hedberg744cf192011-11-08 20:40:14 +02003003int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003004 u8 link_type, u8 addr_type, __le32 value,
3005 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003006{
3007 struct mgmt_ev_user_confirm_request ev;
3008
Johan Hedberg744cf192011-11-08 20:40:14 +02003009 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003010
Johan Hedberg272d90d2012-02-09 15:26:12 +02003011 bacpy(&ev.addr.bdaddr, bdaddr);
3012 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003013 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003014 put_unaligned_le32(value, &ev.value);
3015
Johan Hedberg744cf192011-11-08 20:40:14 +02003016 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003017 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003018}
3019
Johan Hedberg272d90d2012-02-09 15:26:12 +02003020int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3021 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003022{
3023 struct mgmt_ev_user_passkey_request ev;
3024
3025 BT_DBG("%s", hdev->name);
3026
Johan Hedberg272d90d2012-02-09 15:26:12 +02003027 bacpy(&ev.addr.bdaddr, bdaddr);
3028 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003029
3030 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3031 NULL);
3032}
3033
Brian Gix0df4c182011-11-16 13:53:13 -08003034static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003035 u8 link_type, u8 addr_type, u8 status,
3036 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003037{
3038 struct pending_cmd *cmd;
3039 struct mgmt_rp_user_confirm_reply rp;
3040 int err;
3041
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003042 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003043 if (!cmd)
3044 return -ENOENT;
3045
Johan Hedberg272d90d2012-02-09 15:26:12 +02003046 bacpy(&rp.addr.bdaddr, bdaddr);
3047 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003048 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02003049 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003050
Johan Hedberga664b5b2011-02-19 12:06:02 -03003051 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003052
3053 return err;
3054}
3055
Johan Hedberg744cf192011-11-08 20:40:14 +02003056int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003057 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003058{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003059 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3060 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003061}
3062
Johan Hedberg272d90d2012-02-09 15:26:12 +02003063int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3064 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003065{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003066 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3067 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003068}
Johan Hedberg2a611692011-02-19 12:06:00 -03003069
Brian Gix604086b2011-11-23 08:28:33 -08003070int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003071 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003072{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003073 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3074 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003075}
3076
Johan Hedberg272d90d2012-02-09 15:26:12 +02003077int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3078 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003079{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003080 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3081 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003082}
3083
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003084int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3085 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003086{
3087 struct mgmt_ev_auth_failed ev;
3088
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003089 bacpy(&ev.addr.bdaddr, bdaddr);
3090 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003091 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003092
Johan Hedberg744cf192011-11-08 20:40:14 +02003093 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003094}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003095
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003096int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3097{
3098 struct cmd_lookup match = { NULL, hdev };
3099 __le32 ev;
3100 int err;
3101
3102 if (status) {
3103 u8 mgmt_err = mgmt_status(status);
3104 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3105 cmd_status_rsp, &mgmt_err);
3106 return 0;
3107 }
3108
3109 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3110 &match);
3111
3112 ev = cpu_to_le32(get_current_settings(hdev));
3113 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3114
3115 if (match.sk)
3116 sock_put(match.sk);
3117
3118 return err;
3119}
3120
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003121int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3122{
3123 struct cmd_lookup match = { NULL, hdev };
3124 __le32 ev;
3125 int err;
3126
3127 if (status) {
3128 u8 mgmt_err = mgmt_status(status);
3129 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3130 cmd_status_rsp, &mgmt_err);
3131 return 0;
3132 }
3133
3134 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3135
3136 ev = cpu_to_le32(get_current_settings(hdev));
3137 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3138
3139 if (match.sk)
3140 sock_put(match.sk);
3141
3142 return err;
3143}
3144
Johan Hedberg744cf192011-11-08 20:40:14 +02003145int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003146{
3147 struct pending_cmd *cmd;
3148 struct mgmt_cp_set_local_name ev;
3149 int err;
3150
3151 memset(&ev, 0, sizeof(ev));
3152 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3153
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003154 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003155 if (!cmd)
3156 goto send_event;
3157
3158 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003159 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003160 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003161 goto failed;
3162 }
3163
Johan Hedberg744cf192011-11-08 20:40:14 +02003164 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003165
Johan Hedberg744cf192011-11-08 20:40:14 +02003166 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003167 sizeof(ev));
3168 if (err < 0)
3169 goto failed;
3170
3171send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003172 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003173 cmd ? cmd->sk : NULL);
3174
3175failed:
3176 if (cmd)
3177 mgmt_pending_remove(cmd);
3178 return err;
3179}
Szymon Jancc35938b2011-03-22 13:12:21 +01003180
Johan Hedberg744cf192011-11-08 20:40:14 +02003181int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3182 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003183{
3184 struct pending_cmd *cmd;
3185 int err;
3186
Johan Hedberg744cf192011-11-08 20:40:14 +02003187 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003188
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003189 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003190 if (!cmd)
3191 return -ENOENT;
3192
3193 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003194 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003195 MGMT_OP_READ_LOCAL_OOB_DATA,
3196 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003197 } else {
3198 struct mgmt_rp_read_local_oob_data rp;
3199
3200 memcpy(rp.hash, hash, sizeof(rp.hash));
3201 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3202
Johan Hedberg744cf192011-11-08 20:40:14 +02003203 err = cmd_complete(cmd->sk, hdev->id,
3204 MGMT_OP_READ_LOCAL_OOB_DATA,
3205 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003206 }
3207
3208 mgmt_pending_remove(cmd);
3209
3210 return err;
3211}
Johan Hedberge17acd42011-03-30 23:57:16 +03003212
Johan Hedberg48264f02011-11-09 13:58:58 +02003213int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003214 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003215 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003216{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003217 char buf[512];
3218 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003219 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003220
Johan Hedberg1dc06092012-01-15 21:01:23 +02003221 /* Leave 5 bytes for a potential CoD field */
3222 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003223 return -EINVAL;
3224
Johan Hedberg1dc06092012-01-15 21:01:23 +02003225 memset(buf, 0, sizeof(buf));
3226
Johan Hedberge319d2e2012-01-15 19:51:59 +02003227 bacpy(&ev->addr.bdaddr, bdaddr);
3228 ev->addr.type = link_to_mgmt(link_type, addr_type);
3229 ev->rssi = rssi;
3230 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003231
Johan Hedberg1dc06092012-01-15 21:01:23 +02003232 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003233 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003234
Johan Hedberg1dc06092012-01-15 21:01:23 +02003235 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3236 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3237 dev_class, 3);
3238
3239 put_unaligned_le16(eir_len, &ev->eir_len);
3240
3241 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003242
Johan Hedberge319d2e2012-01-15 19:51:59 +02003243 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003244}
Johan Hedberga88a9652011-03-30 13:18:12 +03003245
Johan Hedbergb644ba32012-01-17 21:48:47 +02003246int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3247 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003248{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003249 struct mgmt_ev_device_found *ev;
3250 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3251 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003252
Johan Hedbergb644ba32012-01-17 21:48:47 +02003253 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003254
Johan Hedbergb644ba32012-01-17 21:48:47 +02003255 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003256
Johan Hedbergb644ba32012-01-17 21:48:47 +02003257 bacpy(&ev->addr.bdaddr, bdaddr);
3258 ev->addr.type = link_to_mgmt(link_type, addr_type);
3259 ev->rssi = rssi;
3260
3261 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3262 name_len);
3263
3264 put_unaligned_le16(eir_len, &ev->eir_len);
3265
Johan Hedberg053c7e02012-02-04 00:06:00 +02003266 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3267 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003268}
Johan Hedberg314b2382011-04-27 10:29:57 -04003269
Andre Guedes7a135102011-11-09 17:14:25 -03003270int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003271{
3272 struct pending_cmd *cmd;
3273 int err;
3274
Andre Guedes203159d2012-02-13 15:41:01 -03003275 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3276
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003277 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003278 if (!cmd)
3279 return -ENOENT;
3280
Johan Hedbergca69b792011-11-11 18:10:00 +02003281 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003282 mgmt_pending_remove(cmd);
3283
3284 return err;
3285}
3286
Andre Guedese6d465c2011-11-09 17:14:26 -03003287int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3288{
3289 struct pending_cmd *cmd;
3290 int err;
3291
3292 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3293 if (!cmd)
3294 return -ENOENT;
3295
Andre Guedese75a8b0c2012-01-02 16:50:53 -03003296 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02003297 mgmt_pending_remove(cmd);
3298
3299 return err;
3300}
Johan Hedberg314b2382011-04-27 10:29:57 -04003301
Johan Hedberg744cf192011-11-08 20:40:14 +02003302int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003303{
Johan Hedberg164a6e72011-11-01 17:06:44 +02003304 struct pending_cmd *cmd;
3305
Andre Guedes343fb142011-11-22 17:14:19 -03003306 BT_DBG("%s discovering %u", hdev->name, discovering);
3307
Johan Hedberg164a6e72011-11-01 17:06:44 +02003308 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003309 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003310 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003311 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003312
3313 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003314 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003315 mgmt_pending_remove(cmd);
3316 }
3317
Johan Hedberg744cf192011-11-08 20:40:14 +02003318 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04003319 sizeof(discovering), NULL);
3320}
Antti Julku5e762442011-08-25 16:48:02 +03003321
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003322int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003323{
3324 struct pending_cmd *cmd;
3325 struct mgmt_ev_device_blocked ev;
3326
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003327 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003328
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003329 bacpy(&ev.addr.bdaddr, bdaddr);
3330 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003331
Johan Hedberg744cf192011-11-08 20:40:14 +02003332 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3333 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003334}
3335
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003336int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003337{
3338 struct pending_cmd *cmd;
3339 struct mgmt_ev_device_unblocked ev;
3340
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003341 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003342
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003343 bacpy(&ev.addr.bdaddr, bdaddr);
3344 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003345
Johan Hedberg744cf192011-11-08 20:40:14 +02003346 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3347 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003348}