blob: f1257ee5afbc321c4ca06843f8360458f5fcbfc9 [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
Andre Guedes3fd24152012-02-03 17:48:01 -030038/*
39 * These LE scan and inquiry parameters were chosen according to LE General
40 * Discovery Procedure specification.
41 */
42#define LE_SCAN_TYPE 0x01
43#define LE_SCAN_WIN 0x12
44#define LE_SCAN_INT 0x12
45#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
46
Andre Guedese8777522012-02-03 17:48:02 -030047#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes2519a1f2011-11-07 11:45:24 -030048
Johan Hedberg7d785252011-12-15 00:47:39 +020049#define SERVICE_CACHE_TIMEOUT (5 * 1000)
50
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020051struct pending_cmd {
52 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020053 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020054 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010055 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020056 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030057 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020058};
59
Johan Hedbergca69b792011-11-11 18:10:00 +020060/* HCI to MGMT error code conversion table */
61static u8 mgmt_status_table[] = {
62 MGMT_STATUS_SUCCESS,
63 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
64 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
65 MGMT_STATUS_FAILED, /* Hardware Failure */
66 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
67 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
68 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
69 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
70 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
71 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
72 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
73 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
74 MGMT_STATUS_BUSY, /* Command Disallowed */
75 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
76 MGMT_STATUS_REJECTED, /* Rejected Security */
77 MGMT_STATUS_REJECTED, /* Rejected Personal */
78 MGMT_STATUS_TIMEOUT, /* Host Timeout */
79 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
80 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
81 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
82 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
83 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
84 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
85 MGMT_STATUS_BUSY, /* Repeated Attempts */
86 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
87 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
88 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
89 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
90 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
91 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
92 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
93 MGMT_STATUS_FAILED, /* Unspecified Error */
94 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
95 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
96 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
97 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
98 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
99 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
100 MGMT_STATUS_FAILED, /* Unit Link Key Used */
101 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
102 MGMT_STATUS_TIMEOUT, /* Instant Passed */
103 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
104 MGMT_STATUS_FAILED, /* Transaction Collision */
105 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
106 MGMT_STATUS_REJECTED, /* QoS Rejected */
107 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
108 MGMT_STATUS_REJECTED, /* Insufficient Security */
109 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
110 MGMT_STATUS_BUSY, /* Role Switch Pending */
111 MGMT_STATUS_FAILED, /* Slot Violation */
112 MGMT_STATUS_FAILED, /* Role Switch Failed */
113 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
114 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
115 MGMT_STATUS_BUSY, /* Host Busy Pairing */
116 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
117 MGMT_STATUS_BUSY, /* Controller Busy */
118 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
119 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
120 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
121 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
122 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
123};
124
125static u8 mgmt_status(u8 hci_status)
126{
127 if (hci_status < ARRAY_SIZE(mgmt_status_table))
128 return mgmt_status_table[hci_status];
129
130 return MGMT_STATUS_FAILED;
131}
132
Szymon Janc4e51eae2011-02-25 19:05:48 +0100133static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200134{
135 struct sk_buff *skb;
136 struct mgmt_hdr *hdr;
137 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300138 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200139
Szymon Janc34eb5252011-02-28 14:10:08 +0100140 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200141
142 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
143 if (!skb)
144 return -ENOMEM;
145
146 hdr = (void *) skb_put(skb, sizeof(*hdr));
147
148 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100149 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200150 hdr->len = cpu_to_le16(sizeof(*ev));
151
152 ev = (void *) skb_put(skb, sizeof(*ev));
153 ev->status = status;
154 put_unaligned_le16(cmd, &ev->opcode);
155
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300156 err = sock_queue_rcv_skb(sk, skb);
157 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200158 kfree_skb(skb);
159
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300160 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200161}
162
Szymon Janc4e51eae2011-02-25 19:05:48 +0100163static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
164 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200165{
166 struct sk_buff *skb;
167 struct mgmt_hdr *hdr;
168 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300169 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200170
171 BT_DBG("sock %p", sk);
172
Johan Hedberga38528f2011-01-22 06:46:43 +0200173 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200174 if (!skb)
175 return -ENOMEM;
176
177 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200178
Johan Hedberg02d98122010-12-13 21:07:04 +0200179 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100180 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200181 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200182
Johan Hedberga38528f2011-01-22 06:46:43 +0200183 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
184 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100185
186 if (rp)
187 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200188
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300189 err = sock_queue_rcv_skb(sk, skb);
190 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200191 kfree_skb(skb);
192
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300193 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200194}
195
Johan Hedberga38528f2011-01-22 06:46:43 +0200196static int read_version(struct sock *sk)
197{
198 struct mgmt_rp_read_version rp;
199
200 BT_DBG("sock %p", sk);
201
202 rp.version = MGMT_VERSION;
203 put_unaligned_le16(MGMT_REVISION, &rp.revision);
204
Szymon Janc4e51eae2011-02-25 19:05:48 +0100205 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
206 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200207}
208
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200209static int read_index_list(struct sock *sk)
210{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200211 struct mgmt_rp_read_index_list *rp;
212 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200213 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200214 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200215 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200216 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200217
218 BT_DBG("sock %p", sk);
219
220 read_lock(&hci_dev_list_lock);
221
222 count = 0;
223 list_for_each(p, &hci_dev_list) {
224 count++;
225 }
226
Johan Hedberga38528f2011-01-22 06:46:43 +0200227 rp_len = sizeof(*rp) + (2 * count);
228 rp = kmalloc(rp_len, GFP_ATOMIC);
229 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100230 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200231 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100232 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200233
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200234 put_unaligned_le16(count, &rp->num_controllers);
235
236 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200237 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200238 if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200239 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200240
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200241 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200242 continue;
243
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200244 put_unaligned_le16(d->id, &rp->index[i++]);
245 BT_DBG("Added hci%u", d->id);
246 }
247
248 read_unlock(&hci_dev_list_lock);
249
Szymon Janc4e51eae2011-02-25 19:05:48 +0100250 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
251 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200252
Johan Hedberga38528f2011-01-22 06:46:43 +0200253 kfree(rp);
254
255 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200256}
257
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200258static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200259{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200260 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200261
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200262 settings |= MGMT_SETTING_POWERED;
263 settings |= MGMT_SETTING_CONNECTABLE;
264 settings |= MGMT_SETTING_FAST_CONNECTABLE;
265 settings |= MGMT_SETTING_DISCOVERABLE;
266 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200267
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200268 if (hdev->features[6] & LMP_SIMPLE_PAIR)
269 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200270
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200271 if (!(hdev->features[4] & LMP_NO_BREDR)) {
272 settings |= MGMT_SETTING_BREDR;
273 settings |= MGMT_SETTING_LINK_SECURITY;
274 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200275
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200276 if (hdev->features[4] & LMP_LE)
277 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200278
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200279 return settings;
280}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200281
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200282static u32 get_current_settings(struct hci_dev *hdev)
283{
284 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200285
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200286 if (test_bit(HCI_UP, &hdev->flags))
287 settings |= MGMT_SETTING_POWERED;
288 else
289 return settings;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200290
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200291 if (test_bit(HCI_PSCAN, &hdev->flags))
292 settings |= MGMT_SETTING_CONNECTABLE;
293
294 if (test_bit(HCI_ISCAN, &hdev->flags))
295 settings |= MGMT_SETTING_DISCOVERABLE;
296
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200297 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200298 settings |= MGMT_SETTING_PAIRABLE;
299
300 if (!(hdev->features[4] & LMP_NO_BREDR))
301 settings |= MGMT_SETTING_BREDR;
302
Andre Guedes59e29402011-12-30 10:34:03 -0300303 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200304 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200305
306 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200307 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200308
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200309 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200310 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200311
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200312 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200313}
314
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300315#define PNP_INFO_SVCLASS_ID 0x1200
316
317static u8 bluetooth_base_uuid[] = {
318 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
319 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320};
321
322static u16 get_uuid16(u8 *uuid128)
323{
324 u32 val;
325 int i;
326
327 for (i = 0; i < 12; i++) {
328 if (bluetooth_base_uuid[i] != uuid128[i])
329 return 0;
330 }
331
332 memcpy(&val, &uuid128[12], 4);
333
334 val = le32_to_cpu(val);
335 if (val > 0xffff)
336 return 0;
337
338 return (u16) val;
339}
340
341static void create_eir(struct hci_dev *hdev, u8 *data)
342{
343 u8 *ptr = data;
344 u16 eir_len = 0;
345 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
346 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200347 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300348 size_t name_len;
349
350 name_len = strlen(hdev->dev_name);
351
352 if (name_len > 0) {
353 /* EIR Data type */
354 if (name_len > 48) {
355 name_len = 48;
356 ptr[1] = EIR_NAME_SHORT;
357 } else
358 ptr[1] = EIR_NAME_COMPLETE;
359
360 /* EIR Data length */
361 ptr[0] = name_len + 1;
362
363 memcpy(ptr + 2, hdev->dev_name, name_len);
364
365 eir_len += (name_len + 2);
366 ptr += (name_len + 2);
367 }
368
369 memset(uuid16_list, 0, sizeof(uuid16_list));
370
371 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200372 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300373 u16 uuid16;
374
375 uuid16 = get_uuid16(uuid->uuid);
376 if (uuid16 == 0)
377 return;
378
379 if (uuid16 < 0x1100)
380 continue;
381
382 if (uuid16 == PNP_INFO_SVCLASS_ID)
383 continue;
384
385 /* Stop if not enough space to put next UUID */
386 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
387 truncated = 1;
388 break;
389 }
390
391 /* Check for duplicates */
392 for (i = 0; uuid16_list[i] != 0; i++)
393 if (uuid16_list[i] == uuid16)
394 break;
395
396 if (uuid16_list[i] == 0) {
397 uuid16_list[i] = uuid16;
398 eir_len += sizeof(u16);
399 }
400 }
401
402 if (uuid16_list[0] != 0) {
403 u8 *length = ptr;
404
405 /* EIR Data type */
406 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
407
408 ptr += 2;
409 eir_len += 2;
410
411 for (i = 0; uuid16_list[i] != 0; i++) {
412 *ptr++ = (uuid16_list[i] & 0x00ff);
413 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
414 }
415
416 /* EIR Data length */
417 *length = (i * sizeof(u16)) + 1;
418 }
419}
420
421static int update_eir(struct hci_dev *hdev)
422{
423 struct hci_cp_write_eir cp;
424
425 if (!(hdev->features[6] & LMP_EXT_INQ))
426 return 0;
427
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200428 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300429 return 0;
430
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200431 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300432 return 0;
433
434 memset(&cp, 0, sizeof(cp));
435
436 create_eir(hdev, cp.data);
437
438 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
439 return 0;
440
441 memcpy(hdev->eir, cp.data, sizeof(cp.data));
442
443 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
444}
445
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200446static u8 get_service_classes(struct hci_dev *hdev)
447{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300448 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200449 u8 val = 0;
450
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300451 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200452 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200453
454 return val;
455}
456
457static int update_class(struct hci_dev *hdev)
458{
459 u8 cod[3];
460
461 BT_DBG("%s", hdev->name);
462
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200463 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200464 return 0;
465
466 cod[0] = hdev->minor_class;
467 cod[1] = hdev->major_class;
468 cod[2] = get_service_classes(hdev);
469
470 if (memcmp(cod, hdev->dev_class, 3) == 0)
471 return 0;
472
473 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
474}
475
Johan Hedberg7d785252011-12-15 00:47:39 +0200476static void service_cache_off(struct work_struct *work)
477{
478 struct hci_dev *hdev = container_of(work, struct hci_dev,
479 service_cache.work);
480
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200481 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200482 return;
483
484 hci_dev_lock(hdev);
485
486 update_eir(hdev);
487 update_class(hdev);
488
489 hci_dev_unlock(hdev);
490}
491
492static void mgmt_init_hdev(struct hci_dev *hdev)
493{
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200494 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200495 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
496
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200497 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200498 schedule_delayed_work(&hdev->service_cache,
499 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
500}
501
Johan Hedberg03811012010-12-08 00:21:06 +0200502static int read_controller_info(struct sock *sk, u16 index)
503{
504 struct mgmt_rp_read_info rp;
505 struct hci_dev *hdev;
506
507 BT_DBG("sock %p hci%u", sk, index);
508
509 hdev = hci_dev_get(index);
510 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200511 return cmd_status(sk, index, MGMT_OP_READ_INFO,
512 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200513
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200514 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
Johan Hedberg03811012010-12-08 00:21:06 +0200515 cancel_delayed_work_sync(&hdev->power_off);
516
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300517 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200518
Johan Hedberg7d785252011-12-15 00:47:39 +0200519 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
520 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200521
522 memset(&rp, 0, sizeof(rp));
523
Johan Hedberg03811012010-12-08 00:21:06 +0200524 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200525
526 rp.version = hdev->hci_ver;
527
Johan Hedberg03811012010-12-08 00:21:06 +0200528 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200529
530 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
531 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
532
533 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200534
535 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
536
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300537 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200538 hci_dev_put(hdev);
539
540 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
541}
542
543static void mgmt_pending_free(struct pending_cmd *cmd)
544{
545 sock_put(cmd->sk);
546 kfree(cmd->param);
547 kfree(cmd);
548}
549
550static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
551 struct hci_dev *hdev,
552 void *data, u16 len)
553{
554 struct pending_cmd *cmd;
555
556 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
557 if (!cmd)
558 return NULL;
559
560 cmd->opcode = opcode;
561 cmd->index = hdev->id;
562
563 cmd->param = kmalloc(len, GFP_ATOMIC);
564 if (!cmd->param) {
565 kfree(cmd);
566 return NULL;
567 }
568
569 if (data)
570 memcpy(cmd->param, data, len);
571
572 cmd->sk = sk;
573 sock_hold(sk);
574
575 list_add(&cmd->list, &hdev->mgmt_pending);
576
577 return cmd;
578}
579
580static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
581 void (*cb)(struct pending_cmd *cmd, void *data),
582 void *data)
583{
584 struct list_head *p, *n;
585
586 list_for_each_safe(p, n, &hdev->mgmt_pending) {
587 struct pending_cmd *cmd;
588
589 cmd = list_entry(p, struct pending_cmd, list);
590
591 if (opcode > 0 && cmd->opcode != opcode)
592 continue;
593
594 cb(cmd, data);
595 }
596}
597
598static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
599{
600 struct pending_cmd *cmd;
601
602 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
603 if (cmd->opcode == opcode)
604 return cmd;
605 }
606
607 return NULL;
608}
609
610static void mgmt_pending_remove(struct pending_cmd *cmd)
611{
612 list_del(&cmd->list);
613 mgmt_pending_free(cmd);
614}
615
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200616static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200617{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200618 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200619
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200620 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200621}
622
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300623static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200624{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300625 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200626 struct hci_dev *hdev;
627 struct pending_cmd *cmd;
628 int err, up;
629
Johan Hedberg03811012010-12-08 00:21:06 +0200630 BT_DBG("request for hci%u", index);
631
632 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200633 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
634 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200635
636 hdev = hci_dev_get(index);
637 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200638 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
639 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200640
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300641 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200642
643 up = test_bit(HCI_UP, &hdev->flags);
644 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200645 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200646 goto failed;
647 }
648
649 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200650 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
651 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200652 goto failed;
653 }
654
655 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
656 if (!cmd) {
657 err = -ENOMEM;
658 goto failed;
659 }
660
661 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200662 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200663 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200664 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200665
666 err = 0;
667
668failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300669 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200670 hci_dev_put(hdev);
671 return err;
672}
673
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300674static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200675{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300676 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200677 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200678 struct pending_cmd *cmd;
679 u8 scan;
680 int err;
681
Johan Hedberg03811012010-12-08 00:21:06 +0200682 BT_DBG("request for hci%u", index);
683
684 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200685 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
686 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200687
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200688 hdev = hci_dev_get(index);
689 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200690 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
691 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200692
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300693 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200694
695 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200696 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
697 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200698 goto failed;
699 }
700
701 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
702 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200703 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
704 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200705 goto failed;
706 }
707
708 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
709 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200710 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200711 goto failed;
712 }
713
714 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
715 if (!cmd) {
716 err = -ENOMEM;
717 goto failed;
718 }
719
720 scan = SCAN_PAGE;
721
722 if (cp->val)
723 scan |= SCAN_INQUIRY;
724 else
725 cancel_delayed_work(&hdev->discov_off);
726
727 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
728 if (err < 0)
729 mgmt_pending_remove(cmd);
730
Johan Hedberg03811012010-12-08 00:21:06 +0200731 if (cp->val)
732 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
733
Johan Hedberge41d8b42010-12-13 21:07:03 +0200734failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300735 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200736 hci_dev_put(hdev);
737
738 return err;
739}
740
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300741static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200742{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300743 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200744 struct hci_dev *hdev;
745 struct pending_cmd *cmd;
746 u8 scan;
747 int err;
748
Johan Hedberge41d8b42010-12-13 21:07:03 +0200749 BT_DBG("request for hci%u", index);
750
Johan Hedberg03811012010-12-08 00:21:06 +0200751 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200752 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
753 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200754
755 hdev = hci_dev_get(index);
756 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200757 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
758 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200759
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300760 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200761
762 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200763 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
764 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200765 goto failed;
766 }
767
768 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
769 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200770 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
771 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200772 goto failed;
773 }
774
775 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200776 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200777 goto failed;
778 }
779
780 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
781 if (!cmd) {
782 err = -ENOMEM;
783 goto failed;
784 }
785
786 if (cp->val)
787 scan = SCAN_PAGE;
788 else
789 scan = 0;
790
791 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
792 if (err < 0)
793 mgmt_pending_remove(cmd);
794
795failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300796 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200797 hci_dev_put(hdev);
798
799 return err;
800}
801
802static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
803 u16 data_len, struct sock *skip_sk)
804{
805 struct sk_buff *skb;
806 struct mgmt_hdr *hdr;
807
808 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
809 if (!skb)
810 return -ENOMEM;
811
812 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
813
814 hdr = (void *) skb_put(skb, sizeof(*hdr));
815 hdr->opcode = cpu_to_le16(event);
816 if (hdev)
817 hdr->index = cpu_to_le16(hdev->id);
818 else
819 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
820 hdr->len = cpu_to_le16(data_len);
821
822 if (data)
823 memcpy(skb_put(skb, data_len), data, data_len);
824
825 hci_send_to_sock(NULL, skb, skip_sk);
826 kfree_skb(skb);
827
828 return 0;
829}
830
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300831static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200832{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300833 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200834 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200835 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200836 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200837
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200838 BT_DBG("request for hci%u", index);
839
840 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200841 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
842 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200843
844 hdev = hci_dev_get(index);
845 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200846 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
847 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200848
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300849 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200850
851 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200852 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200853 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200854 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200855
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200856 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200857 if (err < 0)
858 goto failed;
859
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200860 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200861
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200862 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200863
864failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300865 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200866 hci_dev_put(hdev);
867
868 return err;
869}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200870
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300871static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200872{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300873 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200874 struct hci_dev *hdev;
875 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200876 int err;
877
Szymon Janc4e51eae2011-02-25 19:05:48 +0100878 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200879
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100880 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200881 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
882 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100883
Szymon Janc4e51eae2011-02-25 19:05:48 +0100884 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200885 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200886 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
887 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200888
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300889 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200890
891 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
892 if (!uuid) {
893 err = -ENOMEM;
894 goto failed;
895 }
896
897 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200898 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200899
900 list_add(&uuid->list, &hdev->uuids);
901
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200902 err = update_class(hdev);
903 if (err < 0)
904 goto failed;
905
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300906 err = update_eir(hdev);
907 if (err < 0)
908 goto failed;
909
Szymon Janc4e51eae2011-02-25 19:05:48 +0100910 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200911
912failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300913 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200914 hci_dev_put(hdev);
915
916 return err;
917}
918
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300919static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200920{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300921 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200922 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200923 struct hci_dev *hdev;
924 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 +0200925 int err, found;
926
Szymon Janc4e51eae2011-02-25 19:05:48 +0100927 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200928
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100929 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200930 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
931 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100932
Szymon Janc4e51eae2011-02-25 19:05:48 +0100933 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200934 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200935 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
936 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200937
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300938 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200939
940 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
941 err = hci_uuids_clear(hdev);
942 goto unlock;
943 }
944
945 found = 0;
946
947 list_for_each_safe(p, n, &hdev->uuids) {
948 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
949
950 if (memcmp(match->uuid, cp->uuid, 16) != 0)
951 continue;
952
953 list_del(&match->list);
954 found++;
955 }
956
957 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200958 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
959 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200960 goto unlock;
961 }
962
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200963 err = update_class(hdev);
964 if (err < 0)
965 goto unlock;
966
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300967 err = update_eir(hdev);
968 if (err < 0)
969 goto unlock;
970
Szymon Janc4e51eae2011-02-25 19:05:48 +0100971 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200972
973unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300974 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200975 hci_dev_put(hdev);
976
977 return err;
978}
979
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300980static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200981{
982 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300983 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200984 int err;
985
Szymon Janc4e51eae2011-02-25 19:05:48 +0100986 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200987
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100988 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200989 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
990 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100991
Szymon Janc4e51eae2011-02-25 19:05:48 +0100992 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200993 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200994 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
995 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200996
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300997 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200998
999 hdev->major_class = cp->major;
1000 hdev->minor_class = cp->minor;
1001
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001002 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001003 hci_dev_unlock(hdev);
1004 cancel_delayed_work_sync(&hdev->service_cache);
1005 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001006 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001007 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001008
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001009 err = update_class(hdev);
1010
1011 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001012 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001013
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001014 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001015 hci_dev_put(hdev);
1016
1017 return err;
1018}
1019
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001020static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001021{
1022 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001023 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001024 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001025 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001026
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001027 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001028 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1029 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001030
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001031 key_count = get_unaligned_le16(&cp->key_count);
1032
Johan Hedberg86742e12011-11-07 23:13:38 +02001033 expected_len = sizeof(*cp) + key_count *
1034 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001035 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001036 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001037 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001038 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1039 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001040 }
1041
Szymon Janc4e51eae2011-02-25 19:05:48 +01001042 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001043 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001044 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1045 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001046
Szymon Janc4e51eae2011-02-25 19:05:48 +01001047 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001048 key_count);
1049
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001050 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001051
1052 hci_link_keys_clear(hdev);
1053
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001054 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001055
1056 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001057 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001058 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001059 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001060
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001061 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001062 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001063
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001064 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001065 key->pin_len);
1066 }
1067
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001068 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1069
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001070 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001071 hci_dev_put(hdev);
1072
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001073 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001074}
1075
Johan Hedberg124f6e32012-02-09 13:50:12 +02001076static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001077{
1078 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001079 struct mgmt_cp_unpair_device *cp = data;
1080 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001081 struct hci_cp_disconnect dc;
1082 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001083 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001084 int err;
1085
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001086 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001087 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001088 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001089
Szymon Janc4e51eae2011-02-25 19:05:48 +01001090 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001091 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001092 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001093 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001094
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001095 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001096
Johan Hedberga8a1d192011-11-10 15:54:38 +02001097 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001098 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1099 rp.addr.type = cp->addr.type;
Johan Hedbergca69b792011-11-11 18:10:00 +02001100 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001101
Johan Hedberg124f6e32012-02-09 13:50:12 +02001102 if (cp->addr.type == MGMT_ADDR_BREDR)
1103 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1104 else
1105 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001106
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001107 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001108 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001109 goto unlock;
1110 }
1111
Johan Hedberga8a1d192011-11-10 15:54:38 +02001112 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02001113 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001114 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001115 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001116 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001117
Johan Hedberg124f6e32012-02-09 13:50:12 +02001118 if (cp->addr.type == MGMT_ADDR_BREDR)
1119 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1120 &cp->addr.bdaddr);
1121 else
1122 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1123 &cp->addr.bdaddr);
1124
Johan Hedberga8a1d192011-11-10 15:54:38 +02001125 if (!conn) {
Johan Hedberg124f6e32012-02-09 13:50:12 +02001126 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001127 sizeof(rp));
1128 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001129 }
1130
Johan Hedberg124f6e32012-02-09 13:50:12 +02001131 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1132 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001133 if (!cmd) {
1134 err = -ENOMEM;
1135 goto unlock;
1136 }
1137
1138 put_unaligned_le16(conn->handle, &dc.handle);
1139 dc.reason = 0x13; /* Remote User Terminated Connection */
1140 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1141 if (err < 0)
1142 mgmt_pending_remove(cmd);
1143
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001144unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001145 if (err < 0)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001146 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02001147 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001148 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001149 hci_dev_put(hdev);
1150
1151 return err;
1152}
1153
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001154static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001155{
1156 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001157 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001158 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001159 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001160 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001161 int err;
1162
1163 BT_DBG("");
1164
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001165 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001166 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1167 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001168
Szymon Janc4e51eae2011-02-25 19:05:48 +01001169 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001170 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001171 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1172 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001173
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001174 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001175
1176 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001177 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1178 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001179 goto failed;
1180 }
1181
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001182 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001183 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1184 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001185 goto failed;
1186 }
1187
Johan Hedberg88c3df12012-02-09 14:27:38 +02001188 if (cp->addr.type == MGMT_ADDR_BREDR)
1189 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1190 else
1191 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001192
Johan Hedberg8962ee72011-01-20 12:40:27 +02001193 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001194 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1195 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001196 goto failed;
1197 }
1198
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001199 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001200 if (!cmd) {
1201 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001202 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001203 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001204
1205 put_unaligned_le16(conn->handle, &dc.handle);
1206 dc.reason = 0x13; /* Remote User Terminated Connection */
1207
1208 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1209 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001210 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001211
1212failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001213 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001214 hci_dev_put(hdev);
1215
1216 return err;
1217}
1218
Johan Hedberg48264f02011-11-09 13:58:58 +02001219static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001220{
1221 switch (link_type) {
1222 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001223 switch (addr_type) {
1224 case ADDR_LE_DEV_PUBLIC:
1225 return MGMT_ADDR_LE_PUBLIC;
1226 case ADDR_LE_DEV_RANDOM:
1227 return MGMT_ADDR_LE_RANDOM;
1228 default:
1229 return MGMT_ADDR_INVALID;
1230 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001231 case ACL_LINK:
1232 return MGMT_ADDR_BREDR;
1233 default:
1234 return MGMT_ADDR_INVALID;
1235 }
1236}
1237
Szymon Janc8ce62842011-03-01 16:55:32 +01001238static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001239{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001240 struct mgmt_rp_get_connections *rp;
1241 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001242 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001243 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001244 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001245 int i, err;
1246
1247 BT_DBG("");
1248
Szymon Janc4e51eae2011-02-25 19:05:48 +01001249 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001250 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001251 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1252 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001253
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001254 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001255
1256 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001257 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1258 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1259 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001260 }
1261
Johan Hedberg4c659c32011-11-07 23:13:39 +02001262 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001263 rp = kmalloc(rp_len, GFP_ATOMIC);
1264 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001265 err = -ENOMEM;
1266 goto unlock;
1267 }
1268
Johan Hedberg2784eb42011-01-21 13:56:35 +02001269 put_unaligned_le16(count, &rp->conn_count);
1270
Johan Hedberg2784eb42011-01-21 13:56:35 +02001271 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001272 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001273 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1274 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001275 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001276 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001277 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1278 continue;
1279 i++;
1280 }
1281
1282 /* Recalculate length in case of filtered SCO connections, etc */
1283 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001284
Szymon Janc4e51eae2011-02-25 19:05:48 +01001285 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001286
1287unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001288 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001289 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001290 hci_dev_put(hdev);
1291 return err;
1292}
1293
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001294static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1295 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1296{
1297 struct pending_cmd *cmd;
1298 int err;
1299
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001300 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001301 sizeof(*cp));
1302 if (!cmd)
1303 return -ENOMEM;
1304
1305 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1306 &cp->bdaddr);
1307 if (err < 0)
1308 mgmt_pending_remove(cmd);
1309
1310 return err;
1311}
1312
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001313static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001314{
1315 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001316 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001317 struct mgmt_cp_pin_code_reply *cp = data;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001318 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001319 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001320 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001321 int err;
1322
1323 BT_DBG("");
1324
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001325 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001326 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1327 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001328
Szymon Janc4e51eae2011-02-25 19:05:48 +01001329 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001330 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001331 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1332 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001333
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001334 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001335
1336 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001337 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1338 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001339 goto failed;
1340 }
1341
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001342 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1343 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001344 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1345 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001346 goto failed;
1347 }
1348
1349 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1350 bacpy(&ncp.bdaddr, &cp->bdaddr);
1351
1352 BT_ERR("PIN code is not 16 bytes long");
1353
1354 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1355 if (err >= 0)
1356 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001357 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001358
1359 goto failed;
1360 }
1361
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001362 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1363 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001364 if (!cmd) {
1365 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001366 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001367 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001368
1369 bacpy(&reply.bdaddr, &cp->bdaddr);
1370 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001371 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001372
1373 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1374 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001375 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001376
1377failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001378 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001379 hci_dev_put(hdev);
1380
1381 return err;
1382}
1383
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001384static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001385{
1386 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001387 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001388 int err;
1389
1390 BT_DBG("");
1391
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001392 if (len != sizeof(*cp))
1393 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001394 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001395
Szymon Janc4e51eae2011-02-25 19:05:48 +01001396 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001397 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001398 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001399 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001400
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001401 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001402
1403 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001404 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001405 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001406 goto failed;
1407 }
1408
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001409 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001410
1411failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001412 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001413 hci_dev_put(hdev);
1414
1415 return err;
1416}
1417
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001418static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001419{
1420 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001421 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001422
1423 BT_DBG("");
1424
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001425 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001426 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1427 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001428
Szymon Janc4e51eae2011-02-25 19:05:48 +01001429 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001430 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001431 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1432 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001433
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001434 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001435
1436 hdev->io_capability = cp->io_capability;
1437
1438 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001439 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001440
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001441 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001442 hci_dev_put(hdev);
1443
Szymon Janc4e51eae2011-02-25 19:05:48 +01001444 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001445}
1446
Johan Hedberge9a416b2011-02-19 12:05:56 -03001447static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1448{
1449 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001450 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001451
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001452 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001453 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1454 continue;
1455
Johan Hedberge9a416b2011-02-19 12:05:56 -03001456 if (cmd->user_data != conn)
1457 continue;
1458
1459 return cmd;
1460 }
1461
1462 return NULL;
1463}
1464
1465static void pairing_complete(struct pending_cmd *cmd, u8 status)
1466{
1467 struct mgmt_rp_pair_device rp;
1468 struct hci_conn *conn = cmd->user_data;
1469
Johan Hedbergba4e5642011-11-11 00:07:34 +02001470 bacpy(&rp.addr.bdaddr, &conn->dst);
1471 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001472 rp.status = status;
1473
Szymon Janc4e51eae2011-02-25 19:05:48 +01001474 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001475
1476 /* So we don't get further callbacks for this connection */
1477 conn->connect_cfm_cb = NULL;
1478 conn->security_cfm_cb = NULL;
1479 conn->disconn_cfm_cb = NULL;
1480
1481 hci_conn_put(conn);
1482
Johan Hedberga664b5b2011-02-19 12:06:02 -03001483 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001484}
1485
1486static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1487{
1488 struct pending_cmd *cmd;
1489
1490 BT_DBG("status %u", status);
1491
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001492 cmd = find_pairing(conn);
1493 if (!cmd)
1494 BT_DBG("Unable to find a pending command");
1495 else
1496 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001497}
1498
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001499static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001500{
1501 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001502 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001503 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001504 struct pending_cmd *cmd;
1505 u8 sec_level, auth_type;
1506 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001507 int err;
1508
1509 BT_DBG("");
1510
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001511 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001512 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1513 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001514
Szymon Janc4e51eae2011-02-25 19:05:48 +01001515 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001516 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001517 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1518 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001519
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001520 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001521
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001522 sec_level = BT_SECURITY_MEDIUM;
1523 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001524 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001525 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001526 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001527
Johan Hedbergba4e5642011-11-11 00:07:34 +02001528 if (cp->addr.type == MGMT_ADDR_BREDR)
1529 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001530 auth_type);
1531 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001532 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001533 auth_type);
1534
Johan Hedberg1425acb2011-11-11 00:07:35 +02001535 memset(&rp, 0, sizeof(rp));
1536 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1537 rp.addr.type = cp->addr.type;
1538
Ville Tervo30e76272011-02-22 16:10:53 -03001539 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001540 rp.status = -PTR_ERR(conn);
1541 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1542 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001543 goto unlock;
1544 }
1545
1546 if (conn->connect_cfm_cb) {
1547 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001548 rp.status = EBUSY;
1549 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1550 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001551 goto unlock;
1552 }
1553
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001554 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001555 if (!cmd) {
1556 err = -ENOMEM;
1557 hci_conn_put(conn);
1558 goto unlock;
1559 }
1560
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001561 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001562 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001563 conn->connect_cfm_cb = pairing_complete_cb;
1564
Johan Hedberge9a416b2011-02-19 12:05:56 -03001565 conn->security_cfm_cb = pairing_complete_cb;
1566 conn->disconn_cfm_cb = pairing_complete_cb;
1567 conn->io_capability = cp->io_cap;
1568 cmd->user_data = conn;
1569
1570 if (conn->state == BT_CONNECTED &&
1571 hci_conn_security(conn, sec_level, auth_type))
1572 pairing_complete(cmd, 0);
1573
1574 err = 0;
1575
1576unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001577 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001578 hci_dev_put(hdev);
1579
1580 return err;
1581}
1582
Johan Hedberg28424702012-02-02 04:02:29 +02001583static int cancel_pair_device(struct sock *sk, u16 index,
1584 unsigned char *data, u16 len)
1585{
1586 struct mgmt_addr_info *addr = (void *) data;
1587 struct hci_dev *hdev;
1588 struct pending_cmd *cmd;
1589 struct hci_conn *conn;
1590 int err;
1591
1592 BT_DBG("");
1593
1594 if (len != sizeof(*addr))
1595 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1596 MGMT_STATUS_INVALID_PARAMS);
1597
1598 hdev = hci_dev_get(index);
1599 if (!hdev)
1600 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1601 MGMT_STATUS_INVALID_PARAMS);
1602
1603 hci_dev_lock(hdev);
1604
1605 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1606 if (!cmd) {
1607 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1608 MGMT_STATUS_INVALID_PARAMS);
1609 goto unlock;
1610 }
1611
1612 conn = cmd->user_data;
1613
1614 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1615 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1616 MGMT_STATUS_INVALID_PARAMS);
1617 goto unlock;
1618 }
1619
1620 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1621
1622 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr,
1623 sizeof(*addr));
1624unlock:
1625 hci_dev_unlock(hdev);
1626 hci_dev_put(hdev);
1627
1628 return err;
1629}
1630
Brian Gix0df4c182011-11-16 13:53:13 -08001631static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1632 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001633{
Johan Hedberga5c29682011-02-19 12:05:57 -03001634 struct pending_cmd *cmd;
1635 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001636 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001637 int err;
1638
Szymon Janc4e51eae2011-02-25 19:05:48 +01001639 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001640 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001641 return cmd_status(sk, index, mgmt_op,
1642 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001643
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001644 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001645
Johan Hedberga5c29682011-02-19 12:05:57 -03001646 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001647 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1648 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001649 }
1650
Brian Gix47c15e22011-11-16 13:53:14 -08001651 /*
1652 * Check for an existing ACL link, if present pair via
1653 * HCI commands.
1654 *
1655 * If no ACL link is present, check for an LE link and if
1656 * present, pair via the SMP engine.
1657 *
1658 * If neither ACL nor LE links are present, fail with error.
1659 */
1660 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1661 if (!conn) {
1662 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1663 if (!conn) {
1664 err = cmd_status(sk, index, mgmt_op,
1665 MGMT_STATUS_NOT_CONNECTED);
1666 goto done;
1667 }
1668
1669 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001670 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001671
Brian Gix5fe57d92011-12-21 16:12:13 -08001672 if (!err)
1673 err = cmd_status(sk, index, mgmt_op,
1674 MGMT_STATUS_SUCCESS);
1675 else
1676 err = cmd_status(sk, index, mgmt_op,
1677 MGMT_STATUS_FAILED);
1678
Brian Gix47c15e22011-11-16 13:53:14 -08001679 goto done;
1680 }
1681
Brian Gix0df4c182011-11-16 13:53:13 -08001682 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001683 if (!cmd) {
1684 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001685 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001686 }
1687
Brian Gix0df4c182011-11-16 13:53:13 -08001688 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001689 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1690 struct hci_cp_user_passkey_reply cp;
1691
1692 bacpy(&cp.bdaddr, bdaddr);
1693 cp.passkey = passkey;
1694 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1695 } else
1696 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1697
Johan Hedberga664b5b2011-02-19 12:06:02 -03001698 if (err < 0)
1699 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001700
Brian Gix0df4c182011-11-16 13:53:13 -08001701done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001702 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001703 hci_dev_put(hdev);
1704
1705 return err;
1706}
1707
Brian Gix0df4c182011-11-16 13:53:13 -08001708static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1709{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001710 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001711
1712 BT_DBG("");
1713
1714 if (len != sizeof(*cp))
1715 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1716 MGMT_STATUS_INVALID_PARAMS);
1717
1718 return user_pairing_resp(sk, index, &cp->bdaddr,
1719 MGMT_OP_USER_CONFIRM_REPLY,
1720 HCI_OP_USER_CONFIRM_REPLY, 0);
1721}
1722
1723static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1724 u16 len)
1725{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001726 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001727
1728 BT_DBG("");
1729
1730 if (len != sizeof(*cp))
1731 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1732 MGMT_STATUS_INVALID_PARAMS);
1733
1734 return user_pairing_resp(sk, index, &cp->bdaddr,
1735 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1736 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1737}
1738
Brian Gix604086b2011-11-23 08:28:33 -08001739static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1740{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001741 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001742
1743 BT_DBG("");
1744
1745 if (len != sizeof(*cp))
1746 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1747 EINVAL);
1748
1749 return user_pairing_resp(sk, index, &cp->bdaddr,
1750 MGMT_OP_USER_PASSKEY_REPLY,
1751 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1752}
1753
1754static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1755 u16 len)
1756{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001757 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001758
1759 BT_DBG("");
1760
1761 if (len != sizeof(*cp))
1762 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1763 EINVAL);
1764
1765 return user_pairing_resp(sk, index, &cp->bdaddr,
1766 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1767 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1768}
1769
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001770static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02001771 u16 len)
1772{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001773 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001774 struct hci_cp_write_local_name hci_cp;
1775 struct hci_dev *hdev;
1776 struct pending_cmd *cmd;
1777 int err;
1778
1779 BT_DBG("");
1780
1781 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001782 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1783 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001784
1785 hdev = hci_dev_get(index);
1786 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001787 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1788 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001789
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001790 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001791
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001792 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
1793 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001794 if (!cmd) {
1795 err = -ENOMEM;
1796 goto failed;
1797 }
1798
1799 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1800 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1801 &hci_cp);
1802 if (err < 0)
1803 mgmt_pending_remove(cmd);
1804
1805failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001806 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001807 hci_dev_put(hdev);
1808
1809 return err;
1810}
1811
Szymon Jancc35938b2011-03-22 13:12:21 +01001812static int read_local_oob_data(struct sock *sk, u16 index)
1813{
1814 struct hci_dev *hdev;
1815 struct pending_cmd *cmd;
1816 int err;
1817
1818 BT_DBG("hci%u", index);
1819
1820 hdev = hci_dev_get(index);
1821 if (!hdev)
1822 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001823 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001824
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001825 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001826
1827 if (!test_bit(HCI_UP, &hdev->flags)) {
1828 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001829 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001830 goto unlock;
1831 }
1832
1833 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1834 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001835 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001836 goto unlock;
1837 }
1838
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001839 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001840 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1841 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001842 goto unlock;
1843 }
1844
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001845 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001846 if (!cmd) {
1847 err = -ENOMEM;
1848 goto unlock;
1849 }
1850
1851 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1852 if (err < 0)
1853 mgmt_pending_remove(cmd);
1854
1855unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001856 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001857 hci_dev_put(hdev);
1858
1859 return err;
1860}
1861
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001862static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
1863 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01001864{
1865 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001866 struct mgmt_cp_add_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01001867 int err;
1868
1869 BT_DBG("hci%u ", index);
1870
1871 if (len != sizeof(*cp))
1872 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001873 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001874
1875 hdev = hci_dev_get(index);
1876 if (!hdev)
1877 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001878 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001879
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001880 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001881
1882 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1883 cp->randomizer);
1884 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001885 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1886 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001887 else
1888 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1889 0);
1890
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001891 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001892 hci_dev_put(hdev);
1893
1894 return err;
1895}
1896
1897static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001898 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01001899{
1900 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001901 struct mgmt_cp_remove_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01001902 int err;
1903
1904 BT_DBG("hci%u ", index);
1905
1906 if (len != sizeof(*cp))
1907 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001908 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001909
1910 hdev = hci_dev_get(index);
1911 if (!hdev)
1912 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001913 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001914
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001915 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001916
1917 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1918 if (err < 0)
1919 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001920 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001921 else
1922 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1923 NULL, 0);
1924
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001925 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001926 hci_dev_put(hdev);
1927
1928 return err;
1929}
1930
Johan Hedberg450dfda2011-11-12 11:58:22 +02001931static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001932 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001933{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001934 struct mgmt_cp_start_discovery *cp = data;
Andre Guedes3fd24152012-02-03 17:48:01 -03001935 unsigned long discov_type = cp->type;
Johan Hedberg14a53662011-04-27 10:29:56 -04001936 struct pending_cmd *cmd;
1937 struct hci_dev *hdev;
1938 int err;
1939
1940 BT_DBG("hci%u", index);
1941
Johan Hedberg450dfda2011-11-12 11:58:22 +02001942 if (len != sizeof(*cp))
1943 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1944 MGMT_STATUS_INVALID_PARAMS);
1945
Johan Hedberg14a53662011-04-27 10:29:56 -04001946 hdev = hci_dev_get(index);
1947 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001948 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1949 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001950
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001951 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001952
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001953 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001954 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1955 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001956 goto failed;
1957 }
1958
Johan Hedbergff9ef572012-01-04 14:23:45 +02001959 if (hdev->discovery.state != DISCOVERY_STOPPED) {
1960 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1961 MGMT_STATUS_BUSY);
1962 goto failed;
1963 }
1964
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001965 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001966 if (!cmd) {
1967 err = -ENOMEM;
1968 goto failed;
1969 }
1970
Andre Guedes3fd24152012-02-03 17:48:01 -03001971 if (test_bit(MGMT_ADDR_BREDR, &discov_type))
1972 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
1973 else if (test_bit(MGMT_ADDR_LE_PUBLIC, &discov_type) &&
1974 test_bit(MGMT_ADDR_LE_RANDOM, &discov_type))
1975 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
1976 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
1977 else
1978 err = -EINVAL;
1979
Johan Hedberg14a53662011-04-27 10:29:56 -04001980 if (err < 0)
1981 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02001982 else
1983 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04001984
1985failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001986 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001987 hci_dev_put(hdev);
1988
1989 return err;
1990}
1991
1992static int stop_discovery(struct sock *sk, u16 index)
1993{
1994 struct hci_dev *hdev;
1995 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001996 struct hci_cp_remote_name_req_cancel cp;
1997 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04001998 int err;
1999
2000 BT_DBG("hci%u", index);
2001
2002 hdev = hci_dev_get(index);
2003 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002004 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2005 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002006
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002007 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002008
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002009 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002010 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2011 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002012 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002013 }
2014
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002015 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002016 if (!cmd) {
2017 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002018 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002019 }
2020
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002021 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
2022 err = hci_cancel_inquiry(hdev);
2023 if (err < 0)
2024 mgmt_pending_remove(cmd);
2025 else
2026 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2027 goto unlock;
2028 }
2029
2030 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2031 if (!e) {
2032 mgmt_pending_remove(cmd);
2033 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2034 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2035 goto unlock;
2036 }
2037
2038 bacpy(&cp.bdaddr, &e->data.bdaddr);
2039 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2040 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002041 if (err < 0)
2042 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002043 else
2044 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002045
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002046unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002047 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002048 hci_dev_put(hdev);
2049
2050 return err;
2051}
2052
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002053static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002054{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002055 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002056 struct inquiry_entry *e;
2057 struct hci_dev *hdev;
2058 int err;
2059
2060 BT_DBG("hci%u", index);
2061
2062 if (len != sizeof(*cp))
2063 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2064 MGMT_STATUS_INVALID_PARAMS);
2065
2066 hdev = hci_dev_get(index);
2067 if (!hdev)
2068 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2069 MGMT_STATUS_INVALID_PARAMS);
2070
2071 hci_dev_lock(hdev);
2072
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002073 if (!hci_discovery_active(hdev)) {
2074 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2075 MGMT_STATUS_FAILED);
2076 goto failed;
2077 }
2078
Johan Hedberg561aafb2012-01-04 13:31:59 +02002079 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr);
2080 if (!e) {
2081 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2082 MGMT_STATUS_INVALID_PARAMS);
2083 goto failed;
2084 }
2085
2086 if (cp->name_known) {
2087 e->name_state = NAME_KNOWN;
2088 list_del(&e->list);
2089 } else {
2090 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002091 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002092 }
2093
2094 err = 0;
2095
2096failed:
2097 hci_dev_unlock(hdev);
2098
2099 return err;
2100}
2101
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002102static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002103{
2104 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002105 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002106 int err;
2107
2108 BT_DBG("hci%u", index);
2109
Antti Julku7fbec222011-06-15 12:01:15 +03002110 if (len != sizeof(*cp))
2111 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002112 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002113
2114 hdev = hci_dev_get(index);
2115 if (!hdev)
2116 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002117 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002118
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002119 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002120
Antti Julku7fbec222011-06-15 12:01:15 +03002121 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03002122 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002123 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2124 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002125 else
2126 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2127 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002128
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002129 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002130 hci_dev_put(hdev);
2131
2132 return err;
2133}
2134
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002135static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002136{
2137 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002138 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002139 int err;
2140
2141 BT_DBG("hci%u", index);
2142
Antti Julku7fbec222011-06-15 12:01:15 +03002143 if (len != sizeof(*cp))
2144 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002145 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002146
2147 hdev = hci_dev_get(index);
2148 if (!hdev)
2149 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002150 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002151
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002152 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002153
Antti Julku7fbec222011-06-15 12:01:15 +03002154 err = hci_blacklist_del(hdev, &cp->bdaddr);
2155
2156 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002157 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2158 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002159 else
2160 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2161 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002162
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002163 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002164 hci_dev_put(hdev);
2165
2166 return err;
2167}
2168
Antti Julkuf6422ec2011-06-22 13:11:56 +03002169static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002170 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002171{
2172 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002173 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002174 struct hci_cp_write_page_scan_activity acp;
2175 u8 type;
2176 int err;
2177
2178 BT_DBG("hci%u", index);
2179
2180 if (len != sizeof(*cp))
2181 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002182 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002183
2184 hdev = hci_dev_get(index);
2185 if (!hdev)
2186 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002187 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002188
2189 hci_dev_lock(hdev);
2190
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002191 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002192 type = PAGE_SCAN_TYPE_INTERLACED;
2193 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2194 } else {
2195 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2196 acp.interval = 0x0800; /* default 1.28 sec page scan */
2197 }
2198
2199 acp.window = 0x0012; /* default 11.25 msec page scan window */
2200
2201 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2202 sizeof(acp), &acp);
2203 if (err < 0) {
2204 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002205 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002206 goto done;
2207 }
2208
2209 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2210 if (err < 0) {
2211 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002212 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002213 goto done;
2214 }
2215
2216 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2217 NULL, 0);
2218done:
2219 hci_dev_unlock(hdev);
2220 hci_dev_put(hdev);
2221
2222 return err;
2223}
2224
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002225static int load_long_term_keys(struct sock *sk, u16 index,
2226 void *cp_data, u16 len)
2227{
2228 struct hci_dev *hdev;
2229 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2230 u16 key_count, expected_len;
2231 int i;
2232
2233 if (len < sizeof(*cp))
2234 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2235 EINVAL);
2236
2237 key_count = get_unaligned_le16(&cp->key_count);
2238
2239 expected_len = sizeof(*cp) + key_count *
2240 sizeof(struct mgmt_ltk_info);
2241 if (expected_len != len) {
2242 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2243 len, expected_len);
2244 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2245 EINVAL);
2246 }
2247
2248 hdev = hci_dev_get(index);
2249 if (!hdev)
2250 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2251 ENODEV);
2252
2253 BT_DBG("hci%u key_count %u", index, key_count);
2254
2255 hci_dev_lock(hdev);
2256
2257 hci_smp_ltks_clear(hdev);
2258
2259 for (i = 0; i < key_count; i++) {
2260 struct mgmt_ltk_info *key = &cp->keys[i];
2261 u8 type;
2262
2263 if (key->master)
2264 type = HCI_SMP_LTK;
2265 else
2266 type = HCI_SMP_LTK_SLAVE;
2267
2268 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2269 type, 0, key->authenticated, key->val,
2270 key->enc_size, key->ediv, key->rand);
2271 }
2272
2273 hci_dev_unlock(hdev);
2274 hci_dev_put(hdev);
2275
2276 return 0;
2277}
2278
Johan Hedberg03811012010-12-08 00:21:06 +02002279int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2280{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002281 void *buf;
2282 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002283 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002284 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002285 int err;
2286
2287 BT_DBG("got %zu bytes", msglen);
2288
2289 if (msglen < sizeof(*hdr))
2290 return -EINVAL;
2291
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002292 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002293 if (!buf)
2294 return -ENOMEM;
2295
2296 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2297 err = -EFAULT;
2298 goto done;
2299 }
2300
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002301 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002302 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002303 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002304 len = get_unaligned_le16(&hdr->len);
2305
2306 if (len != msglen - sizeof(*hdr)) {
2307 err = -EINVAL;
2308 goto done;
2309 }
2310
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002311 cp = buf + sizeof(*hdr);
2312
Johan Hedberg03811012010-12-08 00:21:06 +02002313 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002314 case MGMT_OP_READ_VERSION:
2315 err = read_version(sk);
2316 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002317 case MGMT_OP_READ_INDEX_LIST:
2318 err = read_index_list(sk);
2319 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002320 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002321 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002322 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002323 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002324 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002325 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002326 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002327 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002328 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002329 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002330 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002331 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002332 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002333 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002334 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002335 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002336 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002337 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002338 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002339 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002340 break;
2341 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002342 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002343 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002344 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002345 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002346 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002347 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002348 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002349 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002350 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002351 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002352 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002353 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002354 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002355 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002356 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002357 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002358 break;
2359 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002360 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002361 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002362 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002363 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002364 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002365 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002366 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002367 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002368 case MGMT_OP_CANCEL_PAIR_DEVICE:
2369 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2370 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002371 case MGMT_OP_UNPAIR_DEVICE:
2372 err = unpair_device(sk, index, cp, len);
2373 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002374 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002375 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002376 break;
2377 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002378 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002379 break;
Brian Gix604086b2011-11-23 08:28:33 -08002380 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002381 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002382 break;
2383 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002384 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002385 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002386 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002387 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002388 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002389 case MGMT_OP_READ_LOCAL_OOB_DATA:
2390 err = read_local_oob_data(sk, index);
2391 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002392 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002393 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002394 break;
2395 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002396 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002397 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002398 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002399 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002400 break;
2401 case MGMT_OP_STOP_DISCOVERY:
2402 err = stop_discovery(sk, index);
2403 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002404 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002405 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002406 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002407 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002408 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002409 break;
2410 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002411 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002412 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002413 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2414 err = load_long_term_keys(sk, index, cp, len);
2415 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002416 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002417 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002418 err = cmd_status(sk, index, opcode,
2419 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002420 break;
2421 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002422
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002423 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002424 goto done;
2425
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002426 err = msglen;
2427
2428done:
2429 kfree(buf);
2430 return err;
2431}
2432
Johan Hedbergb24752f2011-11-03 14:40:33 +02002433static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2434{
2435 u8 *status = data;
2436
2437 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2438 mgmt_pending_remove(cmd);
2439}
2440
Johan Hedberg744cf192011-11-08 20:40:14 +02002441int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002442{
Johan Hedberg744cf192011-11-08 20:40:14 +02002443 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002444}
2445
Johan Hedberg744cf192011-11-08 20:40:14 +02002446int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002447{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002448 u8 status = ENODEV;
2449
Johan Hedberg744cf192011-11-08 20:40:14 +02002450 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002451
Johan Hedberg744cf192011-11-08 20:40:14 +02002452 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002453}
2454
2455struct cmd_lookup {
2456 u8 val;
2457 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002458 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002459};
2460
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002461static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002462{
Johan Hedberg03811012010-12-08 00:21:06 +02002463 struct cmd_lookup *match = data;
2464
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002465 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002466
2467 list_del(&cmd->list);
2468
2469 if (match->sk == NULL) {
2470 match->sk = cmd->sk;
2471 sock_hold(match->sk);
2472 }
2473
2474 mgmt_pending_free(cmd);
2475}
2476
Johan Hedberg744cf192011-11-08 20:40:14 +02002477int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002478{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002479 struct cmd_lookup match = { powered, NULL, hdev };
2480 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002481 int ret;
2482
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002483 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002484
Johan Hedbergb24752f2011-11-03 14:40:33 +02002485 if (!powered) {
2486 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002487 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002488 }
2489
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002490 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002491
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002492 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2493 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002494
2495 if (match.sk)
2496 sock_put(match.sk);
2497
2498 return ret;
2499}
2500
Johan Hedberg744cf192011-11-08 20:40:14 +02002501int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002502{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002503 struct cmd_lookup match = { discoverable, NULL, hdev };
2504 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002505 int ret;
2506
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002507 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002508
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002509 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002510
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002511 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002512 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002513 if (match.sk)
2514 sock_put(match.sk);
2515
2516 return ret;
2517}
2518
Johan Hedberg744cf192011-11-08 20:40:14 +02002519int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002520{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002521 __le32 ev;
2522 struct cmd_lookup match = { connectable, NULL, hdev };
Johan Hedberg03811012010-12-08 00:21:06 +02002523 int ret;
2524
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002525 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2526 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002527
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002528 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002529
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002530 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002531
2532 if (match.sk)
2533 sock_put(match.sk);
2534
2535 return ret;
2536}
2537
Johan Hedberg744cf192011-11-08 20:40:14 +02002538int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002539{
Johan Hedbergca69b792011-11-11 18:10:00 +02002540 u8 mgmt_err = mgmt_status(status);
2541
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002542 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002543 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002544 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002545
2546 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002547 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002548 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002549
2550 return 0;
2551}
2552
Johan Hedberg744cf192011-11-08 20:40:14 +02002553int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2554 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002555{
Johan Hedberg86742e12011-11-07 23:13:38 +02002556 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002557
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002558 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002559
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002560 ev.store_hint = persistent;
2561 bacpy(&ev.key.bdaddr, &key->bdaddr);
2562 ev.key.type = key->type;
2563 memcpy(ev.key.val, key->val, 16);
2564 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002565
Johan Hedberg744cf192011-11-08 20:40:14 +02002566 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002567}
Johan Hedbergf7520542011-01-20 12:34:39 +02002568
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002569int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2570{
2571 struct mgmt_ev_new_long_term_key ev;
2572
2573 memset(&ev, 0, sizeof(ev));
2574
2575 ev.store_hint = persistent;
2576 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2577 ev.key.addr.type = key->bdaddr_type;
2578 ev.key.authenticated = key->authenticated;
2579 ev.key.enc_size = key->enc_size;
2580 ev.key.ediv = key->ediv;
2581
2582 if (key->type == HCI_SMP_LTK)
2583 ev.key.master = 1;
2584
2585 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2586 memcpy(ev.key.val, key->val, sizeof(key->val));
2587
2588 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2589 &ev, sizeof(ev), NULL);
2590}
2591
Johan Hedbergafc747a2012-01-15 18:11:07 +02002592int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002593 u8 addr_type, u8 *name, u8 name_len,
2594 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002595{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002596 char buf[512];
2597 struct mgmt_ev_device_connected *ev = (void *) buf;
2598 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002599
Johan Hedbergb644ba32012-01-17 21:48:47 +02002600 bacpy(&ev->addr.bdaddr, bdaddr);
2601 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002602
Johan Hedbergb644ba32012-01-17 21:48:47 +02002603 if (name_len > 0)
2604 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2605 name, name_len);
2606
2607 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2608 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2609 EIR_CLASS_OF_DEV, dev_class, 3);
2610
2611 put_unaligned_le16(eir_len, &ev->eir_len);
2612
2613 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2614 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002615}
2616
Johan Hedberg8962ee72011-01-20 12:40:27 +02002617static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2618{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002619 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002620 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002621 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002622
Johan Hedberg88c3df12012-02-09 14:27:38 +02002623 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2624 rp.addr.type = cp->addr.type;
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002625 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002626
Szymon Janc4e51eae2011-02-25 19:05:48 +01002627 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002628
2629 *sk = cmd->sk;
2630 sock_hold(*sk);
2631
Johan Hedberga664b5b2011-02-19 12:06:02 -03002632 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002633}
2634
Johan Hedberg124f6e32012-02-09 13:50:12 +02002635static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002636{
2637 u8 *status = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002638 struct mgmt_cp_unpair_device *cp = cmd->param;
2639 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002640
2641 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002642 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2643 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002644 if (status != NULL)
2645 rp.status = *status;
2646
Johan Hedberg124f6e32012-02-09 13:50:12 +02002647 cmd_complete(cmd->sk, cmd->index, MGMT_OP_UNPAIR_DEVICE, &rp,
Johan Hedberga8a1d192011-11-10 15:54:38 +02002648 sizeof(rp));
2649
2650 mgmt_pending_remove(cmd);
2651}
2652
Johan Hedbergafc747a2012-01-15 18:11:07 +02002653int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2654 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002655{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002656 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002657 struct sock *sk = NULL;
2658 int err;
2659
Johan Hedberg744cf192011-11-08 20:40:14 +02002660 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002661
Johan Hedbergf7520542011-01-20 12:34:39 +02002662 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002663 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002664
Johan Hedbergafc747a2012-01-15 18:11:07 +02002665 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2666 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002667
2668 if (sk)
2669 sock_put(sk);
2670
Johan Hedberg124f6e32012-02-09 13:50:12 +02002671 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
2672 NULL);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002673
Johan Hedberg8962ee72011-01-20 12:40:27 +02002674 return err;
2675}
2676
Johan Hedberg88c3df12012-02-09 14:27:38 +02002677int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
2678 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002679{
Johan Hedberg88c3df12012-02-09 14:27:38 +02002680 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002681 struct pending_cmd *cmd;
2682 int err;
2683
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002684 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002685 if (!cmd)
2686 return -ENOENT;
2687
Johan Hedberg88c3df12012-02-09 14:27:38 +02002688 bacpy(&rp.addr.bdaddr, bdaddr);
2689 rp.addr.type = link_to_mgmt(link_type, addr_type);
2690 rp.status = mgmt_status(status);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002691
Johan Hedberg88c3df12012-02-09 14:27:38 +02002692 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002693 &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002694
Johan Hedberga664b5b2011-02-19 12:06:02 -03002695 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002696
2697 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002698}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002699
Johan Hedberg48264f02011-11-09 13:58:58 +02002700int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2701 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002702{
2703 struct mgmt_ev_connect_failed ev;
2704
Johan Hedberg4c659c32011-11-07 23:13:39 +02002705 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002706 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002707 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002708
Johan Hedberg744cf192011-11-08 20:40:14 +02002709 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002710}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002711
Johan Hedberg744cf192011-11-08 20:40:14 +02002712int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002713{
2714 struct mgmt_ev_pin_code_request ev;
2715
Johan Hedberg980e1a52011-01-22 06:10:07 +02002716 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002717 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002718
Johan Hedberg744cf192011-11-08 20:40:14 +02002719 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002720 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002721}
2722
Johan Hedberg744cf192011-11-08 20:40:14 +02002723int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2724 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002725{
2726 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002727 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002728 int err;
2729
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002730 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002731 if (!cmd)
2732 return -ENOENT;
2733
Johan Hedbergac56fb12011-02-19 12:05:59 -03002734 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002735 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002736
Johan Hedberg744cf192011-11-08 20:40:14 +02002737 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002738 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002739
Johan Hedberga664b5b2011-02-19 12:06:02 -03002740 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002741
2742 return err;
2743}
2744
Johan Hedberg744cf192011-11-08 20:40:14 +02002745int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2746 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002747{
2748 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002749 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002750 int err;
2751
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002752 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002753 if (!cmd)
2754 return -ENOENT;
2755
Johan Hedbergac56fb12011-02-19 12:05:59 -03002756 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002757 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002758
Johan Hedberg744cf192011-11-08 20:40:14 +02002759 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002760 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002761
Johan Hedberga664b5b2011-02-19 12:06:02 -03002762 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002763
2764 return err;
2765}
Johan Hedberga5c29682011-02-19 12:05:57 -03002766
Johan Hedberg744cf192011-11-08 20:40:14 +02002767int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2768 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002769{
2770 struct mgmt_ev_user_confirm_request ev;
2771
Johan Hedberg744cf192011-11-08 20:40:14 +02002772 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002773
Johan Hedberga5c29682011-02-19 12:05:57 -03002774 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002775 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002776 put_unaligned_le32(value, &ev.value);
2777
Johan Hedberg744cf192011-11-08 20:40:14 +02002778 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002779 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002780}
2781
Brian Gix604086b2011-11-23 08:28:33 -08002782int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2783{
2784 struct mgmt_ev_user_passkey_request ev;
2785
2786 BT_DBG("%s", hdev->name);
2787
2788 bacpy(&ev.bdaddr, bdaddr);
2789
2790 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2791 NULL);
2792}
2793
Brian Gix0df4c182011-11-16 13:53:13 -08002794static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002795 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002796{
2797 struct pending_cmd *cmd;
2798 struct mgmt_rp_user_confirm_reply rp;
2799 int err;
2800
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002801 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002802 if (!cmd)
2803 return -ENOENT;
2804
Johan Hedberga5c29682011-02-19 12:05:57 -03002805 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002806 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002807 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002808
Johan Hedberga664b5b2011-02-19 12:06:02 -03002809 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002810
2811 return err;
2812}
2813
Johan Hedberg744cf192011-11-08 20:40:14 +02002814int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2815 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002816{
Brian Gix0df4c182011-11-16 13:53:13 -08002817 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002818 MGMT_OP_USER_CONFIRM_REPLY);
2819}
2820
Johan Hedberg744cf192011-11-08 20:40:14 +02002821int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2822 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002823{
Brian Gix0df4c182011-11-16 13:53:13 -08002824 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002825 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2826}
Johan Hedberg2a611692011-02-19 12:06:00 -03002827
Brian Gix604086b2011-11-23 08:28:33 -08002828int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2829 u8 status)
2830{
2831 return user_pairing_resp_complete(hdev, bdaddr, status,
2832 MGMT_OP_USER_PASSKEY_REPLY);
2833}
2834
2835int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2836 bdaddr_t *bdaddr, u8 status)
2837{
2838 return user_pairing_resp_complete(hdev, bdaddr, status,
2839 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2840}
2841
Johan Hedberg744cf192011-11-08 20:40:14 +02002842int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002843{
2844 struct mgmt_ev_auth_failed ev;
2845
Johan Hedberg2a611692011-02-19 12:06:00 -03002846 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002847 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002848
Johan Hedberg744cf192011-11-08 20:40:14 +02002849 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002850}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002851
Johan Hedberg744cf192011-11-08 20:40:14 +02002852int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002853{
2854 struct pending_cmd *cmd;
2855 struct mgmt_cp_set_local_name ev;
2856 int err;
2857
2858 memset(&ev, 0, sizeof(ev));
2859 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2860
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002861 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002862 if (!cmd)
2863 goto send_event;
2864
2865 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002866 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002867 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002868 goto failed;
2869 }
2870
Johan Hedberg744cf192011-11-08 20:40:14 +02002871 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002872
Johan Hedberg744cf192011-11-08 20:40:14 +02002873 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002874 sizeof(ev));
2875 if (err < 0)
2876 goto failed;
2877
2878send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002879 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002880 cmd ? cmd->sk : NULL);
2881
2882failed:
2883 if (cmd)
2884 mgmt_pending_remove(cmd);
2885 return err;
2886}
Szymon Jancc35938b2011-03-22 13:12:21 +01002887
Johan Hedberg744cf192011-11-08 20:40:14 +02002888int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2889 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002890{
2891 struct pending_cmd *cmd;
2892 int err;
2893
Johan Hedberg744cf192011-11-08 20:40:14 +02002894 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002895
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002896 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002897 if (!cmd)
2898 return -ENOENT;
2899
2900 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002901 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002902 MGMT_OP_READ_LOCAL_OOB_DATA,
2903 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002904 } else {
2905 struct mgmt_rp_read_local_oob_data rp;
2906
2907 memcpy(rp.hash, hash, sizeof(rp.hash));
2908 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2909
Johan Hedberg744cf192011-11-08 20:40:14 +02002910 err = cmd_complete(cmd->sk, hdev->id,
2911 MGMT_OP_READ_LOCAL_OOB_DATA,
2912 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002913 }
2914
2915 mgmt_pending_remove(cmd);
2916
2917 return err;
2918}
Johan Hedberge17acd42011-03-30 23:57:16 +03002919
Johan Hedberg48264f02011-11-09 13:58:58 +02002920int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002921 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02002922 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03002923{
Johan Hedberge319d2e2012-01-15 19:51:59 +02002924 char buf[512];
2925 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02002926 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03002927
Johan Hedberg1dc06092012-01-15 21:01:23 +02002928 /* Leave 5 bytes for a potential CoD field */
2929 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03002930 return -EINVAL;
2931
Johan Hedberg1dc06092012-01-15 21:01:23 +02002932 memset(buf, 0, sizeof(buf));
2933
Johan Hedberge319d2e2012-01-15 19:51:59 +02002934 bacpy(&ev->addr.bdaddr, bdaddr);
2935 ev->addr.type = link_to_mgmt(link_type, addr_type);
2936 ev->rssi = rssi;
2937 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03002938
Johan Hedberg1dc06092012-01-15 21:01:23 +02002939 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02002940 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03002941
Johan Hedberg1dc06092012-01-15 21:01:23 +02002942 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
2943 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
2944 dev_class, 3);
2945
2946 put_unaligned_le16(eir_len, &ev->eir_len);
2947
2948 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03002949
Johan Hedberge319d2e2012-01-15 19:51:59 +02002950 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002951}
Johan Hedberga88a9652011-03-30 13:18:12 +03002952
Johan Hedbergb644ba32012-01-17 21:48:47 +02002953int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2954 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03002955{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002956 struct mgmt_ev_device_found *ev;
2957 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
2958 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03002959
Johan Hedbergb644ba32012-01-17 21:48:47 +02002960 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03002961
Johan Hedbergb644ba32012-01-17 21:48:47 +02002962 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03002963
Johan Hedbergb644ba32012-01-17 21:48:47 +02002964 bacpy(&ev->addr.bdaddr, bdaddr);
2965 ev->addr.type = link_to_mgmt(link_type, addr_type);
2966 ev->rssi = rssi;
2967
2968 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
2969 name_len);
2970
2971 put_unaligned_le16(eir_len, &ev->eir_len);
2972
Johan Hedberg053c7e02012-02-04 00:06:00 +02002973 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
2974 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002975}
Johan Hedberg314b2382011-04-27 10:29:57 -04002976
Andre Guedes7a135102011-11-09 17:14:25 -03002977int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002978{
2979 struct pending_cmd *cmd;
2980 int err;
2981
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002982 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002983 if (!cmd)
2984 return -ENOENT;
2985
Johan Hedbergca69b792011-11-11 18:10:00 +02002986 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002987 mgmt_pending_remove(cmd);
2988
2989 return err;
2990}
2991
Andre Guedese6d465c2011-11-09 17:14:26 -03002992int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2993{
2994 struct pending_cmd *cmd;
2995 int err;
2996
2997 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2998 if (!cmd)
2999 return -ENOENT;
3000
Andre Guedese75a8b0c2012-01-02 16:50:53 -03003001 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02003002 mgmt_pending_remove(cmd);
3003
3004 return err;
3005}
Johan Hedberg314b2382011-04-27 10:29:57 -04003006
Johan Hedberg744cf192011-11-08 20:40:14 +02003007int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003008{
Johan Hedberg164a6e72011-11-01 17:06:44 +02003009 struct pending_cmd *cmd;
3010
Andre Guedes343fb142011-11-22 17:14:19 -03003011 BT_DBG("%s discovering %u", hdev->name, discovering);
3012
Johan Hedberg164a6e72011-11-01 17:06:44 +02003013 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003014 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003015 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003016 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003017
3018 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003019 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003020 mgmt_pending_remove(cmd);
3021 }
3022
Johan Hedberg744cf192011-11-08 20:40:14 +02003023 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04003024 sizeof(discovering), NULL);
3025}
Antti Julku5e762442011-08-25 16:48:02 +03003026
Johan Hedberg744cf192011-11-08 20:40:14 +02003027int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03003028{
3029 struct pending_cmd *cmd;
3030 struct mgmt_ev_device_blocked ev;
3031
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003032 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003033
3034 bacpy(&ev.bdaddr, bdaddr);
3035
Johan Hedberg744cf192011-11-08 20:40:14 +02003036 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3037 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003038}
3039
Johan Hedberg744cf192011-11-08 20:40:14 +02003040int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03003041{
3042 struct pending_cmd *cmd;
3043 struct mgmt_ev_device_unblocked ev;
3044
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003045 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003046
3047 bacpy(&ev.bdaddr, bdaddr);
3048
Johan Hedberg744cf192011-11-08 20:40:14 +02003049 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3050 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003051}