blob: 9e5dead1dbef1940425bec7d69837be855dd8df5 [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 Guedes2519a1f2011-11-07 11:45:24 -030038#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
39
Johan Hedberg7d785252011-12-15 00:47:39 +020040#define SERVICE_CACHE_TIMEOUT (5 * 1000)
41
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042struct pending_cmd {
43 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020044 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010046 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020047 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030048 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020049};
50
Johan Hedbergca69b792011-11-11 18:10:00 +020051/* HCI to MGMT error code conversion table */
52static u8 mgmt_status_table[] = {
53 MGMT_STATUS_SUCCESS,
54 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
55 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
56 MGMT_STATUS_FAILED, /* Hardware Failure */
57 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
58 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
59 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
60 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
61 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
62 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
63 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
64 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
65 MGMT_STATUS_BUSY, /* Command Disallowed */
66 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
67 MGMT_STATUS_REJECTED, /* Rejected Security */
68 MGMT_STATUS_REJECTED, /* Rejected Personal */
69 MGMT_STATUS_TIMEOUT, /* Host Timeout */
70 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
71 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
72 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
73 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
74 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
75 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
76 MGMT_STATUS_BUSY, /* Repeated Attempts */
77 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
78 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
79 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
80 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
81 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
82 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
83 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
84 MGMT_STATUS_FAILED, /* Unspecified Error */
85 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
86 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
87 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
88 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
89 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
90 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
91 MGMT_STATUS_FAILED, /* Unit Link Key Used */
92 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
93 MGMT_STATUS_TIMEOUT, /* Instant Passed */
94 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
95 MGMT_STATUS_FAILED, /* Transaction Collision */
96 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
97 MGMT_STATUS_REJECTED, /* QoS Rejected */
98 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
99 MGMT_STATUS_REJECTED, /* Insufficient Security */
100 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
101 MGMT_STATUS_BUSY, /* Role Switch Pending */
102 MGMT_STATUS_FAILED, /* Slot Violation */
103 MGMT_STATUS_FAILED, /* Role Switch Failed */
104 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
105 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
106 MGMT_STATUS_BUSY, /* Host Busy Pairing */
107 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
108 MGMT_STATUS_BUSY, /* Controller Busy */
109 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
110 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
111 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
112 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
113 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
114};
115
116static u8 mgmt_status(u8 hci_status)
117{
118 if (hci_status < ARRAY_SIZE(mgmt_status_table))
119 return mgmt_status_table[hci_status];
120
121 return MGMT_STATUS_FAILED;
122}
123
Szymon Janc4e51eae2011-02-25 19:05:48 +0100124static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200125{
126 struct sk_buff *skb;
127 struct mgmt_hdr *hdr;
128 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300129 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200130
Szymon Janc34eb5252011-02-28 14:10:08 +0100131 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200132
133 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
134 if (!skb)
135 return -ENOMEM;
136
137 hdr = (void *) skb_put(skb, sizeof(*hdr));
138
139 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100140 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200141 hdr->len = cpu_to_le16(sizeof(*ev));
142
143 ev = (void *) skb_put(skb, sizeof(*ev));
144 ev->status = status;
145 put_unaligned_le16(cmd, &ev->opcode);
146
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300147 err = sock_queue_rcv_skb(sk, skb);
148 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200149 kfree_skb(skb);
150
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300151 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200152}
153
Szymon Janc4e51eae2011-02-25 19:05:48 +0100154static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
155 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200156{
157 struct sk_buff *skb;
158 struct mgmt_hdr *hdr;
159 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300160 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200161
162 BT_DBG("sock %p", sk);
163
Johan Hedberga38528f2011-01-22 06:46:43 +0200164 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200165 if (!skb)
166 return -ENOMEM;
167
168 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200169
Johan Hedberg02d98122010-12-13 21:07:04 +0200170 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100171 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200172 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200173
Johan Hedberga38528f2011-01-22 06:46:43 +0200174 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
175 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100176
177 if (rp)
178 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200179
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300180 err = sock_queue_rcv_skb(sk, skb);
181 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200182 kfree_skb(skb);
183
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300184 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200185}
186
Johan Hedberga38528f2011-01-22 06:46:43 +0200187static int read_version(struct sock *sk)
188{
189 struct mgmt_rp_read_version rp;
190
191 BT_DBG("sock %p", sk);
192
193 rp.version = MGMT_VERSION;
194 put_unaligned_le16(MGMT_REVISION, &rp.revision);
195
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
197 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200198}
199
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200200static int read_index_list(struct sock *sk)
201{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200202 struct mgmt_rp_read_index_list *rp;
203 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200204 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200205 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200206 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200207 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200208
209 BT_DBG("sock %p", sk);
210
211 read_lock(&hci_dev_list_lock);
212
213 count = 0;
214 list_for_each(p, &hci_dev_list) {
215 count++;
216 }
217
Johan Hedberga38528f2011-01-22 06:46:43 +0200218 rp_len = sizeof(*rp) + (2 * count);
219 rp = kmalloc(rp_len, GFP_ATOMIC);
220 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100221 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200222 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100223 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200224
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200225 put_unaligned_le16(count, &rp->num_controllers);
226
227 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200228 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200229 if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200230 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200231
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200232 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200233 continue;
234
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200235 put_unaligned_le16(d->id, &rp->index[i++]);
236 BT_DBG("Added hci%u", d->id);
237 }
238
239 read_unlock(&hci_dev_list_lock);
240
Szymon Janc4e51eae2011-02-25 19:05:48 +0100241 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
242 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200243
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 kfree(rp);
245
246 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200247}
248
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200249static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200250{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200251 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200252
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200253 settings |= MGMT_SETTING_POWERED;
254 settings |= MGMT_SETTING_CONNECTABLE;
255 settings |= MGMT_SETTING_FAST_CONNECTABLE;
256 settings |= MGMT_SETTING_DISCOVERABLE;
257 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200258
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200259 if (hdev->features[6] & LMP_SIMPLE_PAIR)
260 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200261
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200262 if (!(hdev->features[4] & LMP_NO_BREDR)) {
263 settings |= MGMT_SETTING_BREDR;
264 settings |= MGMT_SETTING_LINK_SECURITY;
265 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200266
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200267 if (hdev->features[4] & LMP_LE)
268 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200269
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200270 return settings;
271}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200272
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200273static u32 get_current_settings(struct hci_dev *hdev)
274{
275 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200276
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200277 if (test_bit(HCI_UP, &hdev->flags))
278 settings |= MGMT_SETTING_POWERED;
279 else
280 return settings;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200281
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200282 if (test_bit(HCI_PSCAN, &hdev->flags))
283 settings |= MGMT_SETTING_CONNECTABLE;
284
285 if (test_bit(HCI_ISCAN, &hdev->flags))
286 settings |= MGMT_SETTING_DISCOVERABLE;
287
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200288 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200289 settings |= MGMT_SETTING_PAIRABLE;
290
291 if (!(hdev->features[4] & LMP_NO_BREDR))
292 settings |= MGMT_SETTING_BREDR;
293
Andre Guedes59e29402011-12-30 10:34:03 -0300294 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200295 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200296
297 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200298 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200299
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200300 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200301 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200302
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200303 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200304}
305
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300306#define PNP_INFO_SVCLASS_ID 0x1200
307
308static u8 bluetooth_base_uuid[] = {
309 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
310 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311};
312
313static u16 get_uuid16(u8 *uuid128)
314{
315 u32 val;
316 int i;
317
318 for (i = 0; i < 12; i++) {
319 if (bluetooth_base_uuid[i] != uuid128[i])
320 return 0;
321 }
322
323 memcpy(&val, &uuid128[12], 4);
324
325 val = le32_to_cpu(val);
326 if (val > 0xffff)
327 return 0;
328
329 return (u16) val;
330}
331
332static void create_eir(struct hci_dev *hdev, u8 *data)
333{
334 u8 *ptr = data;
335 u16 eir_len = 0;
336 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
337 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200338 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300339 size_t name_len;
340
341 name_len = strlen(hdev->dev_name);
342
343 if (name_len > 0) {
344 /* EIR Data type */
345 if (name_len > 48) {
346 name_len = 48;
347 ptr[1] = EIR_NAME_SHORT;
348 } else
349 ptr[1] = EIR_NAME_COMPLETE;
350
351 /* EIR Data length */
352 ptr[0] = name_len + 1;
353
354 memcpy(ptr + 2, hdev->dev_name, name_len);
355
356 eir_len += (name_len + 2);
357 ptr += (name_len + 2);
358 }
359
360 memset(uuid16_list, 0, sizeof(uuid16_list));
361
362 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200363 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300364 u16 uuid16;
365
366 uuid16 = get_uuid16(uuid->uuid);
367 if (uuid16 == 0)
368 return;
369
370 if (uuid16 < 0x1100)
371 continue;
372
373 if (uuid16 == PNP_INFO_SVCLASS_ID)
374 continue;
375
376 /* Stop if not enough space to put next UUID */
377 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
378 truncated = 1;
379 break;
380 }
381
382 /* Check for duplicates */
383 for (i = 0; uuid16_list[i] != 0; i++)
384 if (uuid16_list[i] == uuid16)
385 break;
386
387 if (uuid16_list[i] == 0) {
388 uuid16_list[i] = uuid16;
389 eir_len += sizeof(u16);
390 }
391 }
392
393 if (uuid16_list[0] != 0) {
394 u8 *length = ptr;
395
396 /* EIR Data type */
397 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
398
399 ptr += 2;
400 eir_len += 2;
401
402 for (i = 0; uuid16_list[i] != 0; i++) {
403 *ptr++ = (uuid16_list[i] & 0x00ff);
404 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
405 }
406
407 /* EIR Data length */
408 *length = (i * sizeof(u16)) + 1;
409 }
410}
411
412static int update_eir(struct hci_dev *hdev)
413{
414 struct hci_cp_write_eir cp;
415
416 if (!(hdev->features[6] & LMP_EXT_INQ))
417 return 0;
418
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200419 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300420 return 0;
421
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200422 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300423 return 0;
424
425 memset(&cp, 0, sizeof(cp));
426
427 create_eir(hdev, cp.data);
428
429 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
430 return 0;
431
432 memcpy(hdev->eir, cp.data, sizeof(cp.data));
433
434 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
435}
436
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200437static u8 get_service_classes(struct hci_dev *hdev)
438{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300439 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200440 u8 val = 0;
441
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300442 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200443 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200444
445 return val;
446}
447
448static int update_class(struct hci_dev *hdev)
449{
450 u8 cod[3];
451
452 BT_DBG("%s", hdev->name);
453
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200454 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200455 return 0;
456
457 cod[0] = hdev->minor_class;
458 cod[1] = hdev->major_class;
459 cod[2] = get_service_classes(hdev);
460
461 if (memcmp(cod, hdev->dev_class, 3) == 0)
462 return 0;
463
464 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
465}
466
Johan Hedberg7d785252011-12-15 00:47:39 +0200467static void service_cache_off(struct work_struct *work)
468{
469 struct hci_dev *hdev = container_of(work, struct hci_dev,
470 service_cache.work);
471
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200472 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200473 return;
474
475 hci_dev_lock(hdev);
476
477 update_eir(hdev);
478 update_class(hdev);
479
480 hci_dev_unlock(hdev);
481}
482
483static void mgmt_init_hdev(struct hci_dev *hdev)
484{
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200485 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200486 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
487
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200488 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200489 schedule_delayed_work(&hdev->service_cache,
490 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
491}
492
Johan Hedberg03811012010-12-08 00:21:06 +0200493static int read_controller_info(struct sock *sk, u16 index)
494{
495 struct mgmt_rp_read_info rp;
496 struct hci_dev *hdev;
497
498 BT_DBG("sock %p hci%u", sk, index);
499
500 hdev = hci_dev_get(index);
501 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200502 return cmd_status(sk, index, MGMT_OP_READ_INFO,
503 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200504
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200505 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
Johan Hedberg03811012010-12-08 00:21:06 +0200506 cancel_delayed_work_sync(&hdev->power_off);
507
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300508 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200509
Johan Hedberg7d785252011-12-15 00:47:39 +0200510 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
511 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200512
513 memset(&rp, 0, sizeof(rp));
514
Johan Hedberg03811012010-12-08 00:21:06 +0200515 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200516
517 rp.version = hdev->hci_ver;
518
Johan Hedberg03811012010-12-08 00:21:06 +0200519 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200520
521 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
522 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
523
524 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200525
526 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
527
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300528 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200529 hci_dev_put(hdev);
530
531 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
532}
533
534static void mgmt_pending_free(struct pending_cmd *cmd)
535{
536 sock_put(cmd->sk);
537 kfree(cmd->param);
538 kfree(cmd);
539}
540
541static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
542 struct hci_dev *hdev,
543 void *data, u16 len)
544{
545 struct pending_cmd *cmd;
546
547 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
548 if (!cmd)
549 return NULL;
550
551 cmd->opcode = opcode;
552 cmd->index = hdev->id;
553
554 cmd->param = kmalloc(len, GFP_ATOMIC);
555 if (!cmd->param) {
556 kfree(cmd);
557 return NULL;
558 }
559
560 if (data)
561 memcpy(cmd->param, data, len);
562
563 cmd->sk = sk;
564 sock_hold(sk);
565
566 list_add(&cmd->list, &hdev->mgmt_pending);
567
568 return cmd;
569}
570
571static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
572 void (*cb)(struct pending_cmd *cmd, void *data),
573 void *data)
574{
575 struct list_head *p, *n;
576
577 list_for_each_safe(p, n, &hdev->mgmt_pending) {
578 struct pending_cmd *cmd;
579
580 cmd = list_entry(p, struct pending_cmd, list);
581
582 if (opcode > 0 && cmd->opcode != opcode)
583 continue;
584
585 cb(cmd, data);
586 }
587}
588
589static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
590{
591 struct pending_cmd *cmd;
592
593 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
594 if (cmd->opcode == opcode)
595 return cmd;
596 }
597
598 return NULL;
599}
600
601static void mgmt_pending_remove(struct pending_cmd *cmd)
602{
603 list_del(&cmd->list);
604 mgmt_pending_free(cmd);
605}
606
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200607static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200608{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200609 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200610
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200611 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200612}
613
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300614static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200615{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300616 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200617 struct hci_dev *hdev;
618 struct pending_cmd *cmd;
619 int err, up;
620
Johan Hedberg03811012010-12-08 00:21:06 +0200621 BT_DBG("request for hci%u", index);
622
623 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200624 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
625 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200626
627 hdev = hci_dev_get(index);
628 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200629 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
630 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200631
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300632 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
634 up = test_bit(HCI_UP, &hdev->flags);
635 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200636 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200637 goto failed;
638 }
639
640 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200641 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
642 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200643 goto failed;
644 }
645
646 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
647 if (!cmd) {
648 err = -ENOMEM;
649 goto failed;
650 }
651
652 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200653 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200654 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200655 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200656
657 err = 0;
658
659failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300660 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200661 hci_dev_put(hdev);
662 return err;
663}
664
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300665static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200666{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300667 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200668 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200669 struct pending_cmd *cmd;
670 u8 scan;
671 int err;
672
Johan Hedberg03811012010-12-08 00:21:06 +0200673 BT_DBG("request for hci%u", index);
674
675 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200676 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
677 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200678
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200679 hdev = hci_dev_get(index);
680 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200681 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
682 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200683
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300684 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200685
686 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200687 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
688 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200689 goto failed;
690 }
691
692 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
693 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200694 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
695 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200696 goto failed;
697 }
698
699 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
700 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200701 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200702 goto failed;
703 }
704
705 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
706 if (!cmd) {
707 err = -ENOMEM;
708 goto failed;
709 }
710
711 scan = SCAN_PAGE;
712
713 if (cp->val)
714 scan |= SCAN_INQUIRY;
715 else
716 cancel_delayed_work(&hdev->discov_off);
717
718 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
719 if (err < 0)
720 mgmt_pending_remove(cmd);
721
Johan Hedberg03811012010-12-08 00:21:06 +0200722 if (cp->val)
723 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
724
Johan Hedberge41d8b42010-12-13 21:07:03 +0200725failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300726 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200727 hci_dev_put(hdev);
728
729 return err;
730}
731
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300732static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200733{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300734 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200735 struct hci_dev *hdev;
736 struct pending_cmd *cmd;
737 u8 scan;
738 int err;
739
Johan Hedberge41d8b42010-12-13 21:07:03 +0200740 BT_DBG("request for hci%u", index);
741
Johan Hedberg03811012010-12-08 00:21:06 +0200742 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200743 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
744 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200745
746 hdev = hci_dev_get(index);
747 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200748 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
749 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200750
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300751 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200752
753 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200754 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
755 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200756 goto failed;
757 }
758
759 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
760 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200761 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
762 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200763 goto failed;
764 }
765
766 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200767 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200768 goto failed;
769 }
770
771 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
772 if (!cmd) {
773 err = -ENOMEM;
774 goto failed;
775 }
776
777 if (cp->val)
778 scan = SCAN_PAGE;
779 else
780 scan = 0;
781
782 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
783 if (err < 0)
784 mgmt_pending_remove(cmd);
785
786failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300787 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200788 hci_dev_put(hdev);
789
790 return err;
791}
792
793static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
794 u16 data_len, struct sock *skip_sk)
795{
796 struct sk_buff *skb;
797 struct mgmt_hdr *hdr;
798
799 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
800 if (!skb)
801 return -ENOMEM;
802
803 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
804
805 hdr = (void *) skb_put(skb, sizeof(*hdr));
806 hdr->opcode = cpu_to_le16(event);
807 if (hdev)
808 hdr->index = cpu_to_le16(hdev->id);
809 else
810 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
811 hdr->len = cpu_to_le16(data_len);
812
813 if (data)
814 memcpy(skb_put(skb, data_len), data, data_len);
815
816 hci_send_to_sock(NULL, skb, skip_sk);
817 kfree_skb(skb);
818
819 return 0;
820}
821
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300822static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200823{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300824 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200825 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200826 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200827 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200828
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200829 BT_DBG("request for hci%u", index);
830
831 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200832 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
833 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200834
835 hdev = hci_dev_get(index);
836 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200837 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
838 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200839
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300840 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200841
842 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200843 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200844 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200845 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200846
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200847 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200848 if (err < 0)
849 goto failed;
850
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200851 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200852
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200853 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200854
855failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300856 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200857 hci_dev_put(hdev);
858
859 return err;
860}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200861
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300862static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200863{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300864 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200865 struct hci_dev *hdev;
866 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200867 int err;
868
Szymon Janc4e51eae2011-02-25 19:05:48 +0100869 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200870
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100871 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200872 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
873 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100874
Szymon Janc4e51eae2011-02-25 19:05:48 +0100875 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200876 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200877 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
878 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200879
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300880 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200881
882 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
883 if (!uuid) {
884 err = -ENOMEM;
885 goto failed;
886 }
887
888 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200889 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200890
891 list_add(&uuid->list, &hdev->uuids);
892
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200893 err = update_class(hdev);
894 if (err < 0)
895 goto failed;
896
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300897 err = update_eir(hdev);
898 if (err < 0)
899 goto failed;
900
Szymon Janc4e51eae2011-02-25 19:05:48 +0100901 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200902
903failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300904 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200905 hci_dev_put(hdev);
906
907 return err;
908}
909
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300910static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200911{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300912 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200913 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200914 struct hci_dev *hdev;
915 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 +0200916 int err, found;
917
Szymon Janc4e51eae2011-02-25 19:05:48 +0100918 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200919
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100920 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200921 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
922 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100923
Szymon Janc4e51eae2011-02-25 19:05:48 +0100924 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200925 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200926 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
927 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200928
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300929 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200930
931 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
932 err = hci_uuids_clear(hdev);
933 goto unlock;
934 }
935
936 found = 0;
937
938 list_for_each_safe(p, n, &hdev->uuids) {
939 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
940
941 if (memcmp(match->uuid, cp->uuid, 16) != 0)
942 continue;
943
944 list_del(&match->list);
945 found++;
946 }
947
948 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200949 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
950 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200951 goto unlock;
952 }
953
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200954 err = update_class(hdev);
955 if (err < 0)
956 goto unlock;
957
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300958 err = update_eir(hdev);
959 if (err < 0)
960 goto unlock;
961
Szymon Janc4e51eae2011-02-25 19:05:48 +0100962 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200963
964unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300965 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200966 hci_dev_put(hdev);
967
968 return err;
969}
970
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300971static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200972{
973 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300974 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200975 int err;
976
Szymon Janc4e51eae2011-02-25 19:05:48 +0100977 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200978
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100979 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200980 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
981 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100982
Szymon Janc4e51eae2011-02-25 19:05:48 +0100983 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200984 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200985 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
986 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200987
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300988 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200989
990 hdev->major_class = cp->major;
991 hdev->minor_class = cp->minor;
992
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200993 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +0200994 hci_dev_unlock(hdev);
995 cancel_delayed_work_sync(&hdev->service_cache);
996 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +0200997 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +0200998 }
Johan Hedberg14c0b602011-12-15 00:47:37 +0200999
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001000 err = update_class(hdev);
1001
1002 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001003 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001004
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001005 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001006 hci_dev_put(hdev);
1007
1008 return err;
1009}
1010
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001011static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001012{
1013 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001014 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001015 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001016 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001017
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001018 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001019 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1020 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001021
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001022 key_count = get_unaligned_le16(&cp->key_count);
1023
Johan Hedberg86742e12011-11-07 23:13:38 +02001024 expected_len = sizeof(*cp) + key_count *
1025 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001026 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001027 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001028 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001029 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1030 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001031 }
1032
Szymon Janc4e51eae2011-02-25 19:05:48 +01001033 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001034 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001035 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1036 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001037
Szymon Janc4e51eae2011-02-25 19:05:48 +01001038 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001039 key_count);
1040
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001041 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001042
1043 hci_link_keys_clear(hdev);
1044
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001045 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001046
1047 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001048 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001049 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001050 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001051
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001052 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001053 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001054
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001055 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001056 key->pin_len);
1057 }
1058
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001059 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1060
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001061 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001062 hci_dev_put(hdev);
1063
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001064 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001065}
1066
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001067static int remove_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001068{
1069 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001070 struct mgmt_cp_remove_keys *cp = data;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001071 struct mgmt_rp_remove_keys rp;
1072 struct hci_cp_disconnect dc;
1073 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001074 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001075 int err;
1076
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001077 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001078 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1079 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001080
Szymon Janc4e51eae2011-02-25 19:05:48 +01001081 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001082 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001083 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1084 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001085
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001086 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001087
Johan Hedberga8a1d192011-11-10 15:54:38 +02001088 memset(&rp, 0, sizeof(rp));
1089 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001090 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001091
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001092 err = hci_remove_ltk(hdev, &cp->bdaddr);
1093 if (err < 0) {
1094 err = cmd_status(sk, index, MGMT_OP_REMOVE_KEYS, -err);
1095 goto unlock;
1096 }
1097
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001098 err = hci_remove_link_key(hdev, &cp->bdaddr);
1099 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001100 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001101 goto unlock;
1102 }
1103
Johan Hedberga8a1d192011-11-10 15:54:38 +02001104 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1105 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1106 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001107 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001108 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001109
1110 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001111 if (!conn) {
1112 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1113 sizeof(rp));
1114 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001115 }
1116
Johan Hedberga8a1d192011-11-10 15:54:38 +02001117 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1118 if (!cmd) {
1119 err = -ENOMEM;
1120 goto unlock;
1121 }
1122
1123 put_unaligned_le16(conn->handle, &dc.handle);
1124 dc.reason = 0x13; /* Remote User Terminated Connection */
1125 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1126 if (err < 0)
1127 mgmt_pending_remove(cmd);
1128
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001129unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001130 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001131 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1132 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001133 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001134 hci_dev_put(hdev);
1135
1136 return err;
1137}
1138
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001139static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001140{
1141 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001142 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001143 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001144 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001145 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001146 int err;
1147
1148 BT_DBG("");
1149
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001150 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001151 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1152 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001153
Szymon Janc4e51eae2011-02-25 19:05:48 +01001154 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001155 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001156 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1157 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001158
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001159 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001160
1161 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001162 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1163 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001164 goto failed;
1165 }
1166
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001167 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001168 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1169 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001170 goto failed;
1171 }
1172
1173 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001174 if (!conn)
1175 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1176
Johan Hedberg8962ee72011-01-20 12:40:27 +02001177 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001178 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1179 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001180 goto failed;
1181 }
1182
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001183 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001184 if (!cmd) {
1185 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001186 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001187 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001188
1189 put_unaligned_le16(conn->handle, &dc.handle);
1190 dc.reason = 0x13; /* Remote User Terminated Connection */
1191
1192 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1193 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001194 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001195
1196failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001197 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001198 hci_dev_put(hdev);
1199
1200 return err;
1201}
1202
Johan Hedberg48264f02011-11-09 13:58:58 +02001203static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001204{
1205 switch (link_type) {
1206 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001207 switch (addr_type) {
1208 case ADDR_LE_DEV_PUBLIC:
1209 return MGMT_ADDR_LE_PUBLIC;
1210 case ADDR_LE_DEV_RANDOM:
1211 return MGMT_ADDR_LE_RANDOM;
1212 default:
1213 return MGMT_ADDR_INVALID;
1214 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001215 case ACL_LINK:
1216 return MGMT_ADDR_BREDR;
1217 default:
1218 return MGMT_ADDR_INVALID;
1219 }
1220}
1221
Szymon Janc8ce62842011-03-01 16:55:32 +01001222static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001223{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001224 struct mgmt_rp_get_connections *rp;
1225 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001226 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001227 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001228 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001229 int i, err;
1230
1231 BT_DBG("");
1232
Szymon Janc4e51eae2011-02-25 19:05:48 +01001233 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001234 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001235 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1236 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001237
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001238 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001239
1240 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001241 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1242 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1243 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001244 }
1245
Johan Hedberg4c659c32011-11-07 23:13:39 +02001246 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001247 rp = kmalloc(rp_len, GFP_ATOMIC);
1248 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001249 err = -ENOMEM;
1250 goto unlock;
1251 }
1252
Johan Hedberg2784eb42011-01-21 13:56:35 +02001253 put_unaligned_le16(count, &rp->conn_count);
1254
Johan Hedberg2784eb42011-01-21 13:56:35 +02001255 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001256 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001257 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1258 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001259 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001260 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001261 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1262 continue;
1263 i++;
1264 }
1265
1266 /* Recalculate length in case of filtered SCO connections, etc */
1267 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001268
Szymon Janc4e51eae2011-02-25 19:05:48 +01001269 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001270
1271unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001272 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001273 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001274 hci_dev_put(hdev);
1275 return err;
1276}
1277
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001278static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1279 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1280{
1281 struct pending_cmd *cmd;
1282 int err;
1283
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001284 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001285 sizeof(*cp));
1286 if (!cmd)
1287 return -ENOMEM;
1288
1289 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1290 &cp->bdaddr);
1291 if (err < 0)
1292 mgmt_pending_remove(cmd);
1293
1294 return err;
1295}
1296
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001297static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001298{
1299 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001300 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001301 struct mgmt_cp_pin_code_reply *cp = data;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001302 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001303 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001304 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001305 int err;
1306
1307 BT_DBG("");
1308
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001309 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001310 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1311 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001312
Szymon Janc4e51eae2011-02-25 19:05:48 +01001313 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001314 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001315 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1316 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001317
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001318 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001319
1320 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001321 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1322 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001323 goto failed;
1324 }
1325
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001326 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1327 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001328 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1329 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001330 goto failed;
1331 }
1332
1333 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1334 bacpy(&ncp.bdaddr, &cp->bdaddr);
1335
1336 BT_ERR("PIN code is not 16 bytes long");
1337
1338 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1339 if (err >= 0)
1340 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001341 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001342
1343 goto failed;
1344 }
1345
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001346 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1347 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001348 if (!cmd) {
1349 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001350 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001351 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001352
1353 bacpy(&reply.bdaddr, &cp->bdaddr);
1354 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001355 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001356
1357 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1358 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001359 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001360
1361failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001362 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001363 hci_dev_put(hdev);
1364
1365 return err;
1366}
1367
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001368static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001369{
1370 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001371 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001372 int err;
1373
1374 BT_DBG("");
1375
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001376 if (len != sizeof(*cp))
1377 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001378 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001379
Szymon Janc4e51eae2011-02-25 19:05:48 +01001380 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001381 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001382 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001383 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001384
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001385 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001386
1387 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001388 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001389 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001390 goto failed;
1391 }
1392
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001393 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001394
1395failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001396 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001397 hci_dev_put(hdev);
1398
1399 return err;
1400}
1401
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001402static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001403{
1404 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001405 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001406
1407 BT_DBG("");
1408
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001409 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001410 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1411 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001412
Szymon Janc4e51eae2011-02-25 19:05:48 +01001413 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001414 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001415 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1416 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001417
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001418 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001419
1420 hdev->io_capability = cp->io_capability;
1421
1422 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001423 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001424
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001425 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001426 hci_dev_put(hdev);
1427
Szymon Janc4e51eae2011-02-25 19:05:48 +01001428 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001429}
1430
Johan Hedberge9a416b2011-02-19 12:05:56 -03001431static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1432{
1433 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001434 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001435
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001436 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001437 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1438 continue;
1439
Johan Hedberge9a416b2011-02-19 12:05:56 -03001440 if (cmd->user_data != conn)
1441 continue;
1442
1443 return cmd;
1444 }
1445
1446 return NULL;
1447}
1448
1449static void pairing_complete(struct pending_cmd *cmd, u8 status)
1450{
1451 struct mgmt_rp_pair_device rp;
1452 struct hci_conn *conn = cmd->user_data;
1453
Johan Hedbergba4e5642011-11-11 00:07:34 +02001454 bacpy(&rp.addr.bdaddr, &conn->dst);
1455 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001456 rp.status = status;
1457
Szymon Janc4e51eae2011-02-25 19:05:48 +01001458 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001459
1460 /* So we don't get further callbacks for this connection */
1461 conn->connect_cfm_cb = NULL;
1462 conn->security_cfm_cb = NULL;
1463 conn->disconn_cfm_cb = NULL;
1464
1465 hci_conn_put(conn);
1466
Johan Hedberga664b5b2011-02-19 12:06:02 -03001467 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001468}
1469
1470static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1471{
1472 struct pending_cmd *cmd;
1473
1474 BT_DBG("status %u", status);
1475
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001476 cmd = find_pairing(conn);
1477 if (!cmd)
1478 BT_DBG("Unable to find a pending command");
1479 else
1480 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001481}
1482
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001483static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001484{
1485 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001486 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001487 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001488 struct pending_cmd *cmd;
1489 u8 sec_level, auth_type;
1490 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001491 int err;
1492
1493 BT_DBG("");
1494
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001495 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001496 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1497 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001498
Szymon Janc4e51eae2011-02-25 19:05:48 +01001499 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001500 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001501 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1502 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001503
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001504 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001505
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001506 sec_level = BT_SECURITY_MEDIUM;
1507 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001508 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001509 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001510 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001511
Johan Hedbergba4e5642011-11-11 00:07:34 +02001512 if (cp->addr.type == MGMT_ADDR_BREDR)
1513 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001514 auth_type);
1515 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001516 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001517 auth_type);
1518
Johan Hedberg1425acb2011-11-11 00:07:35 +02001519 memset(&rp, 0, sizeof(rp));
1520 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1521 rp.addr.type = cp->addr.type;
1522
Ville Tervo30e76272011-02-22 16:10:53 -03001523 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001524 rp.status = -PTR_ERR(conn);
1525 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1526 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001527 goto unlock;
1528 }
1529
1530 if (conn->connect_cfm_cb) {
1531 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001532 rp.status = EBUSY;
1533 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1534 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001535 goto unlock;
1536 }
1537
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001538 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001539 if (!cmd) {
1540 err = -ENOMEM;
1541 hci_conn_put(conn);
1542 goto unlock;
1543 }
1544
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001545 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001546 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001547 conn->connect_cfm_cb = pairing_complete_cb;
1548
Johan Hedberge9a416b2011-02-19 12:05:56 -03001549 conn->security_cfm_cb = pairing_complete_cb;
1550 conn->disconn_cfm_cb = pairing_complete_cb;
1551 conn->io_capability = cp->io_cap;
1552 cmd->user_data = conn;
1553
1554 if (conn->state == BT_CONNECTED &&
1555 hci_conn_security(conn, sec_level, auth_type))
1556 pairing_complete(cmd, 0);
1557
1558 err = 0;
1559
1560unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001561 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001562 hci_dev_put(hdev);
1563
1564 return err;
1565}
1566
Johan Hedberg28424702012-02-02 04:02:29 +02001567static int cancel_pair_device(struct sock *sk, u16 index,
1568 unsigned char *data, u16 len)
1569{
1570 struct mgmt_addr_info *addr = (void *) data;
1571 struct hci_dev *hdev;
1572 struct pending_cmd *cmd;
1573 struct hci_conn *conn;
1574 int err;
1575
1576 BT_DBG("");
1577
1578 if (len != sizeof(*addr))
1579 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1580 MGMT_STATUS_INVALID_PARAMS);
1581
1582 hdev = hci_dev_get(index);
1583 if (!hdev)
1584 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1585 MGMT_STATUS_INVALID_PARAMS);
1586
1587 hci_dev_lock(hdev);
1588
1589 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1590 if (!cmd) {
1591 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1592 MGMT_STATUS_INVALID_PARAMS);
1593 goto unlock;
1594 }
1595
1596 conn = cmd->user_data;
1597
1598 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1599 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1600 MGMT_STATUS_INVALID_PARAMS);
1601 goto unlock;
1602 }
1603
1604 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1605
1606 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr,
1607 sizeof(*addr));
1608unlock:
1609 hci_dev_unlock(hdev);
1610 hci_dev_put(hdev);
1611
1612 return err;
1613}
1614
Brian Gix0df4c182011-11-16 13:53:13 -08001615static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1616 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001617{
Johan Hedberga5c29682011-02-19 12:05:57 -03001618 struct pending_cmd *cmd;
1619 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001620 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001621 int err;
1622
Szymon Janc4e51eae2011-02-25 19:05:48 +01001623 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001624 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001625 return cmd_status(sk, index, mgmt_op,
1626 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001627
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001628 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001629
Johan Hedberga5c29682011-02-19 12:05:57 -03001630 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001631 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1632 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001633 }
1634
Brian Gix47c15e22011-11-16 13:53:14 -08001635 /*
1636 * Check for an existing ACL link, if present pair via
1637 * HCI commands.
1638 *
1639 * If no ACL link is present, check for an LE link and if
1640 * present, pair via the SMP engine.
1641 *
1642 * If neither ACL nor LE links are present, fail with error.
1643 */
1644 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1645 if (!conn) {
1646 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1647 if (!conn) {
1648 err = cmd_status(sk, index, mgmt_op,
1649 MGMT_STATUS_NOT_CONNECTED);
1650 goto done;
1651 }
1652
1653 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001654 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001655
Brian Gix5fe57d92011-12-21 16:12:13 -08001656 if (!err)
1657 err = cmd_status(sk, index, mgmt_op,
1658 MGMT_STATUS_SUCCESS);
1659 else
1660 err = cmd_status(sk, index, mgmt_op,
1661 MGMT_STATUS_FAILED);
1662
Brian Gix47c15e22011-11-16 13:53:14 -08001663 goto done;
1664 }
1665
Brian Gix0df4c182011-11-16 13:53:13 -08001666 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001667 if (!cmd) {
1668 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001669 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001670 }
1671
Brian Gix0df4c182011-11-16 13:53:13 -08001672 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001673 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1674 struct hci_cp_user_passkey_reply cp;
1675
1676 bacpy(&cp.bdaddr, bdaddr);
1677 cp.passkey = passkey;
1678 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1679 } else
1680 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1681
Johan Hedberga664b5b2011-02-19 12:06:02 -03001682 if (err < 0)
1683 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001684
Brian Gix0df4c182011-11-16 13:53:13 -08001685done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001686 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001687 hci_dev_put(hdev);
1688
1689 return err;
1690}
1691
Brian Gix0df4c182011-11-16 13:53:13 -08001692static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1693{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001694 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001695
1696 BT_DBG("");
1697
1698 if (len != sizeof(*cp))
1699 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1700 MGMT_STATUS_INVALID_PARAMS);
1701
1702 return user_pairing_resp(sk, index, &cp->bdaddr,
1703 MGMT_OP_USER_CONFIRM_REPLY,
1704 HCI_OP_USER_CONFIRM_REPLY, 0);
1705}
1706
1707static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1708 u16 len)
1709{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001710 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001711
1712 BT_DBG("");
1713
1714 if (len != sizeof(*cp))
1715 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1716 MGMT_STATUS_INVALID_PARAMS);
1717
1718 return user_pairing_resp(sk, index, &cp->bdaddr,
1719 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1720 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1721}
1722
Brian Gix604086b2011-11-23 08:28:33 -08001723static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1724{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001725 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001726
1727 BT_DBG("");
1728
1729 if (len != sizeof(*cp))
1730 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1731 EINVAL);
1732
1733 return user_pairing_resp(sk, index, &cp->bdaddr,
1734 MGMT_OP_USER_PASSKEY_REPLY,
1735 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1736}
1737
1738static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1739 u16 len)
1740{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001741 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001742
1743 BT_DBG("");
1744
1745 if (len != sizeof(*cp))
1746 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1747 EINVAL);
1748
1749 return user_pairing_resp(sk, index, &cp->bdaddr,
1750 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1751 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1752}
1753
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001754static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02001755 u16 len)
1756{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001757 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001758 struct hci_cp_write_local_name hci_cp;
1759 struct hci_dev *hdev;
1760 struct pending_cmd *cmd;
1761 int err;
1762
1763 BT_DBG("");
1764
1765 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001766 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1767 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001768
1769 hdev = hci_dev_get(index);
1770 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001771 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1772 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001773
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001774 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001775
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001776 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
1777 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001778 if (!cmd) {
1779 err = -ENOMEM;
1780 goto failed;
1781 }
1782
1783 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1784 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1785 &hci_cp);
1786 if (err < 0)
1787 mgmt_pending_remove(cmd);
1788
1789failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001790 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001791 hci_dev_put(hdev);
1792
1793 return err;
1794}
1795
Szymon Jancc35938b2011-03-22 13:12:21 +01001796static int read_local_oob_data(struct sock *sk, u16 index)
1797{
1798 struct hci_dev *hdev;
1799 struct pending_cmd *cmd;
1800 int err;
1801
1802 BT_DBG("hci%u", index);
1803
1804 hdev = hci_dev_get(index);
1805 if (!hdev)
1806 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001807 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001808
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001809 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001810
1811 if (!test_bit(HCI_UP, &hdev->flags)) {
1812 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001813 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001814 goto unlock;
1815 }
1816
1817 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1818 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001819 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001820 goto unlock;
1821 }
1822
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001823 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001824 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1825 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001826 goto unlock;
1827 }
1828
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001829 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001830 if (!cmd) {
1831 err = -ENOMEM;
1832 goto unlock;
1833 }
1834
1835 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1836 if (err < 0)
1837 mgmt_pending_remove(cmd);
1838
1839unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001840 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001841 hci_dev_put(hdev);
1842
1843 return err;
1844}
1845
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001846static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
1847 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01001848{
1849 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001850 struct mgmt_cp_add_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01001851 int err;
1852
1853 BT_DBG("hci%u ", index);
1854
1855 if (len != sizeof(*cp))
1856 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001857 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001858
1859 hdev = hci_dev_get(index);
1860 if (!hdev)
1861 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001862 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001863
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001864 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001865
1866 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1867 cp->randomizer);
1868 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001869 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1870 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001871 else
1872 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1873 0);
1874
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001875 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001876 hci_dev_put(hdev);
1877
1878 return err;
1879}
1880
1881static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001882 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01001883{
1884 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001885 struct mgmt_cp_remove_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01001886 int err;
1887
1888 BT_DBG("hci%u ", index);
1889
1890 if (len != sizeof(*cp))
1891 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001892 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001893
1894 hdev = hci_dev_get(index);
1895 if (!hdev)
1896 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001897 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001898
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001899 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001900
1901 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1902 if (err < 0)
1903 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001904 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001905 else
1906 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1907 NULL, 0);
1908
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001909 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001910 hci_dev_put(hdev);
1911
1912 return err;
1913}
1914
Johan Hedberg450dfda2011-11-12 11:58:22 +02001915static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001916 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001917{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001918 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04001919 struct pending_cmd *cmd;
1920 struct hci_dev *hdev;
1921 int err;
1922
1923 BT_DBG("hci%u", index);
1924
Johan Hedberg450dfda2011-11-12 11:58:22 +02001925 if (len != sizeof(*cp))
1926 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1927 MGMT_STATUS_INVALID_PARAMS);
1928
Johan Hedberg14a53662011-04-27 10:29:56 -04001929 hdev = hci_dev_get(index);
1930 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001931 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1932 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001933
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001934 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001935
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001936 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001937 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1938 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001939 goto failed;
1940 }
1941
Johan Hedbergff9ef572012-01-04 14:23:45 +02001942 if (hdev->discovery.state != DISCOVERY_STOPPED) {
1943 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1944 MGMT_STATUS_BUSY);
1945 goto failed;
1946 }
1947
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001948 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001949 if (!cmd) {
1950 err = -ENOMEM;
1951 goto failed;
1952 }
1953
Andre Guedes2519a1f2011-11-07 11:45:24 -03001954 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001955 if (err < 0)
1956 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02001957 else
1958 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04001959
1960failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001961 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001962 hci_dev_put(hdev);
1963
1964 return err;
1965}
1966
1967static int stop_discovery(struct sock *sk, u16 index)
1968{
1969 struct hci_dev *hdev;
1970 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001971 struct hci_cp_remote_name_req_cancel cp;
1972 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04001973 int err;
1974
1975 BT_DBG("hci%u", index);
1976
1977 hdev = hci_dev_get(index);
1978 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001979 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1980 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001981
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001982 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001983
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001984 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02001985 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1986 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001987 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02001988 }
1989
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001990 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001991 if (!cmd) {
1992 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001993 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04001994 }
1995
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001996 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
1997 err = hci_cancel_inquiry(hdev);
1998 if (err < 0)
1999 mgmt_pending_remove(cmd);
2000 else
2001 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2002 goto unlock;
2003 }
2004
2005 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2006 if (!e) {
2007 mgmt_pending_remove(cmd);
2008 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2009 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2010 goto unlock;
2011 }
2012
2013 bacpy(&cp.bdaddr, &e->data.bdaddr);
2014 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2015 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002016 if (err < 0)
2017 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002018 else
2019 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002020
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002021unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002022 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002023 hci_dev_put(hdev);
2024
2025 return err;
2026}
2027
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002028static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002029{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002030 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002031 struct inquiry_entry *e;
2032 struct hci_dev *hdev;
2033 int err;
2034
2035 BT_DBG("hci%u", index);
2036
2037 if (len != sizeof(*cp))
2038 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2039 MGMT_STATUS_INVALID_PARAMS);
2040
2041 hdev = hci_dev_get(index);
2042 if (!hdev)
2043 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2044 MGMT_STATUS_INVALID_PARAMS);
2045
2046 hci_dev_lock(hdev);
2047
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002048 if (!hci_discovery_active(hdev)) {
2049 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2050 MGMT_STATUS_FAILED);
2051 goto failed;
2052 }
2053
Johan Hedberg561aafb2012-01-04 13:31:59 +02002054 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr);
2055 if (!e) {
2056 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2057 MGMT_STATUS_INVALID_PARAMS);
2058 goto failed;
2059 }
2060
2061 if (cp->name_known) {
2062 e->name_state = NAME_KNOWN;
2063 list_del(&e->list);
2064 } else {
2065 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002066 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002067 }
2068
2069 err = 0;
2070
2071failed:
2072 hci_dev_unlock(hdev);
2073
2074 return err;
2075}
2076
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002077static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002078{
2079 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002080 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002081 int err;
2082
2083 BT_DBG("hci%u", index);
2084
Antti Julku7fbec222011-06-15 12:01:15 +03002085 if (len != sizeof(*cp))
2086 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002087 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002088
2089 hdev = hci_dev_get(index);
2090 if (!hdev)
2091 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002092 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002093
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002094 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002095
Antti Julku7fbec222011-06-15 12:01:15 +03002096 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03002097 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002098 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2099 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002100 else
2101 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2102 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002103
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002104 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002105 hci_dev_put(hdev);
2106
2107 return err;
2108}
2109
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002110static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002111{
2112 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002113 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002114 int err;
2115
2116 BT_DBG("hci%u", index);
2117
Antti Julku7fbec222011-06-15 12:01:15 +03002118 if (len != sizeof(*cp))
2119 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002120 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002121
2122 hdev = hci_dev_get(index);
2123 if (!hdev)
2124 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002125 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002126
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002127 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002128
Antti Julku7fbec222011-06-15 12:01:15 +03002129 err = hci_blacklist_del(hdev, &cp->bdaddr);
2130
2131 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002132 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2133 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002134 else
2135 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2136 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002137
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002138 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002139 hci_dev_put(hdev);
2140
2141 return err;
2142}
2143
Antti Julkuf6422ec2011-06-22 13:11:56 +03002144static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002145 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002146{
2147 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002148 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002149 struct hci_cp_write_page_scan_activity acp;
2150 u8 type;
2151 int err;
2152
2153 BT_DBG("hci%u", index);
2154
2155 if (len != sizeof(*cp))
2156 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002157 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002158
2159 hdev = hci_dev_get(index);
2160 if (!hdev)
2161 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002162 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002163
2164 hci_dev_lock(hdev);
2165
Johan Hedbergf7c68692011-12-15 00:47:36 +02002166 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002167 type = PAGE_SCAN_TYPE_INTERLACED;
2168 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2169 } else {
2170 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2171 acp.interval = 0x0800; /* default 1.28 sec page scan */
2172 }
2173
2174 acp.window = 0x0012; /* default 11.25 msec page scan window */
2175
2176 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2177 sizeof(acp), &acp);
2178 if (err < 0) {
2179 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002180 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002181 goto done;
2182 }
2183
2184 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2185 if (err < 0) {
2186 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002187 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002188 goto done;
2189 }
2190
2191 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2192 NULL, 0);
2193done:
2194 hci_dev_unlock(hdev);
2195 hci_dev_put(hdev);
2196
2197 return err;
2198}
2199
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002200static int load_long_term_keys(struct sock *sk, u16 index,
2201 void *cp_data, u16 len)
2202{
2203 struct hci_dev *hdev;
2204 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2205 u16 key_count, expected_len;
2206 int i;
2207
2208 if (len < sizeof(*cp))
2209 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2210 EINVAL);
2211
2212 key_count = get_unaligned_le16(&cp->key_count);
2213
2214 expected_len = sizeof(*cp) + key_count *
2215 sizeof(struct mgmt_ltk_info);
2216 if (expected_len != len) {
2217 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2218 len, expected_len);
2219 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2220 EINVAL);
2221 }
2222
2223 hdev = hci_dev_get(index);
2224 if (!hdev)
2225 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2226 ENODEV);
2227
2228 BT_DBG("hci%u key_count %u", index, key_count);
2229
2230 hci_dev_lock(hdev);
2231
2232 hci_smp_ltks_clear(hdev);
2233
2234 for (i = 0; i < key_count; i++) {
2235 struct mgmt_ltk_info *key = &cp->keys[i];
2236 u8 type;
2237
2238 if (key->master)
2239 type = HCI_SMP_LTK;
2240 else
2241 type = HCI_SMP_LTK_SLAVE;
2242
2243 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2244 type, 0, key->authenticated, key->val,
2245 key->enc_size, key->ediv, key->rand);
2246 }
2247
2248 hci_dev_unlock(hdev);
2249 hci_dev_put(hdev);
2250
2251 return 0;
2252}
2253
Johan Hedberg03811012010-12-08 00:21:06 +02002254int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2255{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002256 void *buf;
2257 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002258 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002259 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002260 int err;
2261
2262 BT_DBG("got %zu bytes", msglen);
2263
2264 if (msglen < sizeof(*hdr))
2265 return -EINVAL;
2266
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002267 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002268 if (!buf)
2269 return -ENOMEM;
2270
2271 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2272 err = -EFAULT;
2273 goto done;
2274 }
2275
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002276 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002277 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002278 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002279 len = get_unaligned_le16(&hdr->len);
2280
2281 if (len != msglen - sizeof(*hdr)) {
2282 err = -EINVAL;
2283 goto done;
2284 }
2285
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002286 cp = buf + sizeof(*hdr);
2287
Johan Hedberg03811012010-12-08 00:21:06 +02002288 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002289 case MGMT_OP_READ_VERSION:
2290 err = read_version(sk);
2291 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002292 case MGMT_OP_READ_INDEX_LIST:
2293 err = read_index_list(sk);
2294 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002295 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002296 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002297 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002298 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002299 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002300 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002301 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002302 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002303 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002304 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002305 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002306 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002307 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002308 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002309 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002310 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002311 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002312 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002313 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002314 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002315 break;
2316 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002317 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002318 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002319 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002320 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002321 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002322 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002323 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002324 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002325 case MGMT_OP_REMOVE_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002326 err = remove_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002327 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002328 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002329 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002330 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002331 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002332 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002333 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002334 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002335 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002336 break;
2337 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002338 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002339 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002340 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002341 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002342 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002343 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002344 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002345 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002346 case MGMT_OP_CANCEL_PAIR_DEVICE:
2347 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2348 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002349 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002350 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002351 break;
2352 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002353 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002354 break;
Brian Gix604086b2011-11-23 08:28:33 -08002355 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002356 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002357 break;
2358 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002359 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002360 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002361 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002362 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002363 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002364 case MGMT_OP_READ_LOCAL_OOB_DATA:
2365 err = read_local_oob_data(sk, index);
2366 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002367 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002368 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002369 break;
2370 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002371 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002372 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002373 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002374 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002375 break;
2376 case MGMT_OP_STOP_DISCOVERY:
2377 err = stop_discovery(sk, index);
2378 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002379 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002380 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002381 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002382 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002383 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002384 break;
2385 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002386 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002387 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002388 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2389 err = load_long_term_keys(sk, index, cp, len);
2390 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002391 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002392 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002393 err = cmd_status(sk, index, opcode,
2394 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002395 break;
2396 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002397
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002398 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002399 goto done;
2400
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002401 err = msglen;
2402
2403done:
2404 kfree(buf);
2405 return err;
2406}
2407
Johan Hedbergb24752f2011-11-03 14:40:33 +02002408static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2409{
2410 u8 *status = data;
2411
2412 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2413 mgmt_pending_remove(cmd);
2414}
2415
Johan Hedberg744cf192011-11-08 20:40:14 +02002416int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002417{
Johan Hedberg744cf192011-11-08 20:40:14 +02002418 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002419}
2420
Johan Hedberg744cf192011-11-08 20:40:14 +02002421int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002422{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002423 u8 status = ENODEV;
2424
Johan Hedberg744cf192011-11-08 20:40:14 +02002425 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002426
Johan Hedberg744cf192011-11-08 20:40:14 +02002427 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002428}
2429
2430struct cmd_lookup {
2431 u8 val;
2432 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002433 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002434};
2435
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002436static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002437{
Johan Hedberg03811012010-12-08 00:21:06 +02002438 struct cmd_lookup *match = data;
2439
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002440 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002441
2442 list_del(&cmd->list);
2443
2444 if (match->sk == NULL) {
2445 match->sk = cmd->sk;
2446 sock_hold(match->sk);
2447 }
2448
2449 mgmt_pending_free(cmd);
2450}
2451
Johan Hedberg744cf192011-11-08 20:40:14 +02002452int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002453{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002454 struct cmd_lookup match = { powered, NULL, hdev };
2455 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002456 int ret;
2457
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002458 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002459
Johan Hedbergb24752f2011-11-03 14:40:33 +02002460 if (!powered) {
2461 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002462 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002463 }
2464
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002465 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002466
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002467 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2468 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002469
2470 if (match.sk)
2471 sock_put(match.sk);
2472
2473 return ret;
2474}
2475
Johan Hedberg744cf192011-11-08 20:40:14 +02002476int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002477{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002478 struct cmd_lookup match = { discoverable, NULL, hdev };
2479 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002480 int ret;
2481
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002482 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002483
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002484 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002485
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002486 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002487 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002488 if (match.sk)
2489 sock_put(match.sk);
2490
2491 return ret;
2492}
2493
Johan Hedberg744cf192011-11-08 20:40:14 +02002494int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002495{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002496 __le32 ev;
2497 struct cmd_lookup match = { connectable, NULL, hdev };
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_CONNECTABLE, hdev, settings_rsp,
2501 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002502
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002503 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002504
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002505 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002506
2507 if (match.sk)
2508 sock_put(match.sk);
2509
2510 return ret;
2511}
2512
Johan Hedberg744cf192011-11-08 20:40:14 +02002513int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002514{
Johan Hedbergca69b792011-11-11 18:10:00 +02002515 u8 mgmt_err = mgmt_status(status);
2516
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002517 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002518 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002519 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002520
2521 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002522 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002523 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002524
2525 return 0;
2526}
2527
Johan Hedberg744cf192011-11-08 20:40:14 +02002528int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2529 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002530{
Johan Hedberg86742e12011-11-07 23:13:38 +02002531 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002532
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002533 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002534
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002535 ev.store_hint = persistent;
2536 bacpy(&ev.key.bdaddr, &key->bdaddr);
2537 ev.key.type = key->type;
2538 memcpy(ev.key.val, key->val, 16);
2539 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002540
Johan Hedberg744cf192011-11-08 20:40:14 +02002541 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002542}
Johan Hedbergf7520542011-01-20 12:34:39 +02002543
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002544int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2545{
2546 struct mgmt_ev_new_long_term_key ev;
2547
2548 memset(&ev, 0, sizeof(ev));
2549
2550 ev.store_hint = persistent;
2551 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2552 ev.key.addr.type = key->bdaddr_type;
2553 ev.key.authenticated = key->authenticated;
2554 ev.key.enc_size = key->enc_size;
2555 ev.key.ediv = key->ediv;
2556
2557 if (key->type == HCI_SMP_LTK)
2558 ev.key.master = 1;
2559
2560 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2561 memcpy(ev.key.val, key->val, sizeof(key->val));
2562
2563 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2564 &ev, sizeof(ev), NULL);
2565}
2566
Johan Hedbergafc747a2012-01-15 18:11:07 +02002567int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002568 u8 addr_type, u8 *name, u8 name_len,
2569 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002570{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002571 char buf[512];
2572 struct mgmt_ev_device_connected *ev = (void *) buf;
2573 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002574
Johan Hedbergb644ba32012-01-17 21:48:47 +02002575 bacpy(&ev->addr.bdaddr, bdaddr);
2576 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002577
Johan Hedbergb644ba32012-01-17 21:48:47 +02002578 if (name_len > 0)
2579 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2580 name, name_len);
2581
2582 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2583 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2584 EIR_CLASS_OF_DEV, dev_class, 3);
2585
2586 put_unaligned_le16(eir_len, &ev->eir_len);
2587
2588 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2589 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002590}
2591
Johan Hedberg8962ee72011-01-20 12:40:27 +02002592static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2593{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002594 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002595 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002596 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002597
Johan Hedberga38528f2011-01-22 06:46:43 +02002598 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002599 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002600
Szymon Janc4e51eae2011-02-25 19:05:48 +01002601 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002602
2603 *sk = cmd->sk;
2604 sock_hold(*sk);
2605
Johan Hedberga664b5b2011-02-19 12:06:02 -03002606 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002607}
2608
Johan Hedberga8a1d192011-11-10 15:54:38 +02002609static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2610{
2611 u8 *status = data;
2612 struct mgmt_cp_remove_keys *cp = cmd->param;
2613 struct mgmt_rp_remove_keys rp;
2614
2615 memset(&rp, 0, sizeof(rp));
2616 bacpy(&rp.bdaddr, &cp->bdaddr);
2617 if (status != NULL)
2618 rp.status = *status;
2619
2620 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2621 sizeof(rp));
2622
2623 mgmt_pending_remove(cmd);
2624}
2625
Johan Hedbergafc747a2012-01-15 18:11:07 +02002626int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2627 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002628{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002629 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002630 struct sock *sk = NULL;
2631 int err;
2632
Johan Hedberg744cf192011-11-08 20:40:14 +02002633 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002634
Johan Hedbergf7520542011-01-20 12:34:39 +02002635 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002636 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002637
Johan Hedbergafc747a2012-01-15 18:11:07 +02002638 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2639 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002640
2641 if (sk)
2642 sock_put(sk);
2643
Johan Hedberga8a1d192011-11-10 15:54:38 +02002644 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2645
Johan Hedberg8962ee72011-01-20 12:40:27 +02002646 return err;
2647}
2648
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002649int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002650{
2651 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002652 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002653 int err;
2654
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002655 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002656 if (!cmd)
2657 return -ENOENT;
2658
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002659 if (bdaddr) {
2660 struct mgmt_rp_disconnect rp;
2661
2662 bacpy(&rp.bdaddr, bdaddr);
2663 rp.status = status;
2664
2665 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2666 &rp, sizeof(rp));
2667 } else
2668 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002669 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002670
Johan Hedberga664b5b2011-02-19 12:06:02 -03002671 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002672
2673 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002674}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002675
Johan Hedberg48264f02011-11-09 13:58:58 +02002676int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2677 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002678{
2679 struct mgmt_ev_connect_failed ev;
2680
Johan Hedberg4c659c32011-11-07 23:13:39 +02002681 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002682 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002683 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002684
Johan Hedberg744cf192011-11-08 20:40:14 +02002685 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002686}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002687
Johan Hedberg744cf192011-11-08 20:40:14 +02002688int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002689{
2690 struct mgmt_ev_pin_code_request ev;
2691
Johan Hedberg980e1a52011-01-22 06:10:07 +02002692 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002693 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002694
Johan Hedberg744cf192011-11-08 20:40:14 +02002695 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002696 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002697}
2698
Johan Hedberg744cf192011-11-08 20:40:14 +02002699int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2700 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002701{
2702 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002703 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002704 int err;
2705
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002706 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002707 if (!cmd)
2708 return -ENOENT;
2709
Johan Hedbergac56fb12011-02-19 12:05:59 -03002710 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002711 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002712
Johan Hedberg744cf192011-11-08 20:40:14 +02002713 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002714 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002715
Johan Hedberga664b5b2011-02-19 12:06:02 -03002716 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002717
2718 return err;
2719}
2720
Johan Hedberg744cf192011-11-08 20:40:14 +02002721int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2722 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002723{
2724 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002725 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002726 int err;
2727
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002728 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002729 if (!cmd)
2730 return -ENOENT;
2731
Johan Hedbergac56fb12011-02-19 12:05:59 -03002732 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002733 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002734
Johan Hedberg744cf192011-11-08 20:40:14 +02002735 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002736 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002737
Johan Hedberga664b5b2011-02-19 12:06:02 -03002738 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002739
2740 return err;
2741}
Johan Hedberga5c29682011-02-19 12:05:57 -03002742
Johan Hedberg744cf192011-11-08 20:40:14 +02002743int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2744 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002745{
2746 struct mgmt_ev_user_confirm_request ev;
2747
Johan Hedberg744cf192011-11-08 20:40:14 +02002748 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002749
Johan Hedberga5c29682011-02-19 12:05:57 -03002750 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002751 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002752 put_unaligned_le32(value, &ev.value);
2753
Johan Hedberg744cf192011-11-08 20:40:14 +02002754 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002755 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002756}
2757
Brian Gix604086b2011-11-23 08:28:33 -08002758int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2759{
2760 struct mgmt_ev_user_passkey_request ev;
2761
2762 BT_DBG("%s", hdev->name);
2763
2764 bacpy(&ev.bdaddr, bdaddr);
2765
2766 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2767 NULL);
2768}
2769
Brian Gix0df4c182011-11-16 13:53:13 -08002770static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002771 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002772{
2773 struct pending_cmd *cmd;
2774 struct mgmt_rp_user_confirm_reply rp;
2775 int err;
2776
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002777 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002778 if (!cmd)
2779 return -ENOENT;
2780
Johan Hedberga5c29682011-02-19 12:05:57 -03002781 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002782 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002783 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002784
Johan Hedberga664b5b2011-02-19 12:06:02 -03002785 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002786
2787 return err;
2788}
2789
Johan Hedberg744cf192011-11-08 20:40:14 +02002790int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2791 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002792{
Brian Gix0df4c182011-11-16 13:53:13 -08002793 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002794 MGMT_OP_USER_CONFIRM_REPLY);
2795}
2796
Johan Hedberg744cf192011-11-08 20:40:14 +02002797int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2798 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002799{
Brian Gix0df4c182011-11-16 13:53:13 -08002800 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002801 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2802}
Johan Hedberg2a611692011-02-19 12:06:00 -03002803
Brian Gix604086b2011-11-23 08:28:33 -08002804int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2805 u8 status)
2806{
2807 return user_pairing_resp_complete(hdev, bdaddr, status,
2808 MGMT_OP_USER_PASSKEY_REPLY);
2809}
2810
2811int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2812 bdaddr_t *bdaddr, u8 status)
2813{
2814 return user_pairing_resp_complete(hdev, bdaddr, status,
2815 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2816}
2817
Johan Hedberg744cf192011-11-08 20:40:14 +02002818int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002819{
2820 struct mgmt_ev_auth_failed ev;
2821
Johan Hedberg2a611692011-02-19 12:06:00 -03002822 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002823 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002824
Johan Hedberg744cf192011-11-08 20:40:14 +02002825 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002826}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002827
Johan Hedberg744cf192011-11-08 20:40:14 +02002828int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002829{
2830 struct pending_cmd *cmd;
2831 struct mgmt_cp_set_local_name ev;
2832 int err;
2833
2834 memset(&ev, 0, sizeof(ev));
2835 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2836
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002837 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002838 if (!cmd)
2839 goto send_event;
2840
2841 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002842 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002843 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002844 goto failed;
2845 }
2846
Johan Hedberg744cf192011-11-08 20:40:14 +02002847 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002848
Johan Hedberg744cf192011-11-08 20:40:14 +02002849 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002850 sizeof(ev));
2851 if (err < 0)
2852 goto failed;
2853
2854send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002855 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002856 cmd ? cmd->sk : NULL);
2857
2858failed:
2859 if (cmd)
2860 mgmt_pending_remove(cmd);
2861 return err;
2862}
Szymon Jancc35938b2011-03-22 13:12:21 +01002863
Johan Hedberg744cf192011-11-08 20:40:14 +02002864int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2865 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002866{
2867 struct pending_cmd *cmd;
2868 int err;
2869
Johan Hedberg744cf192011-11-08 20:40:14 +02002870 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002871
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002872 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002873 if (!cmd)
2874 return -ENOENT;
2875
2876 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002877 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002878 MGMT_OP_READ_LOCAL_OOB_DATA,
2879 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002880 } else {
2881 struct mgmt_rp_read_local_oob_data rp;
2882
2883 memcpy(rp.hash, hash, sizeof(rp.hash));
2884 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2885
Johan Hedberg744cf192011-11-08 20:40:14 +02002886 err = cmd_complete(cmd->sk, hdev->id,
2887 MGMT_OP_READ_LOCAL_OOB_DATA,
2888 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002889 }
2890
2891 mgmt_pending_remove(cmd);
2892
2893 return err;
2894}
Johan Hedberge17acd42011-03-30 23:57:16 +03002895
Johan Hedberg48264f02011-11-09 13:58:58 +02002896int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002897 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02002898 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03002899{
Johan Hedberge319d2e2012-01-15 19:51:59 +02002900 char buf[512];
2901 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02002902 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03002903
Johan Hedberg1dc06092012-01-15 21:01:23 +02002904 /* Leave 5 bytes for a potential CoD field */
2905 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03002906 return -EINVAL;
2907
Johan Hedberg1dc06092012-01-15 21:01:23 +02002908 memset(buf, 0, sizeof(buf));
2909
Johan Hedberge319d2e2012-01-15 19:51:59 +02002910 bacpy(&ev->addr.bdaddr, bdaddr);
2911 ev->addr.type = link_to_mgmt(link_type, addr_type);
2912 ev->rssi = rssi;
2913 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03002914
Johan Hedberg1dc06092012-01-15 21:01:23 +02002915 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02002916 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03002917
Johan Hedberg1dc06092012-01-15 21:01:23 +02002918 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
2919 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
2920 dev_class, 3);
2921
2922 put_unaligned_le16(eir_len, &ev->eir_len);
2923
2924 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03002925
Johan Hedberge319d2e2012-01-15 19:51:59 +02002926 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002927}
Johan Hedberga88a9652011-03-30 13:18:12 +03002928
Johan Hedbergb644ba32012-01-17 21:48:47 +02002929int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2930 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03002931{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002932 struct mgmt_ev_device_found *ev;
2933 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
2934 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03002935
Johan Hedbergb644ba32012-01-17 21:48:47 +02002936 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03002937
Johan Hedbergb644ba32012-01-17 21:48:47 +02002938 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03002939
Johan Hedbergb644ba32012-01-17 21:48:47 +02002940 bacpy(&ev->addr.bdaddr, bdaddr);
2941 ev->addr.type = link_to_mgmt(link_type, addr_type);
2942 ev->rssi = rssi;
2943
2944 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
2945 name_len);
2946
2947 put_unaligned_le16(eir_len, &ev->eir_len);
2948
2949 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002950}
Johan Hedberg314b2382011-04-27 10:29:57 -04002951
Andre Guedes7a135102011-11-09 17:14:25 -03002952int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002953{
2954 struct pending_cmd *cmd;
2955 int err;
2956
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002957 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002958 if (!cmd)
2959 return -ENOENT;
2960
Johan Hedbergca69b792011-11-11 18:10:00 +02002961 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002962 mgmt_pending_remove(cmd);
2963
2964 return err;
2965}
2966
Andre Guedese6d465c2011-11-09 17:14:26 -03002967int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2968{
2969 struct pending_cmd *cmd;
2970 int err;
2971
2972 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2973 if (!cmd)
2974 return -ENOENT;
2975
Andre Guedese75a8b0c2012-01-02 16:50:53 -03002976 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02002977 mgmt_pending_remove(cmd);
2978
2979 return err;
2980}
Johan Hedberg314b2382011-04-27 10:29:57 -04002981
Johan Hedberg744cf192011-11-08 20:40:14 +02002982int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002983{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002984 struct pending_cmd *cmd;
2985
2986 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002987 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002988 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002989 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002990
2991 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002992 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002993 mgmt_pending_remove(cmd);
2994 }
2995
Johan Hedberg744cf192011-11-08 20:40:14 +02002996 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002997 sizeof(discovering), NULL);
2998}
Antti Julku5e762442011-08-25 16:48:02 +03002999
Johan Hedberg744cf192011-11-08 20:40:14 +02003000int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03003001{
3002 struct pending_cmd *cmd;
3003 struct mgmt_ev_device_blocked ev;
3004
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003005 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003006
3007 bacpy(&ev.bdaddr, bdaddr);
3008
Johan Hedberg744cf192011-11-08 20:40:14 +02003009 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3010 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003011}
3012
Johan Hedberg744cf192011-11-08 20:40:14 +02003013int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03003014{
3015 struct pending_cmd *cmd;
3016 struct mgmt_ev_device_unblocked ev;
3017
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003018 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003019
3020 bacpy(&ev.bdaddr, bdaddr);
3021
Johan Hedberg744cf192011-11-08 20:40:14 +02003022 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3023 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003024}