blob: b0de7194249ef68f8e565639ce528c11c31829b9 [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
1531 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1532 &cp->bdaddr);
1533 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;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001544 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001545 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001546 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001547 int err;
1548
1549 BT_DBG("");
1550
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001551 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001552 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1553 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001554
Szymon Janc4e51eae2011-02-25 19:05:48 +01001555 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001556 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001557 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1558 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001559
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001560 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001561
1562 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001563 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1564 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001565 goto failed;
1566 }
1567
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001568 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1569 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001570 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1571 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001572 goto failed;
1573 }
1574
1575 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1576 bacpy(&ncp.bdaddr, &cp->bdaddr);
1577
1578 BT_ERR("PIN code is not 16 bytes long");
1579
1580 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1581 if (err >= 0)
1582 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001583 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001584
1585 goto failed;
1586 }
1587
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001588 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1589 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001590 if (!cmd) {
1591 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001592 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001593 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001594
1595 bacpy(&reply.bdaddr, &cp->bdaddr);
1596 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001597 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001598
1599 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1600 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001601 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001602
1603failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001604 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001605 hci_dev_put(hdev);
1606
1607 return err;
1608}
1609
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001610static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001611{
1612 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001613 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001614 int err;
1615
1616 BT_DBG("");
1617
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001618 if (len != sizeof(*cp))
1619 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001620 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001621
Szymon Janc4e51eae2011-02-25 19:05:48 +01001622 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001623 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001624 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001625 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001626
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001627 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001628
1629 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001630 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001631 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001632 goto failed;
1633 }
1634
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001635 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001636
1637failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001638 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001639 hci_dev_put(hdev);
1640
1641 return err;
1642}
1643
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001644static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001645{
1646 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001647 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001648
1649 BT_DBG("");
1650
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001651 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001652 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1653 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001654
Szymon Janc4e51eae2011-02-25 19:05:48 +01001655 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001656 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001657 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1658 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001659
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001660 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001661
1662 hdev->io_capability = cp->io_capability;
1663
1664 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001665 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001666
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001667 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001668 hci_dev_put(hdev);
1669
Szymon Janc4e51eae2011-02-25 19:05:48 +01001670 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001671}
1672
Johan Hedberge9a416b2011-02-19 12:05:56 -03001673static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1674{
1675 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001676 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001677
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001678 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001679 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1680 continue;
1681
Johan Hedberge9a416b2011-02-19 12:05:56 -03001682 if (cmd->user_data != conn)
1683 continue;
1684
1685 return cmd;
1686 }
1687
1688 return NULL;
1689}
1690
1691static void pairing_complete(struct pending_cmd *cmd, u8 status)
1692{
1693 struct mgmt_rp_pair_device rp;
1694 struct hci_conn *conn = cmd->user_data;
1695
Johan Hedbergba4e5642011-11-11 00:07:34 +02001696 bacpy(&rp.addr.bdaddr, &conn->dst);
1697 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001698 rp.status = status;
1699
Szymon Janc4e51eae2011-02-25 19:05:48 +01001700 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001701
1702 /* So we don't get further callbacks for this connection */
1703 conn->connect_cfm_cb = NULL;
1704 conn->security_cfm_cb = NULL;
1705 conn->disconn_cfm_cb = NULL;
1706
1707 hci_conn_put(conn);
1708
Johan Hedberga664b5b2011-02-19 12:06:02 -03001709 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001710}
1711
1712static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1713{
1714 struct pending_cmd *cmd;
1715
1716 BT_DBG("status %u", status);
1717
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001718 cmd = find_pairing(conn);
1719 if (!cmd)
1720 BT_DBG("Unable to find a pending command");
1721 else
1722 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001723}
1724
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001725static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001726{
1727 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001728 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001729 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001730 struct pending_cmd *cmd;
1731 u8 sec_level, auth_type;
1732 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001733 int err;
1734
1735 BT_DBG("");
1736
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001737 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001738 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1739 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001740
Szymon Janc4e51eae2011-02-25 19:05:48 +01001741 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001742 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001743 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1744 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001745
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001746 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001747
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001748 sec_level = BT_SECURITY_MEDIUM;
1749 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001750 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001751 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001752 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001753
Johan Hedbergba4e5642011-11-11 00:07:34 +02001754 if (cp->addr.type == MGMT_ADDR_BREDR)
1755 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001756 auth_type);
1757 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001758 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001759 auth_type);
1760
Johan Hedberg1425acb2011-11-11 00:07:35 +02001761 memset(&rp, 0, sizeof(rp));
1762 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1763 rp.addr.type = cp->addr.type;
1764
Ville Tervo30e76272011-02-22 16:10:53 -03001765 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001766 rp.status = -PTR_ERR(conn);
1767 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1768 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001769 goto unlock;
1770 }
1771
1772 if (conn->connect_cfm_cb) {
1773 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001774 rp.status = EBUSY;
1775 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1776 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001777 goto unlock;
1778 }
1779
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001780 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001781 if (!cmd) {
1782 err = -ENOMEM;
1783 hci_conn_put(conn);
1784 goto unlock;
1785 }
1786
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001787 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001788 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001789 conn->connect_cfm_cb = pairing_complete_cb;
1790
Johan Hedberge9a416b2011-02-19 12:05:56 -03001791 conn->security_cfm_cb = pairing_complete_cb;
1792 conn->disconn_cfm_cb = pairing_complete_cb;
1793 conn->io_capability = cp->io_cap;
1794 cmd->user_data = conn;
1795
1796 if (conn->state == BT_CONNECTED &&
1797 hci_conn_security(conn, sec_level, auth_type))
1798 pairing_complete(cmd, 0);
1799
1800 err = 0;
1801
1802unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001803 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001804 hci_dev_put(hdev);
1805
1806 return err;
1807}
1808
Johan Hedberg28424702012-02-02 04:02:29 +02001809static int cancel_pair_device(struct sock *sk, u16 index,
1810 unsigned char *data, u16 len)
1811{
1812 struct mgmt_addr_info *addr = (void *) data;
1813 struct hci_dev *hdev;
1814 struct pending_cmd *cmd;
1815 struct hci_conn *conn;
1816 int err;
1817
1818 BT_DBG("");
1819
1820 if (len != sizeof(*addr))
1821 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1822 MGMT_STATUS_INVALID_PARAMS);
1823
1824 hdev = hci_dev_get(index);
1825 if (!hdev)
1826 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1827 MGMT_STATUS_INVALID_PARAMS);
1828
1829 hci_dev_lock(hdev);
1830
1831 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1832 if (!cmd) {
1833 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1834 MGMT_STATUS_INVALID_PARAMS);
1835 goto unlock;
1836 }
1837
1838 conn = cmd->user_data;
1839
1840 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1841 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1842 MGMT_STATUS_INVALID_PARAMS);
1843 goto unlock;
1844 }
1845
1846 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1847
1848 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr,
1849 sizeof(*addr));
1850unlock:
1851 hci_dev_unlock(hdev);
1852 hci_dev_put(hdev);
1853
1854 return err;
1855}
1856
Brian Gix0df4c182011-11-16 13:53:13 -08001857static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001858 u8 type, u16 mgmt_op, u16 hci_op,
1859 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001860{
Johan Hedberga5c29682011-02-19 12:05:57 -03001861 struct pending_cmd *cmd;
1862 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001863 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001864 int err;
1865
Szymon Janc4e51eae2011-02-25 19:05:48 +01001866 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001867 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001868 return cmd_status(sk, index, mgmt_op,
1869 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001870
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001871 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001872
Johan Hedberga5c29682011-02-19 12:05:57 -03001873 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001874 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1875 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001876 }
1877
Johan Hedberg272d90d2012-02-09 15:26:12 +02001878 if (type == MGMT_ADDR_BREDR)
1879 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1880 else
Brian Gix47c15e22011-11-16 13:53:14 -08001881 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001882
Johan Hedberg272d90d2012-02-09 15:26:12 +02001883 if (!conn) {
1884 err = cmd_status(sk, index, mgmt_op,
1885 MGMT_STATUS_NOT_CONNECTED);
1886 goto done;
1887 }
1888
1889 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001890 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001891 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001892
Brian Gix5fe57d92011-12-21 16:12:13 -08001893 if (!err)
1894 err = cmd_status(sk, index, mgmt_op,
1895 MGMT_STATUS_SUCCESS);
1896 else
1897 err = cmd_status(sk, index, mgmt_op,
1898 MGMT_STATUS_FAILED);
1899
Brian Gix47c15e22011-11-16 13:53:14 -08001900 goto done;
1901 }
1902
Brian Gix0df4c182011-11-16 13:53:13 -08001903 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001904 if (!cmd) {
1905 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001906 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001907 }
1908
Brian Gix0df4c182011-11-16 13:53:13 -08001909 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001910 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1911 struct hci_cp_user_passkey_reply cp;
1912
1913 bacpy(&cp.bdaddr, bdaddr);
1914 cp.passkey = passkey;
1915 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1916 } else
1917 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1918
Johan Hedberga664b5b2011-02-19 12:06:02 -03001919 if (err < 0)
1920 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001921
Brian Gix0df4c182011-11-16 13:53:13 -08001922done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001923 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001924 hci_dev_put(hdev);
1925
1926 return err;
1927}
1928
Brian Gix0df4c182011-11-16 13:53:13 -08001929static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1930{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001931 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001932
1933 BT_DBG("");
1934
1935 if (len != sizeof(*cp))
1936 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1937 MGMT_STATUS_INVALID_PARAMS);
1938
Johan Hedberg272d90d2012-02-09 15:26:12 +02001939 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1940 MGMT_OP_USER_CONFIRM_REPLY,
1941 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001942}
1943
1944static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1945 u16 len)
1946{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001947 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001948
1949 BT_DBG("");
1950
1951 if (len != sizeof(*cp))
1952 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1953 MGMT_STATUS_INVALID_PARAMS);
1954
Johan Hedberg272d90d2012-02-09 15:26:12 +02001955 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1956 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1957 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001958}
1959
Brian Gix604086b2011-11-23 08:28:33 -08001960static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1961{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001962 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001963
1964 BT_DBG("");
1965
1966 if (len != sizeof(*cp))
1967 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1968 EINVAL);
1969
Johan Hedberg272d90d2012-02-09 15:26:12 +02001970 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1971 MGMT_OP_USER_PASSKEY_REPLY,
1972 HCI_OP_USER_PASSKEY_REPLY,
1973 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08001974}
1975
1976static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1977 u16 len)
1978{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001979 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001980
1981 BT_DBG("");
1982
1983 if (len != sizeof(*cp))
1984 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1985 EINVAL);
1986
Johan Hedberg272d90d2012-02-09 15:26:12 +02001987 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1988 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1989 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08001990}
1991
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001992static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02001993 u16 len)
1994{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001995 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001996 struct hci_cp_write_local_name hci_cp;
1997 struct hci_dev *hdev;
1998 struct pending_cmd *cmd;
1999 int err;
2000
2001 BT_DBG("");
2002
2003 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002004 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2005 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002006
2007 hdev = hci_dev_get(index);
2008 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002009 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2010 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002011
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002012 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002013
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002014 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2015 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002016 if (!cmd) {
2017 err = -ENOMEM;
2018 goto failed;
2019 }
2020
2021 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2022 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2023 &hci_cp);
2024 if (err < 0)
2025 mgmt_pending_remove(cmd);
2026
2027failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002028 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002029 hci_dev_put(hdev);
2030
2031 return err;
2032}
2033
Szymon Jancc35938b2011-03-22 13:12:21 +01002034static int read_local_oob_data(struct sock *sk, u16 index)
2035{
2036 struct hci_dev *hdev;
2037 struct pending_cmd *cmd;
2038 int err;
2039
2040 BT_DBG("hci%u", index);
2041
2042 hdev = hci_dev_get(index);
2043 if (!hdev)
2044 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002045 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002046
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002047 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002048
2049 if (!test_bit(HCI_UP, &hdev->flags)) {
2050 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002051 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002052 goto unlock;
2053 }
2054
2055 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2056 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002057 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002058 goto unlock;
2059 }
2060
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002061 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002062 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2063 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002064 goto unlock;
2065 }
2066
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002067 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002068 if (!cmd) {
2069 err = -ENOMEM;
2070 goto unlock;
2071 }
2072
2073 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2074 if (err < 0)
2075 mgmt_pending_remove(cmd);
2076
2077unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002078 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002079 hci_dev_put(hdev);
2080
2081 return err;
2082}
2083
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002084static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2085 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002086{
2087 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002088 struct mgmt_cp_add_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01002089 int err;
2090
2091 BT_DBG("hci%u ", index);
2092
2093 if (len != sizeof(*cp))
2094 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002095 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002096
2097 hdev = hci_dev_get(index);
2098 if (!hdev)
2099 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002100 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002101
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002102 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002103
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002104 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002105 cp->randomizer);
2106 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002107 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2108 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01002109 else
2110 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
2111 0);
2112
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002113 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002114 hci_dev_put(hdev);
2115
2116 return err;
2117}
2118
2119static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002120 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002121{
2122 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002123 struct mgmt_cp_remove_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01002124 int err;
2125
2126 BT_DBG("hci%u ", index);
2127
2128 if (len != sizeof(*cp))
2129 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002130 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002131
2132 hdev = hci_dev_get(index);
2133 if (!hdev)
2134 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002135 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002136
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002137 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002138
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002139 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002140 if (err < 0)
2141 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002142 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002143 else
2144 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2145 NULL, 0);
2146
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002147 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002148 hci_dev_put(hdev);
2149
2150 return err;
2151}
2152
Johan Hedberg450dfda2011-11-12 11:58:22 +02002153static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002154 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002155{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002156 struct mgmt_cp_start_discovery *cp = data;
Andre Guedes3fd24152012-02-03 17:48:01 -03002157 unsigned long discov_type = cp->type;
Johan Hedberg14a53662011-04-27 10:29:56 -04002158 struct pending_cmd *cmd;
2159 struct hci_dev *hdev;
2160 int err;
2161
2162 BT_DBG("hci%u", index);
2163
Johan Hedberg450dfda2011-11-12 11:58:22 +02002164 if (len != sizeof(*cp))
2165 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2166 MGMT_STATUS_INVALID_PARAMS);
2167
Johan Hedberg14a53662011-04-27 10:29:56 -04002168 hdev = hci_dev_get(index);
2169 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002170 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2171 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002172
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002173 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002174
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002175 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002176 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2177 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002178 goto failed;
2179 }
2180
Johan Hedbergff9ef572012-01-04 14:23:45 +02002181 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2182 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2183 MGMT_STATUS_BUSY);
2184 goto failed;
2185 }
2186
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002187 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002188 if (!cmd) {
2189 err = -ENOMEM;
2190 goto failed;
2191 }
2192
Andre Guedes3fd24152012-02-03 17:48:01 -03002193 if (test_bit(MGMT_ADDR_BREDR, &discov_type))
2194 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2195 else if (test_bit(MGMT_ADDR_LE_PUBLIC, &discov_type) &&
2196 test_bit(MGMT_ADDR_LE_RANDOM, &discov_type))
2197 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2198 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
2199 else
2200 err = -EINVAL;
2201
Johan Hedberg14a53662011-04-27 10:29:56 -04002202 if (err < 0)
2203 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002204 else
2205 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002206
2207failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002208 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002209 hci_dev_put(hdev);
2210
2211 return err;
2212}
2213
2214static int stop_discovery(struct sock *sk, u16 index)
2215{
2216 struct hci_dev *hdev;
2217 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002218 struct hci_cp_remote_name_req_cancel cp;
2219 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002220 int err;
2221
2222 BT_DBG("hci%u", index);
2223
2224 hdev = hci_dev_get(index);
2225 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002226 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2227 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002228
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002229 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002230
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002231 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002232 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2233 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002234 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002235 }
2236
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002237 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002238 if (!cmd) {
2239 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002240 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002241 }
2242
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002243 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
2244 err = hci_cancel_inquiry(hdev);
2245 if (err < 0)
2246 mgmt_pending_remove(cmd);
2247 else
2248 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2249 goto unlock;
2250 }
2251
2252 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2253 if (!e) {
2254 mgmt_pending_remove(cmd);
2255 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2256 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2257 goto unlock;
2258 }
2259
2260 bacpy(&cp.bdaddr, &e->data.bdaddr);
2261 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2262 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002263 if (err < 0)
2264 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002265 else
2266 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002267
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002268unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002269 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002270 hci_dev_put(hdev);
2271
2272 return err;
2273}
2274
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002275static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002276{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002277 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002278 struct inquiry_entry *e;
2279 struct hci_dev *hdev;
2280 int err;
2281
2282 BT_DBG("hci%u", index);
2283
2284 if (len != sizeof(*cp))
2285 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2286 MGMT_STATUS_INVALID_PARAMS);
2287
2288 hdev = hci_dev_get(index);
2289 if (!hdev)
2290 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2291 MGMT_STATUS_INVALID_PARAMS);
2292
2293 hci_dev_lock(hdev);
2294
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002295 if (!hci_discovery_active(hdev)) {
2296 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2297 MGMT_STATUS_FAILED);
2298 goto failed;
2299 }
2300
Johan Hedberg561aafb2012-01-04 13:31:59 +02002301 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr);
2302 if (!e) {
2303 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2304 MGMT_STATUS_INVALID_PARAMS);
2305 goto failed;
2306 }
2307
2308 if (cp->name_known) {
2309 e->name_state = NAME_KNOWN;
2310 list_del(&e->list);
2311 } else {
2312 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002313 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002314 }
2315
2316 err = 0;
2317
2318failed:
2319 hci_dev_unlock(hdev);
2320
2321 return err;
2322}
2323
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002324static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002325{
2326 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002327 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002328 int err;
2329
2330 BT_DBG("hci%u", index);
2331
Antti Julku7fbec222011-06-15 12:01:15 +03002332 if (len != sizeof(*cp))
2333 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002334 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002335
2336 hdev = hci_dev_get(index);
2337 if (!hdev)
2338 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002339 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002340
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002341 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002342
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002343 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002344 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002345 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2346 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002347 else
2348 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2349 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002350
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002351 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002352 hci_dev_put(hdev);
2353
2354 return err;
2355}
2356
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002357static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002358{
2359 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002360 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002361 int err;
2362
2363 BT_DBG("hci%u", index);
2364
Antti Julku7fbec222011-06-15 12:01:15 +03002365 if (len != sizeof(*cp))
2366 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002367 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002368
2369 hdev = hci_dev_get(index);
2370 if (!hdev)
2371 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002372 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002373
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002374 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002375
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002376 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002377
2378 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002379 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2380 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002381 else
2382 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2383 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002384
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002385 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002386 hci_dev_put(hdev);
2387
2388 return err;
2389}
2390
Antti Julkuf6422ec2011-06-22 13:11:56 +03002391static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002392 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002393{
2394 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002395 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002396 struct hci_cp_write_page_scan_activity acp;
2397 u8 type;
2398 int err;
2399
2400 BT_DBG("hci%u", index);
2401
2402 if (len != sizeof(*cp))
2403 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002404 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002405
2406 hdev = hci_dev_get(index);
2407 if (!hdev)
2408 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002409 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002410
2411 hci_dev_lock(hdev);
2412
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002413 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002414 type = PAGE_SCAN_TYPE_INTERLACED;
2415 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2416 } else {
2417 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2418 acp.interval = 0x0800; /* default 1.28 sec page scan */
2419 }
2420
2421 acp.window = 0x0012; /* default 11.25 msec page scan window */
2422
2423 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2424 sizeof(acp), &acp);
2425 if (err < 0) {
2426 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002427 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002428 goto done;
2429 }
2430
2431 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2432 if (err < 0) {
2433 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002434 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002435 goto done;
2436 }
2437
2438 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2439 NULL, 0);
2440done:
2441 hci_dev_unlock(hdev);
2442 hci_dev_put(hdev);
2443
2444 return err;
2445}
2446
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002447static int load_long_term_keys(struct sock *sk, u16 index,
2448 void *cp_data, u16 len)
2449{
2450 struct hci_dev *hdev;
2451 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2452 u16 key_count, expected_len;
2453 int i;
2454
2455 if (len < sizeof(*cp))
2456 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2457 EINVAL);
2458
2459 key_count = get_unaligned_le16(&cp->key_count);
2460
2461 expected_len = sizeof(*cp) + key_count *
2462 sizeof(struct mgmt_ltk_info);
2463 if (expected_len != len) {
2464 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2465 len, expected_len);
2466 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2467 EINVAL);
2468 }
2469
2470 hdev = hci_dev_get(index);
2471 if (!hdev)
2472 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2473 ENODEV);
2474
2475 BT_DBG("hci%u key_count %u", index, key_count);
2476
2477 hci_dev_lock(hdev);
2478
2479 hci_smp_ltks_clear(hdev);
2480
2481 for (i = 0; i < key_count; i++) {
2482 struct mgmt_ltk_info *key = &cp->keys[i];
2483 u8 type;
2484
2485 if (key->master)
2486 type = HCI_SMP_LTK;
2487 else
2488 type = HCI_SMP_LTK_SLAVE;
2489
2490 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2491 type, 0, key->authenticated, key->val,
2492 key->enc_size, key->ediv, key->rand);
2493 }
2494
2495 hci_dev_unlock(hdev);
2496 hci_dev_put(hdev);
2497
2498 return 0;
2499}
2500
Johan Hedberg03811012010-12-08 00:21:06 +02002501int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2502{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002503 void *buf;
2504 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002505 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002506 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002507 int err;
2508
2509 BT_DBG("got %zu bytes", msglen);
2510
2511 if (msglen < sizeof(*hdr))
2512 return -EINVAL;
2513
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002514 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002515 if (!buf)
2516 return -ENOMEM;
2517
2518 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2519 err = -EFAULT;
2520 goto done;
2521 }
2522
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002523 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002524 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002525 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002526 len = get_unaligned_le16(&hdr->len);
2527
2528 if (len != msglen - sizeof(*hdr)) {
2529 err = -EINVAL;
2530 goto done;
2531 }
2532
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002533 cp = buf + sizeof(*hdr);
2534
Johan Hedberg03811012010-12-08 00:21:06 +02002535 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002536 case MGMT_OP_READ_VERSION:
2537 err = read_version(sk);
2538 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002539 case MGMT_OP_READ_COMMANDS:
2540 err = read_commands(sk);
2541 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002542 case MGMT_OP_READ_INDEX_LIST:
2543 err = read_index_list(sk);
2544 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002545 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002546 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002547 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002548 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002549 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002550 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002551 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002552 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002553 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002554 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002555 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002556 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002557 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002558 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002559 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002560 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002561 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002562 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002563 case MGMT_OP_SET_LINK_SECURITY:
2564 err = set_link_security(sk, index, cp, len);
2565 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002566 case MGMT_OP_SET_SSP:
2567 err = set_ssp(sk, index, cp, len);
2568 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002569 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002570 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002571 break;
2572 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002573 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002574 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002575 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002576 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002577 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002578 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002579 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002580 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002581 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002582 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002583 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002584 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002585 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002586 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002587 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002588 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002589 break;
2590 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002591 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002592 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002593 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002594 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002595 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002596 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002597 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002598 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002599 case MGMT_OP_CANCEL_PAIR_DEVICE:
2600 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2601 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002602 case MGMT_OP_UNPAIR_DEVICE:
2603 err = unpair_device(sk, index, cp, len);
2604 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002605 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002606 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002607 break;
2608 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002609 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002610 break;
Brian Gix604086b2011-11-23 08:28:33 -08002611 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002612 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002613 break;
2614 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002615 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002616 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002617 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002618 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002619 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002620 case MGMT_OP_READ_LOCAL_OOB_DATA:
2621 err = read_local_oob_data(sk, index);
2622 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002623 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002624 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002625 break;
2626 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002627 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002628 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002629 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002630 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002631 break;
2632 case MGMT_OP_STOP_DISCOVERY:
2633 err = stop_discovery(sk, index);
2634 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002635 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002636 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002637 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002638 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002639 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002640 break;
2641 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002642 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002643 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002644 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2645 err = load_long_term_keys(sk, index, cp, len);
2646 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002647 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002648 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002649 err = cmd_status(sk, index, opcode,
2650 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002651 break;
2652 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002653
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002654 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002655 goto done;
2656
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002657 err = msglen;
2658
2659done:
2660 kfree(buf);
2661 return err;
2662}
2663
Johan Hedbergb24752f2011-11-03 14:40:33 +02002664static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2665{
2666 u8 *status = data;
2667
2668 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2669 mgmt_pending_remove(cmd);
2670}
2671
Johan Hedberg744cf192011-11-08 20:40:14 +02002672int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002673{
Johan Hedberg744cf192011-11-08 20:40:14 +02002674 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002675}
2676
Johan Hedberg744cf192011-11-08 20:40:14 +02002677int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002678{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002679 u8 status = ENODEV;
2680
Johan Hedberg744cf192011-11-08 20:40:14 +02002681 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002682
Johan Hedberg744cf192011-11-08 20:40:14 +02002683 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002684}
2685
2686struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002687 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002688 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002689};
2690
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002691static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002692{
Johan Hedberg03811012010-12-08 00:21:06 +02002693 struct cmd_lookup *match = data;
2694
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002695 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002696
2697 list_del(&cmd->list);
2698
2699 if (match->sk == NULL) {
2700 match->sk = cmd->sk;
2701 sock_hold(match->sk);
2702 }
2703
2704 mgmt_pending_free(cmd);
2705}
2706
Johan Hedberg744cf192011-11-08 20:40:14 +02002707int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002708{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002709 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002710 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002711 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002712
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002713 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002714
Johan Hedbergb24752f2011-11-03 14:40:33 +02002715 if (!powered) {
2716 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002717 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002718 }
2719
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002720 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002721
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002722 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002723 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002724
2725 if (match.sk)
2726 sock_put(match.sk);
2727
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002728 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002729}
2730
Johan Hedberg744cf192011-11-08 20:40:14 +02002731int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002732{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002733 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002734 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002735 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002736
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002737 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002738
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002739 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002740
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002741 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002742 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002743 if (match.sk)
2744 sock_put(match.sk);
2745
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002746 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002747}
2748
Johan Hedberg744cf192011-11-08 20:40:14 +02002749int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002750{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002751 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002752 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002753 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002754
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002755 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2756 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002757
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002758 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002759
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002760 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002761
2762 if (match.sk)
2763 sock_put(match.sk);
2764
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002765 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002766}
2767
Johan Hedberg744cf192011-11-08 20:40:14 +02002768int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002769{
Johan Hedbergca69b792011-11-11 18:10:00 +02002770 u8 mgmt_err = mgmt_status(status);
2771
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002772 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002773 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002774 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002775
2776 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002777 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002778 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002779
2780 return 0;
2781}
2782
Johan Hedberg744cf192011-11-08 20:40:14 +02002783int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2784 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002785{
Johan Hedberg86742e12011-11-07 23:13:38 +02002786 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002787
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002788 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002789
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002790 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002791 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2792 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002793 ev.key.type = key->type;
2794 memcpy(ev.key.val, key->val, 16);
2795 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002796
Johan Hedberg744cf192011-11-08 20:40:14 +02002797 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002798}
Johan Hedbergf7520542011-01-20 12:34:39 +02002799
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002800int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2801{
2802 struct mgmt_ev_new_long_term_key ev;
2803
2804 memset(&ev, 0, sizeof(ev));
2805
2806 ev.store_hint = persistent;
2807 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2808 ev.key.addr.type = key->bdaddr_type;
2809 ev.key.authenticated = key->authenticated;
2810 ev.key.enc_size = key->enc_size;
2811 ev.key.ediv = key->ediv;
2812
2813 if (key->type == HCI_SMP_LTK)
2814 ev.key.master = 1;
2815
2816 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2817 memcpy(ev.key.val, key->val, sizeof(key->val));
2818
2819 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2820 &ev, sizeof(ev), NULL);
2821}
2822
Johan Hedbergafc747a2012-01-15 18:11:07 +02002823int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002824 u8 addr_type, u8 *name, u8 name_len,
2825 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002826{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002827 char buf[512];
2828 struct mgmt_ev_device_connected *ev = (void *) buf;
2829 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002830
Johan Hedbergb644ba32012-01-17 21:48:47 +02002831 bacpy(&ev->addr.bdaddr, bdaddr);
2832 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002833
Johan Hedbergb644ba32012-01-17 21:48:47 +02002834 if (name_len > 0)
2835 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2836 name, name_len);
2837
2838 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2839 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2840 EIR_CLASS_OF_DEV, dev_class, 3);
2841
2842 put_unaligned_le16(eir_len, &ev->eir_len);
2843
2844 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2845 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002846}
2847
Johan Hedberg8962ee72011-01-20 12:40:27 +02002848static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2849{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002850 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002851 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002852 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002853
Johan Hedberg88c3df12012-02-09 14:27:38 +02002854 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2855 rp.addr.type = cp->addr.type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002856 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002857
Szymon Janc4e51eae2011-02-25 19:05:48 +01002858 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002859
2860 *sk = cmd->sk;
2861 sock_hold(*sk);
2862
Johan Hedberga664b5b2011-02-19 12:06:02 -03002863 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002864}
2865
Johan Hedberg124f6e32012-02-09 13:50:12 +02002866static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002867{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002868 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002869 struct mgmt_cp_unpair_device *cp = cmd->param;
2870 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002871
2872 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002873 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2874 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002875
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002876 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2877
2878 cmd_complete(cmd->sk, cmd->index, cmd->opcode, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002879
2880 mgmt_pending_remove(cmd);
2881}
2882
Johan Hedbergafc747a2012-01-15 18:11:07 +02002883int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2884 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002885{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002886 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002887 struct sock *sk = NULL;
2888 int err;
2889
Johan Hedberg744cf192011-11-08 20:40:14 +02002890 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002891
Johan Hedbergf7520542011-01-20 12:34:39 +02002892 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002893 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002894
Johan Hedbergafc747a2012-01-15 18:11:07 +02002895 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2896 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002897
2898 if (sk)
2899 sock_put(sk);
2900
Johan Hedberg124f6e32012-02-09 13:50:12 +02002901 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002902 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002903
Johan Hedberg8962ee72011-01-20 12:40:27 +02002904 return err;
2905}
2906
Johan Hedberg88c3df12012-02-09 14:27:38 +02002907int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
2908 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002909{
Johan Hedberg88c3df12012-02-09 14:27:38 +02002910 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002911 struct pending_cmd *cmd;
2912 int err;
2913
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002914 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002915 if (!cmd)
2916 return -ENOENT;
2917
Johan Hedberg88c3df12012-02-09 14:27:38 +02002918 bacpy(&rp.addr.bdaddr, bdaddr);
2919 rp.addr.type = link_to_mgmt(link_type, addr_type);
2920 rp.status = mgmt_status(status);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002921
Johan Hedberg88c3df12012-02-09 14:27:38 +02002922 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002923 &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002924
Johan Hedberga664b5b2011-02-19 12:06:02 -03002925 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002926
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002927 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
2928 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002929 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002930}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002931
Johan Hedberg48264f02011-11-09 13:58:58 +02002932int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2933 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002934{
2935 struct mgmt_ev_connect_failed ev;
2936
Johan Hedberg4c659c32011-11-07 23:13:39 +02002937 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002938 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002939 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002940
Johan Hedberg744cf192011-11-08 20:40:14 +02002941 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002942}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002943
Johan Hedberg744cf192011-11-08 20:40:14 +02002944int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002945{
2946 struct mgmt_ev_pin_code_request ev;
2947
Johan Hedberg980e1a52011-01-22 06:10:07 +02002948 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002949 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002950
Johan Hedberg744cf192011-11-08 20:40:14 +02002951 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002952 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002953}
2954
Johan Hedberg744cf192011-11-08 20:40:14 +02002955int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2956 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002957{
2958 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002959 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002960 int err;
2961
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002962 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002963 if (!cmd)
2964 return -ENOENT;
2965
Johan Hedbergac56fb12011-02-19 12:05:59 -03002966 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002967 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002968
Johan Hedberg744cf192011-11-08 20:40:14 +02002969 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002970 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002971
Johan Hedberga664b5b2011-02-19 12:06:02 -03002972 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002973
2974 return err;
2975}
2976
Johan Hedberg744cf192011-11-08 20:40:14 +02002977int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2978 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002979{
2980 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002981 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002982 int err;
2983
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002984 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002985 if (!cmd)
2986 return -ENOENT;
2987
Johan Hedbergac56fb12011-02-19 12:05:59 -03002988 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002989 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002990
Johan Hedberg744cf192011-11-08 20:40:14 +02002991 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002992 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002993
Johan Hedberga664b5b2011-02-19 12:06:02 -03002994 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002995
2996 return err;
2997}
Johan Hedberga5c29682011-02-19 12:05:57 -03002998
Johan Hedberg744cf192011-11-08 20:40:14 +02002999int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003000 u8 link_type, u8 addr_type, __le32 value,
3001 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003002{
3003 struct mgmt_ev_user_confirm_request ev;
3004
Johan Hedberg744cf192011-11-08 20:40:14 +02003005 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003006
Johan Hedberg272d90d2012-02-09 15:26:12 +02003007 bacpy(&ev.addr.bdaddr, bdaddr);
3008 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003009 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003010 put_unaligned_le32(value, &ev.value);
3011
Johan Hedberg744cf192011-11-08 20:40:14 +02003012 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003013 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003014}
3015
Johan Hedberg272d90d2012-02-09 15:26:12 +02003016int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3017 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003018{
3019 struct mgmt_ev_user_passkey_request ev;
3020
3021 BT_DBG("%s", hdev->name);
3022
Johan Hedberg272d90d2012-02-09 15:26:12 +02003023 bacpy(&ev.addr.bdaddr, bdaddr);
3024 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003025
3026 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3027 NULL);
3028}
3029
Brian Gix0df4c182011-11-16 13:53:13 -08003030static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003031 u8 link_type, u8 addr_type, u8 status,
3032 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003033{
3034 struct pending_cmd *cmd;
3035 struct mgmt_rp_user_confirm_reply rp;
3036 int err;
3037
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003038 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003039 if (!cmd)
3040 return -ENOENT;
3041
Johan Hedberg272d90d2012-02-09 15:26:12 +02003042 bacpy(&rp.addr.bdaddr, bdaddr);
3043 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003044 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02003045 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003046
Johan Hedberga664b5b2011-02-19 12:06:02 -03003047 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003048
3049 return err;
3050}
3051
Johan Hedberg744cf192011-11-08 20:40:14 +02003052int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003053 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003054{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003055 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3056 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003057}
3058
Johan Hedberg272d90d2012-02-09 15:26:12 +02003059int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3060 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003061{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003062 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3063 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003064}
Johan Hedberg2a611692011-02-19 12:06:00 -03003065
Brian Gix604086b2011-11-23 08:28:33 -08003066int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003067 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003068{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003069 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3070 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003071}
3072
Johan Hedberg272d90d2012-02-09 15:26:12 +02003073int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3074 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003075{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003076 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3077 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003078}
3079
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003080int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3081 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003082{
3083 struct mgmt_ev_auth_failed ev;
3084
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003085 bacpy(&ev.addr.bdaddr, bdaddr);
3086 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003087 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003088
Johan Hedberg744cf192011-11-08 20:40:14 +02003089 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003090}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003091
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003092int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3093{
3094 struct cmd_lookup match = { NULL, hdev };
3095 __le32 ev;
3096 int err;
3097
3098 if (status) {
3099 u8 mgmt_err = mgmt_status(status);
3100 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3101 cmd_status_rsp, &mgmt_err);
3102 return 0;
3103 }
3104
3105 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3106 &match);
3107
3108 ev = cpu_to_le32(get_current_settings(hdev));
3109 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3110
3111 if (match.sk)
3112 sock_put(match.sk);
3113
3114 return err;
3115}
3116
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003117int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3118{
3119 struct cmd_lookup match = { NULL, hdev };
3120 __le32 ev;
3121 int err;
3122
3123 if (status) {
3124 u8 mgmt_err = mgmt_status(status);
3125 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3126 cmd_status_rsp, &mgmt_err);
3127 return 0;
3128 }
3129
3130 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3131
3132 ev = cpu_to_le32(get_current_settings(hdev));
3133 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3134
3135 if (match.sk)
3136 sock_put(match.sk);
3137
3138 return err;
3139}
3140
Johan Hedberg744cf192011-11-08 20:40:14 +02003141int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003142{
3143 struct pending_cmd *cmd;
3144 struct mgmt_cp_set_local_name ev;
3145 int err;
3146
3147 memset(&ev, 0, sizeof(ev));
3148 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3149
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003150 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003151 if (!cmd)
3152 goto send_event;
3153
3154 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003155 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003156 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003157 goto failed;
3158 }
3159
Johan Hedberg744cf192011-11-08 20:40:14 +02003160 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003161
Johan Hedberg744cf192011-11-08 20:40:14 +02003162 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003163 sizeof(ev));
3164 if (err < 0)
3165 goto failed;
3166
3167send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003168 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003169 cmd ? cmd->sk : NULL);
3170
3171failed:
3172 if (cmd)
3173 mgmt_pending_remove(cmd);
3174 return err;
3175}
Szymon Jancc35938b2011-03-22 13:12:21 +01003176
Johan Hedberg744cf192011-11-08 20:40:14 +02003177int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3178 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003179{
3180 struct pending_cmd *cmd;
3181 int err;
3182
Johan Hedberg744cf192011-11-08 20:40:14 +02003183 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003184
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003185 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003186 if (!cmd)
3187 return -ENOENT;
3188
3189 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003190 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003191 MGMT_OP_READ_LOCAL_OOB_DATA,
3192 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003193 } else {
3194 struct mgmt_rp_read_local_oob_data rp;
3195
3196 memcpy(rp.hash, hash, sizeof(rp.hash));
3197 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3198
Johan Hedberg744cf192011-11-08 20:40:14 +02003199 err = cmd_complete(cmd->sk, hdev->id,
3200 MGMT_OP_READ_LOCAL_OOB_DATA,
3201 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003202 }
3203
3204 mgmt_pending_remove(cmd);
3205
3206 return err;
3207}
Johan Hedberge17acd42011-03-30 23:57:16 +03003208
Johan Hedberg48264f02011-11-09 13:58:58 +02003209int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003210 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003211 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003212{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003213 char buf[512];
3214 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003215 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003216
Johan Hedberg1dc06092012-01-15 21:01:23 +02003217 /* Leave 5 bytes for a potential CoD field */
3218 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003219 return -EINVAL;
3220
Johan Hedberg1dc06092012-01-15 21:01:23 +02003221 memset(buf, 0, sizeof(buf));
3222
Johan Hedberge319d2e2012-01-15 19:51:59 +02003223 bacpy(&ev->addr.bdaddr, bdaddr);
3224 ev->addr.type = link_to_mgmt(link_type, addr_type);
3225 ev->rssi = rssi;
3226 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003227
Johan Hedberg1dc06092012-01-15 21:01:23 +02003228 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003229 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003230
Johan Hedberg1dc06092012-01-15 21:01:23 +02003231 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3232 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3233 dev_class, 3);
3234
3235 put_unaligned_le16(eir_len, &ev->eir_len);
3236
3237 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003238
Johan Hedberge319d2e2012-01-15 19:51:59 +02003239 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003240}
Johan Hedberga88a9652011-03-30 13:18:12 +03003241
Johan Hedbergb644ba32012-01-17 21:48:47 +02003242int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3243 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003244{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003245 struct mgmt_ev_device_found *ev;
3246 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3247 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003248
Johan Hedbergb644ba32012-01-17 21:48:47 +02003249 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003250
Johan Hedbergb644ba32012-01-17 21:48:47 +02003251 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003252
Johan Hedbergb644ba32012-01-17 21:48:47 +02003253 bacpy(&ev->addr.bdaddr, bdaddr);
3254 ev->addr.type = link_to_mgmt(link_type, addr_type);
3255 ev->rssi = rssi;
3256
3257 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3258 name_len);
3259
3260 put_unaligned_le16(eir_len, &ev->eir_len);
3261
Johan Hedberg053c7e02012-02-04 00:06:00 +02003262 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3263 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003264}
Johan Hedberg314b2382011-04-27 10:29:57 -04003265
Andre Guedes7a135102011-11-09 17:14:25 -03003266int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003267{
3268 struct pending_cmd *cmd;
3269 int err;
3270
Andre Guedes203159d2012-02-13 15:41:01 -03003271 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3272
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003273 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003274 if (!cmd)
3275 return -ENOENT;
3276
Johan Hedbergca69b792011-11-11 18:10:00 +02003277 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003278 mgmt_pending_remove(cmd);
3279
3280 return err;
3281}
3282
Andre Guedese6d465c2011-11-09 17:14:26 -03003283int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3284{
3285 struct pending_cmd *cmd;
3286 int err;
3287
3288 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3289 if (!cmd)
3290 return -ENOENT;
3291
Andre Guedese75a8b0c2012-01-02 16:50:53 -03003292 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02003293 mgmt_pending_remove(cmd);
3294
3295 return err;
3296}
Johan Hedberg314b2382011-04-27 10:29:57 -04003297
Johan Hedberg744cf192011-11-08 20:40:14 +02003298int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003299{
Johan Hedberg164a6e72011-11-01 17:06:44 +02003300 struct pending_cmd *cmd;
3301
Andre Guedes343fb142011-11-22 17:14:19 -03003302 BT_DBG("%s discovering %u", hdev->name, discovering);
3303
Johan Hedberg164a6e72011-11-01 17:06:44 +02003304 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003305 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003306 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003307 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003308
3309 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003310 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003311 mgmt_pending_remove(cmd);
3312 }
3313
Johan Hedberg744cf192011-11-08 20:40:14 +02003314 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04003315 sizeof(discovering), NULL);
3316}
Antti Julku5e762442011-08-25 16:48:02 +03003317
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003318int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003319{
3320 struct pending_cmd *cmd;
3321 struct mgmt_ev_device_blocked ev;
3322
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003323 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003324
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003325 bacpy(&ev.addr.bdaddr, bdaddr);
3326 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003327
Johan Hedberg744cf192011-11-08 20:40:14 +02003328 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3329 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003330}
3331
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003332int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003333{
3334 struct pending_cmd *cmd;
3335 struct mgmt_ev_device_unblocked ev;
3336
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003337 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003338
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003339 bacpy(&ev.addr.bdaddr, bdaddr);
3340 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003341
Johan Hedberg744cf192011-11-08 20:40:14 +02003342 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3343 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003344}