blob: 8c9de58779c71dbfda551c6ba73f32f78b503c59 [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 Guedes2519a1f2011-11-07 11:45:24 -030047#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
48
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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200158 kfree_skb(skb);
159
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300160 return err;
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200308
Johan Hedberg84bde9d2012-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 Hedbergf7b64e62010-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 Hedberg84bde9d2012-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-12-13 21:07:06 +0200692
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300693 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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 Hedbergf7b64e62010-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
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001076static int remove_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001077{
1078 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001079 struct mgmt_cp_remove_keys *cp = data;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001080 struct mgmt_rp_remove_keys rp;
1081 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 Hedbergca69b792011-11-11 18:10:00 +02001087 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1088 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 Hedbergca69b792011-11-11 18:10:00 +02001092 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1093 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));
1098 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001099 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001100
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001101 err = hci_remove_ltk(hdev, &cp->bdaddr);
1102 if (err < 0) {
1103 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err);
1104 goto unlock;
1105 }
1106
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001107 err = hci_remove_link_key(hdev, &cp->bdaddr);
1108 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001109 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001110 goto unlock;
1111 }
1112
Johan Hedberga8a1d192011-11-10 15:54:38 +02001113 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1114 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1115 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001116 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001117 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001118
1119 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001120 if (!conn) {
1121 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1122 sizeof(rp));
1123 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001124 }
1125
Johan Hedberga8a1d192011-11-10 15:54:38 +02001126 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1127 if (!cmd) {
1128 err = -ENOMEM;
1129 goto unlock;
1130 }
1131
1132 put_unaligned_le16(conn->handle, &dc.handle);
1133 dc.reason = 0x13; /* Remote User Terminated Connection */
1134 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1135 if (err < 0)
1136 mgmt_pending_remove(cmd);
1137
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001138unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001139 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001140 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1141 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001142 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001143 hci_dev_put(hdev);
1144
1145 return err;
1146}
1147
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001148static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001149{
1150 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001151 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001152 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001153 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001154 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001155 int err;
1156
1157 BT_DBG("");
1158
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001159 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001160 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1161 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001162
Szymon Janc4e51eae2011-02-25 19:05:48 +01001163 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001164 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001165 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1166 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001167
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001168 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001169
1170 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001171 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1172 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001173 goto failed;
1174 }
1175
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001176 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001177 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1178 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001179 goto failed;
1180 }
1181
1182 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001183 if (!conn)
1184 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1185
Johan Hedberg8962ee72011-01-20 12:40:27 +02001186 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001187 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1188 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001189 goto failed;
1190 }
1191
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001192 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001193 if (!cmd) {
1194 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001195 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001196 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001197
1198 put_unaligned_le16(conn->handle, &dc.handle);
1199 dc.reason = 0x13; /* Remote User Terminated Connection */
1200
1201 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1202 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001203 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001204
1205failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001206 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001207 hci_dev_put(hdev);
1208
1209 return err;
1210}
1211
Johan Hedberg48264f02011-11-09 13:58:58 +02001212static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001213{
1214 switch (link_type) {
1215 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001216 switch (addr_type) {
1217 case ADDR_LE_DEV_PUBLIC:
1218 return MGMT_ADDR_LE_PUBLIC;
1219 case ADDR_LE_DEV_RANDOM:
1220 return MGMT_ADDR_LE_RANDOM;
1221 default:
1222 return MGMT_ADDR_INVALID;
1223 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001224 case ACL_LINK:
1225 return MGMT_ADDR_BREDR;
1226 default:
1227 return MGMT_ADDR_INVALID;
1228 }
1229}
1230
Szymon Janc8ce62842011-03-01 16:55:32 +01001231static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001232{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001233 struct mgmt_rp_get_connections *rp;
1234 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001235 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001236 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001237 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001238 int i, err;
1239
1240 BT_DBG("");
1241
Szymon Janc4e51eae2011-02-25 19:05:48 +01001242 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001243 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001244 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1245 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001246
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001247 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001248
1249 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001250 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1251 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1252 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001253 }
1254
Johan Hedberg4c659c32011-11-07 23:13:39 +02001255 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001256 rp = kmalloc(rp_len, GFP_ATOMIC);
1257 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001258 err = -ENOMEM;
1259 goto unlock;
1260 }
1261
Johan Hedberg2784eb42011-01-21 13:56:35 +02001262 put_unaligned_le16(count, &rp->conn_count);
1263
Johan Hedberg2784eb42011-01-21 13:56:35 +02001264 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001265 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001266 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1267 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001268 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001269 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001270 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1271 continue;
1272 i++;
1273 }
1274
1275 /* Recalculate length in case of filtered SCO connections, etc */
1276 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001277
Szymon Janc4e51eae2011-02-25 19:05:48 +01001278 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001279
1280unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001281 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001282 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001283 hci_dev_put(hdev);
1284 return err;
1285}
1286
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001287static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1288 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1289{
1290 struct pending_cmd *cmd;
1291 int err;
1292
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001293 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001294 sizeof(*cp));
1295 if (!cmd)
1296 return -ENOMEM;
1297
1298 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1299 &cp->bdaddr);
1300 if (err < 0)
1301 mgmt_pending_remove(cmd);
1302
1303 return err;
1304}
1305
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001306static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001307{
1308 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001309 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001310 struct mgmt_cp_pin_code_reply *cp = data;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001311 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001312 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001313 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001314 int err;
1315
1316 BT_DBG("");
1317
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001318 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001319 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1320 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001321
Szymon Janc4e51eae2011-02-25 19:05:48 +01001322 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001323 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001324 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1325 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001326
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001327 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001328
1329 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001330 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1331 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001332 goto failed;
1333 }
1334
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001335 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1336 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001337 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1338 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001339 goto failed;
1340 }
1341
1342 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1343 bacpy(&ncp.bdaddr, &cp->bdaddr);
1344
1345 BT_ERR("PIN code is not 16 bytes long");
1346
1347 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1348 if (err >= 0)
1349 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001350 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001351
1352 goto failed;
1353 }
1354
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001355 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1356 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001357 if (!cmd) {
1358 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001359 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001360 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001361
1362 bacpy(&reply.bdaddr, &cp->bdaddr);
1363 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001364 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001365
1366 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1367 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001368 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001369
1370failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001371 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001372 hci_dev_put(hdev);
1373
1374 return err;
1375}
1376
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001377static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001378{
1379 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001380 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001381 int err;
1382
1383 BT_DBG("");
1384
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001385 if (len != sizeof(*cp))
1386 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001387 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001388
Szymon Janc4e51eae2011-02-25 19:05:48 +01001389 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001390 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001391 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001392 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001393
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001394 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001395
1396 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001397 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001398 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001399 goto failed;
1400 }
1401
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001402 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001403
1404failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001405 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001406 hci_dev_put(hdev);
1407
1408 return err;
1409}
1410
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001411static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001412{
1413 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001414 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001415
1416 BT_DBG("");
1417
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001418 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001419 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1420 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001421
Szymon Janc4e51eae2011-02-25 19:05:48 +01001422 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001423 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001424 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1425 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001426
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001427 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001428
1429 hdev->io_capability = cp->io_capability;
1430
1431 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001432 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001433
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001434 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001435 hci_dev_put(hdev);
1436
Szymon Janc4e51eae2011-02-25 19:05:48 +01001437 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001438}
1439
Johan Hedberge9a416b2011-02-19 12:05:56 -03001440static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1441{
1442 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001443 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001444
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001445 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001446 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1447 continue;
1448
Johan Hedberge9a416b2011-02-19 12:05:56 -03001449 if (cmd->user_data != conn)
1450 continue;
1451
1452 return cmd;
1453 }
1454
1455 return NULL;
1456}
1457
1458static void pairing_complete(struct pending_cmd *cmd, u8 status)
1459{
1460 struct mgmt_rp_pair_device rp;
1461 struct hci_conn *conn = cmd->user_data;
1462
Johan Hedbergba4e5642011-11-11 00:07:34 +02001463 bacpy(&rp.addr.bdaddr, &conn->dst);
1464 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001465 rp.status = status;
1466
Szymon Janc4e51eae2011-02-25 19:05:48 +01001467 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001468
1469 /* So we don't get further callbacks for this connection */
1470 conn->connect_cfm_cb = NULL;
1471 conn->security_cfm_cb = NULL;
1472 conn->disconn_cfm_cb = NULL;
1473
1474 hci_conn_put(conn);
1475
Johan Hedberga664b5b2011-02-19 12:06:02 -03001476 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001477}
1478
1479static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1480{
1481 struct pending_cmd *cmd;
1482
1483 BT_DBG("status %u", status);
1484
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001485 cmd = find_pairing(conn);
1486 if (!cmd)
1487 BT_DBG("Unable to find a pending command");
1488 else
1489 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001490}
1491
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001492static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001493{
1494 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001495 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001496 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001497 struct pending_cmd *cmd;
1498 u8 sec_level, auth_type;
1499 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001500 int err;
1501
1502 BT_DBG("");
1503
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001504 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001505 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1506 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001507
Szymon Janc4e51eae2011-02-25 19:05:48 +01001508 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001509 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001510 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1511 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001512
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001513 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001514
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001515 sec_level = BT_SECURITY_MEDIUM;
1516 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001517 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001518 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001519 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001520
Johan Hedbergba4e5642011-11-11 00:07:34 +02001521 if (cp->addr.type == MGMT_ADDR_BREDR)
1522 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001523 auth_type);
1524 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001525 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001526 auth_type);
1527
Johan Hedberg1425acb2011-11-11 00:07:35 +02001528 memset(&rp, 0, sizeof(rp));
1529 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1530 rp.addr.type = cp->addr.type;
1531
Ville Tervo30e76272011-02-22 16:10:53 -03001532 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001533 rp.status = -PTR_ERR(conn);
1534 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1535 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001536 goto unlock;
1537 }
1538
1539 if (conn->connect_cfm_cb) {
1540 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001541 rp.status = EBUSY;
1542 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1543 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001544 goto unlock;
1545 }
1546
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001547 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001548 if (!cmd) {
1549 err = -ENOMEM;
1550 hci_conn_put(conn);
1551 goto unlock;
1552 }
1553
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001554 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001555 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001556 conn->connect_cfm_cb = pairing_complete_cb;
1557
Johan Hedberge9a416b2011-02-19 12:05:56 -03001558 conn->security_cfm_cb = pairing_complete_cb;
1559 conn->disconn_cfm_cb = pairing_complete_cb;
1560 conn->io_capability = cp->io_cap;
1561 cmd->user_data = conn;
1562
1563 if (conn->state == BT_CONNECTED &&
1564 hci_conn_security(conn, sec_level, auth_type))
1565 pairing_complete(cmd, 0);
1566
1567 err = 0;
1568
1569unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001570 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001571 hci_dev_put(hdev);
1572
1573 return err;
1574}
1575
Johan Hedberg28424702012-02-02 04:02:29 +02001576static int cancel_pair_device(struct sock *sk, u16 index,
1577 unsigned char *data, u16 len)
1578{
1579 struct mgmt_addr_info *addr = (void *) data;
1580 struct hci_dev *hdev;
1581 struct pending_cmd *cmd;
1582 struct hci_conn *conn;
1583 int err;
1584
1585 BT_DBG("");
1586
1587 if (len != sizeof(*addr))
1588 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1589 MGMT_STATUS_INVALID_PARAMS);
1590
1591 hdev = hci_dev_get(index);
1592 if (!hdev)
1593 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1594 MGMT_STATUS_INVALID_PARAMS);
1595
1596 hci_dev_lock(hdev);
1597
1598 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1599 if (!cmd) {
1600 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1601 MGMT_STATUS_INVALID_PARAMS);
1602 goto unlock;
1603 }
1604
1605 conn = cmd->user_data;
1606
1607 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1608 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1609 MGMT_STATUS_INVALID_PARAMS);
1610 goto unlock;
1611 }
1612
1613 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1614
1615 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr,
1616 sizeof(*addr));
1617unlock:
1618 hci_dev_unlock(hdev);
1619 hci_dev_put(hdev);
1620
1621 return err;
1622}
1623
Brian Gix0df4c182011-11-16 13:53:13 -08001624static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1625 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001626{
Johan Hedberga5c29682011-02-19 12:05:57 -03001627 struct pending_cmd *cmd;
1628 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001629 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001630 int err;
1631
Szymon Janc4e51eae2011-02-25 19:05:48 +01001632 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001633 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001634 return cmd_status(sk, index, mgmt_op,
1635 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001636
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001637 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001638
Johan Hedberga5c29682011-02-19 12:05:57 -03001639 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001640 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1641 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001642 }
1643
Brian Gix47c15e22011-11-16 13:53:14 -08001644 /*
1645 * Check for an existing ACL link, if present pair via
1646 * HCI commands.
1647 *
1648 * If no ACL link is present, check for an LE link and if
1649 * present, pair via the SMP engine.
1650 *
1651 * If neither ACL nor LE links are present, fail with error.
1652 */
1653 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1654 if (!conn) {
1655 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1656 if (!conn) {
1657 err = cmd_status(sk, index, mgmt_op,
1658 MGMT_STATUS_NOT_CONNECTED);
1659 goto done;
1660 }
1661
1662 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001663 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001664
Brian Gix5fe57d92011-12-21 16:12:13 -08001665 if (!err)
1666 err = cmd_status(sk, index, mgmt_op,
1667 MGMT_STATUS_SUCCESS);
1668 else
1669 err = cmd_status(sk, index, mgmt_op,
1670 MGMT_STATUS_FAILED);
1671
Brian Gix47c15e22011-11-16 13:53:14 -08001672 goto done;
1673 }
1674
Brian Gix0df4c182011-11-16 13:53:13 -08001675 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001676 if (!cmd) {
1677 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001678 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001679 }
1680
Brian Gix0df4c182011-11-16 13:53:13 -08001681 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001682 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1683 struct hci_cp_user_passkey_reply cp;
1684
1685 bacpy(&cp.bdaddr, bdaddr);
1686 cp.passkey = passkey;
1687 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1688 } else
1689 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1690
Johan Hedberga664b5b2011-02-19 12:06:02 -03001691 if (err < 0)
1692 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001693
Brian Gix0df4c182011-11-16 13:53:13 -08001694done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001695 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001696 hci_dev_put(hdev);
1697
1698 return err;
1699}
1700
Brian Gix0df4c182011-11-16 13:53:13 -08001701static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1702{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001703 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001704
1705 BT_DBG("");
1706
1707 if (len != sizeof(*cp))
1708 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1709 MGMT_STATUS_INVALID_PARAMS);
1710
1711 return user_pairing_resp(sk, index, &cp->bdaddr,
1712 MGMT_OP_USER_CONFIRM_REPLY,
1713 HCI_OP_USER_CONFIRM_REPLY, 0);
1714}
1715
1716static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1717 u16 len)
1718{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001719 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001720
1721 BT_DBG("");
1722
1723 if (len != sizeof(*cp))
1724 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1725 MGMT_STATUS_INVALID_PARAMS);
1726
1727 return user_pairing_resp(sk, index, &cp->bdaddr,
1728 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1729 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1730}
1731
Brian Gix604086b2011-11-23 08:28:33 -08001732static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1733{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001734 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001735
1736 BT_DBG("");
1737
1738 if (len != sizeof(*cp))
1739 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1740 EINVAL);
1741
1742 return user_pairing_resp(sk, index, &cp->bdaddr,
1743 MGMT_OP_USER_PASSKEY_REPLY,
1744 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1745}
1746
1747static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1748 u16 len)
1749{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001750 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001751
1752 BT_DBG("");
1753
1754 if (len != sizeof(*cp))
1755 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1756 EINVAL);
1757
1758 return user_pairing_resp(sk, index, &cp->bdaddr,
1759 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1760 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1761}
1762
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001763static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02001764 u16 len)
1765{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001766 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001767 struct hci_cp_write_local_name hci_cp;
1768 struct hci_dev *hdev;
1769 struct pending_cmd *cmd;
1770 int err;
1771
1772 BT_DBG("");
1773
1774 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001775 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1776 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001777
1778 hdev = hci_dev_get(index);
1779 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001780 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1781 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001782
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001783 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001784
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001785 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
1786 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001787 if (!cmd) {
1788 err = -ENOMEM;
1789 goto failed;
1790 }
1791
1792 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1793 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1794 &hci_cp);
1795 if (err < 0)
1796 mgmt_pending_remove(cmd);
1797
1798failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001799 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001800 hci_dev_put(hdev);
1801
1802 return err;
1803}
1804
Szymon Jancc35938b2011-03-22 13:12:21 +01001805static int read_local_oob_data(struct sock *sk, u16 index)
1806{
1807 struct hci_dev *hdev;
1808 struct pending_cmd *cmd;
1809 int err;
1810
1811 BT_DBG("hci%u", index);
1812
1813 hdev = hci_dev_get(index);
1814 if (!hdev)
1815 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001816 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001817
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001818 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001819
1820 if (!test_bit(HCI_UP, &hdev->flags)) {
1821 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001822 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001823 goto unlock;
1824 }
1825
1826 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1827 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001828 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001829 goto unlock;
1830 }
1831
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001832 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001833 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1834 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001835 goto unlock;
1836 }
1837
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001838 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001839 if (!cmd) {
1840 err = -ENOMEM;
1841 goto unlock;
1842 }
1843
1844 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1845 if (err < 0)
1846 mgmt_pending_remove(cmd);
1847
1848unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001849 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001850 hci_dev_put(hdev);
1851
1852 return err;
1853}
1854
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001855static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
1856 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01001857{
1858 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001859 struct mgmt_cp_add_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01001860 int err;
1861
1862 BT_DBG("hci%u ", index);
1863
1864 if (len != sizeof(*cp))
1865 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001866 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001867
1868 hdev = hci_dev_get(index);
1869 if (!hdev)
1870 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001871 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001872
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001873 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001874
1875 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1876 cp->randomizer);
1877 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001878 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1879 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001880 else
1881 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1882 0);
1883
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001884 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001885 hci_dev_put(hdev);
1886
1887 return err;
1888}
1889
1890static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001891 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01001892{
1893 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001894 struct mgmt_cp_remove_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01001895 int err;
1896
1897 BT_DBG("hci%u ", index);
1898
1899 if (len != sizeof(*cp))
1900 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001901 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001902
1903 hdev = hci_dev_get(index);
1904 if (!hdev)
1905 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001906 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001907
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001908 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001909
1910 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1911 if (err < 0)
1912 err = 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 else
1915 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1916 NULL, 0);
1917
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001918 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001919 hci_dev_put(hdev);
1920
1921 return err;
1922}
1923
Johan Hedberg450dfda2011-11-12 11:58:22 +02001924static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001925 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001926{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001927 struct mgmt_cp_start_discovery *cp = data;
Andre Guedes3fd24152012-02-03 17:48:01 -03001928 unsigned long discov_type = cp->type;
Johan Hedberg14a53662011-04-27 10:29:56 -04001929 struct pending_cmd *cmd;
1930 struct hci_dev *hdev;
1931 int err;
1932
1933 BT_DBG("hci%u", index);
1934
Johan Hedberg450dfda2011-11-12 11:58:22 +02001935 if (len != sizeof(*cp))
1936 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1937 MGMT_STATUS_INVALID_PARAMS);
1938
Johan Hedberg14a53662011-04-27 10:29:56 -04001939 hdev = hci_dev_get(index);
1940 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001941 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1942 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001943
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001944 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001945
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001946 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001947 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1948 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001949 goto failed;
1950 }
1951
Johan Hedbergff9ef572012-01-04 14:23:45 +02001952 if (hdev->discovery.state != DISCOVERY_STOPPED) {
1953 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1954 MGMT_STATUS_BUSY);
1955 goto failed;
1956 }
1957
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001958 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001959 if (!cmd) {
1960 err = -ENOMEM;
1961 goto failed;
1962 }
1963
Andre Guedes3fd24152012-02-03 17:48:01 -03001964 if (test_bit(MGMT_ADDR_BREDR, &discov_type))
1965 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
1966 else if (test_bit(MGMT_ADDR_LE_PUBLIC, &discov_type) &&
1967 test_bit(MGMT_ADDR_LE_RANDOM, &discov_type))
1968 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
1969 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
1970 else
1971 err = -EINVAL;
1972
Johan Hedberg14a53662011-04-27 10:29:56 -04001973 if (err < 0)
1974 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02001975 else
1976 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04001977
1978failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001979 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001980 hci_dev_put(hdev);
1981
1982 return err;
1983}
1984
1985static int stop_discovery(struct sock *sk, u16 index)
1986{
1987 struct hci_dev *hdev;
1988 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001989 struct hci_cp_remote_name_req_cancel cp;
1990 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04001991 int err;
1992
1993 BT_DBG("hci%u", index);
1994
1995 hdev = hci_dev_get(index);
1996 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001997 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1998 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001999
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002000 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002001
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002002 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002003 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2004 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002005 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002006 }
2007
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002008 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002009 if (!cmd) {
2010 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002011 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002012 }
2013
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002014 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
2015 err = hci_cancel_inquiry(hdev);
2016 if (err < 0)
2017 mgmt_pending_remove(cmd);
2018 else
2019 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2020 goto unlock;
2021 }
2022
2023 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2024 if (!e) {
2025 mgmt_pending_remove(cmd);
2026 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2027 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2028 goto unlock;
2029 }
2030
2031 bacpy(&cp.bdaddr, &e->data.bdaddr);
2032 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2033 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002034 if (err < 0)
2035 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002036 else
2037 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002038
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002039unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002040 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002041 hci_dev_put(hdev);
2042
2043 return err;
2044}
2045
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002046static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002047{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002048 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002049 struct inquiry_entry *e;
2050 struct hci_dev *hdev;
2051 int err;
2052
2053 BT_DBG("hci%u", index);
2054
2055 if (len != sizeof(*cp))
2056 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2057 MGMT_STATUS_INVALID_PARAMS);
2058
2059 hdev = hci_dev_get(index);
2060 if (!hdev)
2061 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2062 MGMT_STATUS_INVALID_PARAMS);
2063
2064 hci_dev_lock(hdev);
2065
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002066 if (!hci_discovery_active(hdev)) {
2067 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2068 MGMT_STATUS_FAILED);
2069 goto failed;
2070 }
2071
Johan Hedberg561aafb2012-01-04 13:31:59 +02002072 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr);
2073 if (!e) {
2074 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2075 MGMT_STATUS_INVALID_PARAMS);
2076 goto failed;
2077 }
2078
2079 if (cp->name_known) {
2080 e->name_state = NAME_KNOWN;
2081 list_del(&e->list);
2082 } else {
2083 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002084 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002085 }
2086
2087 err = 0;
2088
2089failed:
2090 hci_dev_unlock(hdev);
2091
2092 return err;
2093}
2094
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002095static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002096{
2097 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002098 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002099 int err;
2100
2101 BT_DBG("hci%u", index);
2102
Antti Julku7fbec222011-06-15 12:01:15 +03002103 if (len != sizeof(*cp))
2104 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002105 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002106
2107 hdev = hci_dev_get(index);
2108 if (!hdev)
2109 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002110 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002111
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002112 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002113
Antti Julku7fbec222011-06-15 12:01:15 +03002114 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03002115 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002116 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2117 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002118 else
2119 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2120 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002121
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002122 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002123 hci_dev_put(hdev);
2124
2125 return err;
2126}
2127
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002128static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002129{
2130 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002131 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002132 int err;
2133
2134 BT_DBG("hci%u", index);
2135
Antti Julku7fbec222011-06-15 12:01:15 +03002136 if (len != sizeof(*cp))
2137 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002138 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002139
2140 hdev = hci_dev_get(index);
2141 if (!hdev)
2142 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002143 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002144
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002145 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002146
Antti Julku7fbec222011-06-15 12:01:15 +03002147 err = hci_blacklist_del(hdev, &cp->bdaddr);
2148
2149 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002150 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2151 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002152 else
2153 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2154 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002155
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002156 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002157 hci_dev_put(hdev);
2158
2159 return err;
2160}
2161
Antti Julkuf6422ec2011-06-22 13:11:56 +03002162static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002163 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002164{
2165 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002166 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002167 struct hci_cp_write_page_scan_activity acp;
2168 u8 type;
2169 int err;
2170
2171 BT_DBG("hci%u", index);
2172
2173 if (len != sizeof(*cp))
2174 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002175 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002176
2177 hdev = hci_dev_get(index);
2178 if (!hdev)
2179 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002180 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002181
2182 hci_dev_lock(hdev);
2183
Johan Hedbergf7c68692011-12-15 00:47:36 +02002184 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002185 type = PAGE_SCAN_TYPE_INTERLACED;
2186 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2187 } else {
2188 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2189 acp.interval = 0x0800; /* default 1.28 sec page scan */
2190 }
2191
2192 acp.window = 0x0012; /* default 11.25 msec page scan window */
2193
2194 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2195 sizeof(acp), &acp);
2196 if (err < 0) {
2197 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002198 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002199 goto done;
2200 }
2201
2202 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
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 = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2210 NULL, 0);
2211done:
2212 hci_dev_unlock(hdev);
2213 hci_dev_put(hdev);
2214
2215 return err;
2216}
2217
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002218static int load_long_term_keys(struct sock *sk, u16 index,
2219 void *cp_data, u16 len)
2220{
2221 struct hci_dev *hdev;
2222 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2223 u16 key_count, expected_len;
2224 int i;
2225
2226 if (len < sizeof(*cp))
2227 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2228 EINVAL);
2229
2230 key_count = get_unaligned_le16(&cp->key_count);
2231
2232 expected_len = sizeof(*cp) + key_count *
2233 sizeof(struct mgmt_ltk_info);
2234 if (expected_len != len) {
2235 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2236 len, expected_len);
2237 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2238 EINVAL);
2239 }
2240
2241 hdev = hci_dev_get(index);
2242 if (!hdev)
2243 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2244 ENODEV);
2245
2246 BT_DBG("hci%u key_count %u", index, key_count);
2247
2248 hci_dev_lock(hdev);
2249
2250 hci_smp_ltks_clear(hdev);
2251
2252 for (i = 0; i < key_count; i++) {
2253 struct mgmt_ltk_info *key = &cp->keys[i];
2254 u8 type;
2255
2256 if (key->master)
2257 type = HCI_SMP_LTK;
2258 else
2259 type = HCI_SMP_LTK_SLAVE;
2260
2261 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2262 type, 0, key->authenticated, key->val,
2263 key->enc_size, key->ediv, key->rand);
2264 }
2265
2266 hci_dev_unlock(hdev);
2267 hci_dev_put(hdev);
2268
2269 return 0;
2270}
2271
Johan Hedberg03811012010-12-08 00:21:06 +02002272int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2273{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002274 void *buf;
2275 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002276 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002277 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002278 int err;
2279
2280 BT_DBG("got %zu bytes", msglen);
2281
2282 if (msglen < sizeof(*hdr))
2283 return -EINVAL;
2284
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002285 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002286 if (!buf)
2287 return -ENOMEM;
2288
2289 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2290 err = -EFAULT;
2291 goto done;
2292 }
2293
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002294 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002295 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002296 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002297 len = get_unaligned_le16(&hdr->len);
2298
2299 if (len != msglen - sizeof(*hdr)) {
2300 err = -EINVAL;
2301 goto done;
2302 }
2303
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002304 cp = buf + sizeof(*hdr);
2305
Johan Hedberg03811012010-12-08 00:21:06 +02002306 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002307 case MGMT_OP_READ_VERSION:
2308 err = read_version(sk);
2309 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002310 case MGMT_OP_READ_INDEX_LIST:
2311 err = read_index_list(sk);
2312 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002313 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002314 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002315 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002316 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002317 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002318 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002319 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002320 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002321 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002322 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002323 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002324 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002325 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002326 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002327 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002328 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002329 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002330 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002331 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002332 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002333 break;
2334 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002335 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002336 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002337 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002338 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002339 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002340 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002341 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002342 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002343 case MGMT_OP_REMOVE_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002344 err = remove_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002345 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002346 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002347 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002348 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002349 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002350 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002351 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002352 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002353 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002354 break;
2355 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002356 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002357 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002358 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002359 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002360 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002361 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002362 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002363 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002364 case MGMT_OP_CANCEL_PAIR_DEVICE:
2365 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2366 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002367 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002368 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002369 break;
2370 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002371 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002372 break;
Brian Gix604086b2011-11-23 08:28:33 -08002373 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002374 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002375 break;
2376 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002377 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002378 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002379 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002380 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002381 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002382 case MGMT_OP_READ_LOCAL_OOB_DATA:
2383 err = read_local_oob_data(sk, index);
2384 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002385 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002386 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002387 break;
2388 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002389 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002390 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002391 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002392 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002393 break;
2394 case MGMT_OP_STOP_DISCOVERY:
2395 err = stop_discovery(sk, index);
2396 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002397 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002398 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002399 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002400 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002401 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002402 break;
2403 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002404 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002405 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002406 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2407 err = load_long_term_keys(sk, index, cp, len);
2408 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002409 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002410 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002411 err = cmd_status(sk, index, opcode,
2412 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002413 break;
2414 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002415
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002416 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002417 goto done;
2418
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002419 err = msglen;
2420
2421done:
2422 kfree(buf);
2423 return err;
2424}
2425
Johan Hedbergb24752f2011-11-03 14:40:33 +02002426static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2427{
2428 u8 *status = data;
2429
2430 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2431 mgmt_pending_remove(cmd);
2432}
2433
Johan Hedberg744cf192011-11-08 20:40:14 +02002434int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002435{
Johan Hedberg744cf192011-11-08 20:40:14 +02002436 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002437}
2438
Johan Hedberg744cf192011-11-08 20:40:14 +02002439int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002440{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002441 u8 status = ENODEV;
2442
Johan Hedberg744cf192011-11-08 20:40:14 +02002443 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002444
Johan Hedberg744cf192011-11-08 20:40:14 +02002445 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002446}
2447
2448struct cmd_lookup {
2449 u8 val;
2450 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002451 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002452};
2453
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002454static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002455{
Johan Hedberg03811012010-12-08 00:21:06 +02002456 struct cmd_lookup *match = data;
2457
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002458 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002459
2460 list_del(&cmd->list);
2461
2462 if (match->sk == NULL) {
2463 match->sk = cmd->sk;
2464 sock_hold(match->sk);
2465 }
2466
2467 mgmt_pending_free(cmd);
2468}
2469
Johan Hedberg744cf192011-11-08 20:40:14 +02002470int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002471{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002472 struct cmd_lookup match = { powered, NULL, hdev };
2473 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002474 int ret;
2475
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002476 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002477
Johan Hedbergb24752f2011-11-03 14:40:33 +02002478 if (!powered) {
2479 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002480 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002481 }
2482
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002483 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002484
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002485 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2486 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002487
2488 if (match.sk)
2489 sock_put(match.sk);
2490
2491 return ret;
2492}
2493
Johan Hedberg744cf192011-11-08 20:40:14 +02002494int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002495{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002496 struct cmd_lookup match = { discoverable, NULL, hdev };
2497 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002498 int ret;
2499
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002500 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002501
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002502 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002503
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002504 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002505 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002506 if (match.sk)
2507 sock_put(match.sk);
2508
2509 return ret;
2510}
2511
Johan Hedberg744cf192011-11-08 20:40:14 +02002512int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002513{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002514 __le32 ev;
2515 struct cmd_lookup match = { connectable, NULL, hdev };
Johan Hedberg03811012010-12-08 00:21:06 +02002516 int ret;
2517
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002518 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2519 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002520
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002521 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002522
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002523 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002524
2525 if (match.sk)
2526 sock_put(match.sk);
2527
2528 return ret;
2529}
2530
Johan Hedberg744cf192011-11-08 20:40:14 +02002531int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002532{
Johan Hedbergca69b792011-11-11 18:10:00 +02002533 u8 mgmt_err = mgmt_status(status);
2534
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002535 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002536 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002537 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002538
2539 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002540 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002541 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002542
2543 return 0;
2544}
2545
Johan Hedberg744cf192011-11-08 20:40:14 +02002546int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2547 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002548{
Johan Hedberg86742e12011-11-07 23:13:38 +02002549 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002550
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002551 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002552
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002553 ev.store_hint = persistent;
2554 bacpy(&ev.key.bdaddr, &key->bdaddr);
2555 ev.key.type = key->type;
2556 memcpy(ev.key.val, key->val, 16);
2557 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002558
Johan Hedberg744cf192011-11-08 20:40:14 +02002559 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002560}
Johan Hedbergf7520542011-01-20 12:34:39 +02002561
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002562int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2563{
2564 struct mgmt_ev_new_long_term_key ev;
2565
2566 memset(&ev, 0, sizeof(ev));
2567
2568 ev.store_hint = persistent;
2569 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2570 ev.key.addr.type = key->bdaddr_type;
2571 ev.key.authenticated = key->authenticated;
2572 ev.key.enc_size = key->enc_size;
2573 ev.key.ediv = key->ediv;
2574
2575 if (key->type == HCI_SMP_LTK)
2576 ev.key.master = 1;
2577
2578 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2579 memcpy(ev.key.val, key->val, sizeof(key->val));
2580
2581 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2582 &ev, sizeof(ev), NULL);
2583}
2584
Johan Hedbergafc747a2012-01-15 18:11:07 +02002585int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002586 u8 addr_type, u8 *name, u8 name_len,
2587 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002588{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002589 char buf[512];
2590 struct mgmt_ev_device_connected *ev = (void *) buf;
2591 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002592
Johan Hedbergb644ba32012-01-17 21:48:47 +02002593 bacpy(&ev->addr.bdaddr, bdaddr);
2594 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002595
Johan Hedbergb644ba32012-01-17 21:48:47 +02002596 if (name_len > 0)
2597 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2598 name, name_len);
2599
2600 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2601 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2602 EIR_CLASS_OF_DEV, dev_class, 3);
2603
2604 put_unaligned_le16(eir_len, &ev->eir_len);
2605
2606 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2607 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002608}
2609
Johan Hedberg8962ee72011-01-20 12:40:27 +02002610static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2611{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002612 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002613 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002614 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002615
Johan Hedberga38528f2011-01-22 06:46:43 +02002616 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002617 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002618
Szymon Janc4e51eae2011-02-25 19:05:48 +01002619 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002620
2621 *sk = cmd->sk;
2622 sock_hold(*sk);
2623
Johan Hedberga664b5b2011-02-19 12:06:02 -03002624 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002625}
2626
Johan Hedberga8a1d192011-11-10 15:54:38 +02002627static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2628{
2629 u8 *status = data;
2630 struct mgmt_cp_remove_keys *cp = cmd->param;
2631 struct mgmt_rp_remove_keys rp;
2632
2633 memset(&rp, 0, sizeof(rp));
2634 bacpy(&rp.bdaddr, &cp->bdaddr);
2635 if (status != NULL)
2636 rp.status = *status;
2637
2638 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2639 sizeof(rp));
2640
2641 mgmt_pending_remove(cmd);
2642}
2643
Johan Hedbergafc747a2012-01-15 18:11:07 +02002644int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2645 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002646{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002647 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002648 struct sock *sk = NULL;
2649 int err;
2650
Johan Hedberg744cf192011-11-08 20:40:14 +02002651 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002652
Johan Hedbergf7520542011-01-20 12:34:39 +02002653 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002654 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002655
Johan Hedbergafc747a2012-01-15 18:11:07 +02002656 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2657 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002658
2659 if (sk)
2660 sock_put(sk);
2661
Johan Hedberga8a1d192011-11-10 15:54:38 +02002662 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2663
Johan Hedberg8962ee72011-01-20 12:40:27 +02002664 return err;
2665}
2666
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002667int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002668{
2669 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002670 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002671 int err;
2672
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002673 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002674 if (!cmd)
2675 return -ENOENT;
2676
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002677 if (bdaddr) {
2678 struct mgmt_rp_disconnect rp;
2679
2680 bacpy(&rp.bdaddr, bdaddr);
2681 rp.status = status;
2682
2683 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2684 &rp, sizeof(rp));
2685 } else
2686 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002687 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002688
Johan Hedberga664b5b2011-02-19 12:06:02 -03002689 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002690
2691 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002692}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002693
Johan Hedberg48264f02011-11-09 13:58:58 +02002694int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2695 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002696{
2697 struct mgmt_ev_connect_failed ev;
2698
Johan Hedberg4c659c32011-11-07 23:13:39 +02002699 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002700 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002701 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002702
Johan Hedberg744cf192011-11-08 20:40:14 +02002703 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002704}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002705
Johan Hedberg744cf192011-11-08 20:40:14 +02002706int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002707{
2708 struct mgmt_ev_pin_code_request ev;
2709
Johan Hedberg980e1a52011-01-22 06:10:07 +02002710 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002711 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002712
Johan Hedberg744cf192011-11-08 20:40:14 +02002713 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002714 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002715}
2716
Johan Hedberg744cf192011-11-08 20:40:14 +02002717int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2718 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002719{
2720 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002721 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002722 int err;
2723
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002724 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002725 if (!cmd)
2726 return -ENOENT;
2727
Johan Hedbergac56fb12011-02-19 12:05:59 -03002728 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002729 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002730
Johan Hedberg744cf192011-11-08 20:40:14 +02002731 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002732 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002733
Johan Hedberga664b5b2011-02-19 12:06:02 -03002734 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002735
2736 return err;
2737}
2738
Johan Hedberg744cf192011-11-08 20:40:14 +02002739int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2740 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002741{
2742 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002743 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002744 int err;
2745
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002746 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002747 if (!cmd)
2748 return -ENOENT;
2749
Johan Hedbergac56fb12011-02-19 12:05:59 -03002750 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002751 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002752
Johan Hedberg744cf192011-11-08 20:40:14 +02002753 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002754 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002755
Johan Hedberga664b5b2011-02-19 12:06:02 -03002756 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002757
2758 return err;
2759}
Johan Hedberga5c29682011-02-19 12:05:57 -03002760
Johan Hedberg744cf192011-11-08 20:40:14 +02002761int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2762 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002763{
2764 struct mgmt_ev_user_confirm_request ev;
2765
Johan Hedberg744cf192011-11-08 20:40:14 +02002766 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002767
Johan Hedberga5c29682011-02-19 12:05:57 -03002768 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002769 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002770 put_unaligned_le32(value, &ev.value);
2771
Johan Hedberg744cf192011-11-08 20:40:14 +02002772 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002773 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002774}
2775
Brian Gix604086b2011-11-23 08:28:33 -08002776int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2777{
2778 struct mgmt_ev_user_passkey_request ev;
2779
2780 BT_DBG("%s", hdev->name);
2781
2782 bacpy(&ev.bdaddr, bdaddr);
2783
2784 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2785 NULL);
2786}
2787
Brian Gix0df4c182011-11-16 13:53:13 -08002788static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002789 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002790{
2791 struct pending_cmd *cmd;
2792 struct mgmt_rp_user_confirm_reply rp;
2793 int err;
2794
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002795 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002796 if (!cmd)
2797 return -ENOENT;
2798
Johan Hedberga5c29682011-02-19 12:05:57 -03002799 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002800 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002801 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002802
Johan Hedberga664b5b2011-02-19 12:06:02 -03002803 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002804
2805 return err;
2806}
2807
Johan Hedberg744cf192011-11-08 20:40:14 +02002808int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2809 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002810{
Brian Gix0df4c182011-11-16 13:53:13 -08002811 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002812 MGMT_OP_USER_CONFIRM_REPLY);
2813}
2814
Johan Hedberg744cf192011-11-08 20:40:14 +02002815int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2816 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002817{
Brian Gix0df4c182011-11-16 13:53:13 -08002818 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002819 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2820}
Johan Hedberg2a611692011-02-19 12:06:00 -03002821
Brian Gix604086b2011-11-23 08:28:33 -08002822int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2823 u8 status)
2824{
2825 return user_pairing_resp_complete(hdev, bdaddr, status,
2826 MGMT_OP_USER_PASSKEY_REPLY);
2827}
2828
2829int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2830 bdaddr_t *bdaddr, u8 status)
2831{
2832 return user_pairing_resp_complete(hdev, bdaddr, status,
2833 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2834}
2835
Johan Hedberg744cf192011-11-08 20:40:14 +02002836int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002837{
2838 struct mgmt_ev_auth_failed ev;
2839
Johan Hedberg2a611692011-02-19 12:06:00 -03002840 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002841 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002842
Johan Hedberg744cf192011-11-08 20:40:14 +02002843 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002844}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002845
Johan Hedberg744cf192011-11-08 20:40:14 +02002846int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002847{
2848 struct pending_cmd *cmd;
2849 struct mgmt_cp_set_local_name ev;
2850 int err;
2851
2852 memset(&ev, 0, sizeof(ev));
2853 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2854
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002855 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002856 if (!cmd)
2857 goto send_event;
2858
2859 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002860 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002861 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002862 goto failed;
2863 }
2864
Johan Hedberg744cf192011-11-08 20:40:14 +02002865 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002866
Johan Hedberg744cf192011-11-08 20:40:14 +02002867 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002868 sizeof(ev));
2869 if (err < 0)
2870 goto failed;
2871
2872send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002873 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002874 cmd ? cmd->sk : NULL);
2875
2876failed:
2877 if (cmd)
2878 mgmt_pending_remove(cmd);
2879 return err;
2880}
Szymon Jancc35938b2011-03-22 13:12:21 +01002881
Johan Hedberg744cf192011-11-08 20:40:14 +02002882int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2883 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002884{
2885 struct pending_cmd *cmd;
2886 int err;
2887
Johan Hedberg744cf192011-11-08 20:40:14 +02002888 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002889
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002890 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002891 if (!cmd)
2892 return -ENOENT;
2893
2894 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002895 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002896 MGMT_OP_READ_LOCAL_OOB_DATA,
2897 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002898 } else {
2899 struct mgmt_rp_read_local_oob_data rp;
2900
2901 memcpy(rp.hash, hash, sizeof(rp.hash));
2902 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2903
Johan Hedberg744cf192011-11-08 20:40:14 +02002904 err = cmd_complete(cmd->sk, hdev->id,
2905 MGMT_OP_READ_LOCAL_OOB_DATA,
2906 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002907 }
2908
2909 mgmt_pending_remove(cmd);
2910
2911 return err;
2912}
Johan Hedberge17acd42011-03-30 23:57:16 +03002913
Johan Hedberg48264f02011-11-09 13:58:58 +02002914int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002915 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02002916 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03002917{
Johan Hedberge319d2e2012-01-15 19:51:59 +02002918 char buf[512];
2919 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02002920 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03002921
Johan Hedberg1dc06092012-01-15 21:01:23 +02002922 /* Leave 5 bytes for a potential CoD field */
2923 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03002924 return -EINVAL;
2925
Johan Hedberg1dc06092012-01-15 21:01:23 +02002926 memset(buf, 0, sizeof(buf));
2927
Johan Hedberge319d2e2012-01-15 19:51:59 +02002928 bacpy(&ev->addr.bdaddr, bdaddr);
2929 ev->addr.type = link_to_mgmt(link_type, addr_type);
2930 ev->rssi = rssi;
2931 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03002932
Johan Hedberg1dc06092012-01-15 21:01:23 +02002933 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02002934 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03002935
Johan Hedberg1dc06092012-01-15 21:01:23 +02002936 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
2937 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
2938 dev_class, 3);
2939
2940 put_unaligned_le16(eir_len, &ev->eir_len);
2941
2942 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03002943
Johan Hedberge319d2e2012-01-15 19:51:59 +02002944 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002945}
Johan Hedberga88a9652011-03-30 13:18:12 +03002946
Johan Hedbergb644ba32012-01-17 21:48:47 +02002947int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2948 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03002949{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002950 struct mgmt_ev_device_found *ev;
2951 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
2952 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03002953
Johan Hedbergb644ba32012-01-17 21:48:47 +02002954 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03002955
Johan Hedbergb644ba32012-01-17 21:48:47 +02002956 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03002957
Johan Hedbergb644ba32012-01-17 21:48:47 +02002958 bacpy(&ev->addr.bdaddr, bdaddr);
2959 ev->addr.type = link_to_mgmt(link_type, addr_type);
2960 ev->rssi = rssi;
2961
2962 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
2963 name_len);
2964
2965 put_unaligned_le16(eir_len, &ev->eir_len);
2966
2967 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002968}
Johan Hedberg314b2382011-04-27 10:29:57 -04002969
Andre Guedes7a135102011-11-09 17:14:25 -03002970int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002971{
2972 struct pending_cmd *cmd;
2973 int err;
2974
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002975 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002976 if (!cmd)
2977 return -ENOENT;
2978
Johan Hedbergca69b792011-11-11 18:10:00 +02002979 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002980 mgmt_pending_remove(cmd);
2981
2982 return err;
2983}
2984
Andre Guedese6d465c2011-11-09 17:14:26 -03002985int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2986{
2987 struct pending_cmd *cmd;
2988 int err;
2989
2990 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2991 if (!cmd)
2992 return -ENOENT;
2993
Andre Guedese75a8b0c2012-01-02 16:50:53 -03002994 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02002995 mgmt_pending_remove(cmd);
2996
2997 return err;
2998}
Johan Hedberg314b2382011-04-27 10:29:57 -04002999
Johan Hedberg744cf192011-11-08 20:40:14 +02003000int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003001{
Johan Hedberg164a6e72011-11-01 17:06:44 +02003002 struct pending_cmd *cmd;
3003
3004 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003005 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003006 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003007 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003008
3009 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003010 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003011 mgmt_pending_remove(cmd);
3012 }
3013
Johan Hedberg744cf192011-11-08 20:40:14 +02003014 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04003015 sizeof(discovering), NULL);
3016}
Antti Julku5e762442011-08-25 16:48:02 +03003017
Johan Hedberg744cf192011-11-08 20:40:14 +02003018int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03003019{
3020 struct pending_cmd *cmd;
3021 struct mgmt_ev_device_blocked ev;
3022
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003023 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003024
3025 bacpy(&ev.bdaddr, bdaddr);
3026
Johan Hedberg744cf192011-11-08 20:40:14 +02003027 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3028 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003029}
3030
Johan Hedberg744cf192011-11-08 20:40:14 +02003031int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03003032{
3033 struct pending_cmd *cmd;
3034 struct mgmt_ev_device_unblocked ev;
3035
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003036 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003037
3038 bacpy(&ev.bdaddr, bdaddr);
3039
Johan Hedberg744cf192011-11-08 20:40:14 +02003040 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3041 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003042}