blob: fd0b08115f2ea7fc8593a16259aa5c90b49df0a2 [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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200149 kfree_skb(skb);
150
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300151 return err;
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200299
Johan Hedberg84bde9d6c2012-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 Hedbergf7b64e692010-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 Hedberg84bde9d6c2012-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200683
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300684 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001092 err = hci_remove_link_key(hdev, &cp->bdaddr);
1093 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001094 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001095 goto unlock;
1096 }
1097
Johan Hedberga8a1d192011-11-10 15:54:38 +02001098 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1099 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1100 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001101 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001102 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001103
1104 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001105 if (!conn) {
1106 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1107 sizeof(rp));
1108 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001109 }
1110
Johan Hedberga8a1d192011-11-10 15:54:38 +02001111 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1112 if (!cmd) {
1113 err = -ENOMEM;
1114 goto unlock;
1115 }
1116
1117 put_unaligned_le16(conn->handle, &dc.handle);
1118 dc.reason = 0x13; /* Remote User Terminated Connection */
1119 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1120 if (err < 0)
1121 mgmt_pending_remove(cmd);
1122
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001123unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001124 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001125 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1126 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001127 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001128 hci_dev_put(hdev);
1129
1130 return err;
1131}
1132
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001133static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001134{
1135 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001136 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001137 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001138 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001139 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001140 int err;
1141
1142 BT_DBG("");
1143
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001144 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001145 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1146 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001147
Szymon Janc4e51eae2011-02-25 19:05:48 +01001148 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001149 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001150 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1151 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001152
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001153 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001154
1155 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001156 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1157 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001158 goto failed;
1159 }
1160
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001161 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001162 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1163 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001164 goto failed;
1165 }
1166
1167 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001168 if (!conn)
1169 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1170
Johan Hedberg8962ee72011-01-20 12:40:27 +02001171 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001172 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1173 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001174 goto failed;
1175 }
1176
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001177 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001178 if (!cmd) {
1179 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001180 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001181 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001182
1183 put_unaligned_le16(conn->handle, &dc.handle);
1184 dc.reason = 0x13; /* Remote User Terminated Connection */
1185
1186 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1187 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001188 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001189
1190failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001191 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001192 hci_dev_put(hdev);
1193
1194 return err;
1195}
1196
Johan Hedberg48264f02011-11-09 13:58:58 +02001197static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001198{
1199 switch (link_type) {
1200 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001201 switch (addr_type) {
1202 case ADDR_LE_DEV_PUBLIC:
1203 return MGMT_ADDR_LE_PUBLIC;
1204 case ADDR_LE_DEV_RANDOM:
1205 return MGMT_ADDR_LE_RANDOM;
1206 default:
1207 return MGMT_ADDR_INVALID;
1208 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001209 case ACL_LINK:
1210 return MGMT_ADDR_BREDR;
1211 default:
1212 return MGMT_ADDR_INVALID;
1213 }
1214}
1215
Szymon Janc8ce62842011-03-01 16:55:32 +01001216static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001217{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001218 struct mgmt_rp_get_connections *rp;
1219 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001220 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001221 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001222 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001223 int i, err;
1224
1225 BT_DBG("");
1226
Szymon Janc4e51eae2011-02-25 19:05:48 +01001227 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001228 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001229 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1230 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001231
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001232 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001233
1234 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001235 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1236 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1237 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001238 }
1239
Johan Hedberg4c659c32011-11-07 23:13:39 +02001240 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001241 rp = kmalloc(rp_len, GFP_ATOMIC);
1242 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001243 err = -ENOMEM;
1244 goto unlock;
1245 }
1246
Johan Hedberg2784eb42011-01-21 13:56:35 +02001247 put_unaligned_le16(count, &rp->conn_count);
1248
Johan Hedberg2784eb42011-01-21 13:56:35 +02001249 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001250 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001251 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1252 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001253 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001254 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001255 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1256 continue;
1257 i++;
1258 }
1259
1260 /* Recalculate length in case of filtered SCO connections, etc */
1261 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001262
Szymon Janc4e51eae2011-02-25 19:05:48 +01001263 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001264
1265unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001266 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001267 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001268 hci_dev_put(hdev);
1269 return err;
1270}
1271
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001272static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1273 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1274{
1275 struct pending_cmd *cmd;
1276 int err;
1277
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001278 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001279 sizeof(*cp));
1280 if (!cmd)
1281 return -ENOMEM;
1282
1283 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1284 &cp->bdaddr);
1285 if (err < 0)
1286 mgmt_pending_remove(cmd);
1287
1288 return err;
1289}
1290
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001291static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001292{
1293 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001294 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001295 struct mgmt_cp_pin_code_reply *cp = data;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001296 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001297 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001298 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001299 int err;
1300
1301 BT_DBG("");
1302
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001303 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001304 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1305 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001306
Szymon Janc4e51eae2011-02-25 19:05:48 +01001307 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001308 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001309 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1310 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001311
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001312 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001313
1314 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001315 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1316 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001317 goto failed;
1318 }
1319
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001320 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1321 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001322 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1323 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001324 goto failed;
1325 }
1326
1327 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1328 bacpy(&ncp.bdaddr, &cp->bdaddr);
1329
1330 BT_ERR("PIN code is not 16 bytes long");
1331
1332 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1333 if (err >= 0)
1334 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001335 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001336
1337 goto failed;
1338 }
1339
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001340 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1341 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001342 if (!cmd) {
1343 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001344 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001345 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001346
1347 bacpy(&reply.bdaddr, &cp->bdaddr);
1348 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001349 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001350
1351 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1352 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001353 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001354
1355failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001356 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001357 hci_dev_put(hdev);
1358
1359 return err;
1360}
1361
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001362static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001363{
1364 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001365 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001366 int err;
1367
1368 BT_DBG("");
1369
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001370 if (len != sizeof(*cp))
1371 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001372 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001373
Szymon Janc4e51eae2011-02-25 19:05:48 +01001374 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001375 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001376 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001377 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001378
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001379 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001380
1381 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001382 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001383 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001384 goto failed;
1385 }
1386
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001387 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001388
1389failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001390 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001391 hci_dev_put(hdev);
1392
1393 return err;
1394}
1395
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001396static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001397{
1398 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001399 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001400
1401 BT_DBG("");
1402
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001403 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001404 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1405 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001406
Szymon Janc4e51eae2011-02-25 19:05:48 +01001407 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001408 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001409 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1410 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001411
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001412 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001413
1414 hdev->io_capability = cp->io_capability;
1415
1416 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001417 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001418
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001419 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001420 hci_dev_put(hdev);
1421
Szymon Janc4e51eae2011-02-25 19:05:48 +01001422 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001423}
1424
Johan Hedberge9a416b2011-02-19 12:05:56 -03001425static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1426{
1427 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001428 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001429
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001430 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001431 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1432 continue;
1433
Johan Hedberge9a416b2011-02-19 12:05:56 -03001434 if (cmd->user_data != conn)
1435 continue;
1436
1437 return cmd;
1438 }
1439
1440 return NULL;
1441}
1442
1443static void pairing_complete(struct pending_cmd *cmd, u8 status)
1444{
1445 struct mgmt_rp_pair_device rp;
1446 struct hci_conn *conn = cmd->user_data;
1447
Johan Hedbergba4e5642011-11-11 00:07:34 +02001448 bacpy(&rp.addr.bdaddr, &conn->dst);
1449 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001450 rp.status = status;
1451
Szymon Janc4e51eae2011-02-25 19:05:48 +01001452 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001453
1454 /* So we don't get further callbacks for this connection */
1455 conn->connect_cfm_cb = NULL;
1456 conn->security_cfm_cb = NULL;
1457 conn->disconn_cfm_cb = NULL;
1458
1459 hci_conn_put(conn);
1460
Johan Hedberga664b5b2011-02-19 12:06:02 -03001461 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001462}
1463
1464static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1465{
1466 struct pending_cmd *cmd;
1467
1468 BT_DBG("status %u", status);
1469
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001470 cmd = find_pairing(conn);
1471 if (!cmd)
1472 BT_DBG("Unable to find a pending command");
1473 else
1474 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001475}
1476
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001477static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001478{
1479 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001480 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001481 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001482 struct pending_cmd *cmd;
1483 u8 sec_level, auth_type;
1484 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001485 int err;
1486
1487 BT_DBG("");
1488
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001489 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001490 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1491 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001492
Szymon Janc4e51eae2011-02-25 19:05:48 +01001493 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001494 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001495 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1496 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001497
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001498 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001499
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001500 sec_level = BT_SECURITY_MEDIUM;
1501 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001502 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001503 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001504 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001505
Johan Hedbergba4e5642011-11-11 00:07:34 +02001506 if (cp->addr.type == MGMT_ADDR_BREDR)
1507 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001508 auth_type);
1509 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001510 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001511 auth_type);
1512
Johan Hedberg1425acb2011-11-11 00:07:35 +02001513 memset(&rp, 0, sizeof(rp));
1514 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1515 rp.addr.type = cp->addr.type;
1516
Ville Tervo30e76272011-02-22 16:10:53 -03001517 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001518 rp.status = -PTR_ERR(conn);
1519 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1520 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001521 goto unlock;
1522 }
1523
1524 if (conn->connect_cfm_cb) {
1525 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001526 rp.status = EBUSY;
1527 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1528 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001529 goto unlock;
1530 }
1531
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001532 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001533 if (!cmd) {
1534 err = -ENOMEM;
1535 hci_conn_put(conn);
1536 goto unlock;
1537 }
1538
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001539 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001540 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001541 conn->connect_cfm_cb = pairing_complete_cb;
1542
Johan Hedberge9a416b2011-02-19 12:05:56 -03001543 conn->security_cfm_cb = pairing_complete_cb;
1544 conn->disconn_cfm_cb = pairing_complete_cb;
1545 conn->io_capability = cp->io_cap;
1546 cmd->user_data = conn;
1547
1548 if (conn->state == BT_CONNECTED &&
1549 hci_conn_security(conn, sec_level, auth_type))
1550 pairing_complete(cmd, 0);
1551
1552 err = 0;
1553
1554unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001555 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001556 hci_dev_put(hdev);
1557
1558 return err;
1559}
1560
Johan Hedberg28424702012-02-02 04:02:29 +02001561static int cancel_pair_device(struct sock *sk, u16 index,
1562 unsigned char *data, u16 len)
1563{
1564 struct mgmt_addr_info *addr = (void *) data;
1565 struct hci_dev *hdev;
1566 struct pending_cmd *cmd;
1567 struct hci_conn *conn;
1568 int err;
1569
1570 BT_DBG("");
1571
1572 if (len != sizeof(*addr))
1573 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1574 MGMT_STATUS_INVALID_PARAMS);
1575
1576 hdev = hci_dev_get(index);
1577 if (!hdev)
1578 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1579 MGMT_STATUS_INVALID_PARAMS);
1580
1581 hci_dev_lock(hdev);
1582
1583 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1584 if (!cmd) {
1585 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1586 MGMT_STATUS_INVALID_PARAMS);
1587 goto unlock;
1588 }
1589
1590 conn = cmd->user_data;
1591
1592 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1593 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1594 MGMT_STATUS_INVALID_PARAMS);
1595 goto unlock;
1596 }
1597
1598 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1599
1600 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr,
1601 sizeof(*addr));
1602unlock:
1603 hci_dev_unlock(hdev);
1604 hci_dev_put(hdev);
1605
1606 return err;
1607}
1608
Brian Gix0df4c182011-11-16 13:53:13 -08001609static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1610 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001611{
Johan Hedberga5c29682011-02-19 12:05:57 -03001612 struct pending_cmd *cmd;
1613 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001614 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001615 int err;
1616
Szymon Janc4e51eae2011-02-25 19:05:48 +01001617 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001618 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001619 return cmd_status(sk, index, mgmt_op,
1620 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001621
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001622 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001623
Johan Hedberga5c29682011-02-19 12:05:57 -03001624 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001625 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1626 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001627 }
1628
Brian Gix47c15e22011-11-16 13:53:14 -08001629 /*
1630 * Check for an existing ACL link, if present pair via
1631 * HCI commands.
1632 *
1633 * If no ACL link is present, check for an LE link and if
1634 * present, pair via the SMP engine.
1635 *
1636 * If neither ACL nor LE links are present, fail with error.
1637 */
1638 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1639 if (!conn) {
1640 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1641 if (!conn) {
1642 err = cmd_status(sk, index, mgmt_op,
1643 MGMT_STATUS_NOT_CONNECTED);
1644 goto done;
1645 }
1646
1647 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001648 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001649
Brian Gix5fe57d92011-12-21 16:12:13 -08001650 if (!err)
1651 err = cmd_status(sk, index, mgmt_op,
1652 MGMT_STATUS_SUCCESS);
1653 else
1654 err = cmd_status(sk, index, mgmt_op,
1655 MGMT_STATUS_FAILED);
1656
Brian Gix47c15e22011-11-16 13:53:14 -08001657 goto done;
1658 }
1659
Brian Gix0df4c182011-11-16 13:53:13 -08001660 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001661 if (!cmd) {
1662 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001663 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001664 }
1665
Brian Gix0df4c182011-11-16 13:53:13 -08001666 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001667 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1668 struct hci_cp_user_passkey_reply cp;
1669
1670 bacpy(&cp.bdaddr, bdaddr);
1671 cp.passkey = passkey;
1672 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1673 } else
1674 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1675
Johan Hedberga664b5b2011-02-19 12:06:02 -03001676 if (err < 0)
1677 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001678
Brian Gix0df4c182011-11-16 13:53:13 -08001679done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001680 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001681 hci_dev_put(hdev);
1682
1683 return err;
1684}
1685
Brian Gix0df4c182011-11-16 13:53:13 -08001686static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1687{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001688 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001689
1690 BT_DBG("");
1691
1692 if (len != sizeof(*cp))
1693 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1694 MGMT_STATUS_INVALID_PARAMS);
1695
1696 return user_pairing_resp(sk, index, &cp->bdaddr,
1697 MGMT_OP_USER_CONFIRM_REPLY,
1698 HCI_OP_USER_CONFIRM_REPLY, 0);
1699}
1700
1701static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1702 u16 len)
1703{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001704 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001705
1706 BT_DBG("");
1707
1708 if (len != sizeof(*cp))
1709 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1710 MGMT_STATUS_INVALID_PARAMS);
1711
1712 return user_pairing_resp(sk, index, &cp->bdaddr,
1713 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1714 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1715}
1716
Brian Gix604086b2011-11-23 08:28:33 -08001717static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1718{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001719 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001720
1721 BT_DBG("");
1722
1723 if (len != sizeof(*cp))
1724 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1725 EINVAL);
1726
1727 return user_pairing_resp(sk, index, &cp->bdaddr,
1728 MGMT_OP_USER_PASSKEY_REPLY,
1729 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1730}
1731
1732static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1733 u16 len)
1734{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001735 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001736
1737 BT_DBG("");
1738
1739 if (len != sizeof(*cp))
1740 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1741 EINVAL);
1742
1743 return user_pairing_resp(sk, index, &cp->bdaddr,
1744 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1745 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1746}
1747
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001748static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02001749 u16 len)
1750{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001751 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02001752 struct hci_cp_write_local_name hci_cp;
1753 struct hci_dev *hdev;
1754 struct pending_cmd *cmd;
1755 int err;
1756
1757 BT_DBG("");
1758
1759 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001760 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1761 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001762
1763 hdev = hci_dev_get(index);
1764 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001765 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1766 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001767
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001768 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001769
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001770 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
1771 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001772 if (!cmd) {
1773 err = -ENOMEM;
1774 goto failed;
1775 }
1776
1777 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1778 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1779 &hci_cp);
1780 if (err < 0)
1781 mgmt_pending_remove(cmd);
1782
1783failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001784 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001785 hci_dev_put(hdev);
1786
1787 return err;
1788}
1789
Szymon Jancc35938b2011-03-22 13:12:21 +01001790static int read_local_oob_data(struct sock *sk, u16 index)
1791{
1792 struct hci_dev *hdev;
1793 struct pending_cmd *cmd;
1794 int err;
1795
1796 BT_DBG("hci%u", index);
1797
1798 hdev = hci_dev_get(index);
1799 if (!hdev)
1800 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001801 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001802
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001803 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001804
1805 if (!test_bit(HCI_UP, &hdev->flags)) {
1806 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001807 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001808 goto unlock;
1809 }
1810
1811 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1812 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001813 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001814 goto unlock;
1815 }
1816
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001817 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001818 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1819 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001820 goto unlock;
1821 }
1822
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001823 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001824 if (!cmd) {
1825 err = -ENOMEM;
1826 goto unlock;
1827 }
1828
1829 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1830 if (err < 0)
1831 mgmt_pending_remove(cmd);
1832
1833unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001834 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001835 hci_dev_put(hdev);
1836
1837 return err;
1838}
1839
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001840static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
1841 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01001842{
1843 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001844 struct mgmt_cp_add_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01001845 int err;
1846
1847 BT_DBG("hci%u ", index);
1848
1849 if (len != sizeof(*cp))
1850 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001851 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001852
1853 hdev = hci_dev_get(index);
1854 if (!hdev)
1855 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001856 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001858 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001859
1860 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1861 cp->randomizer);
1862 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001863 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1864 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001865 else
1866 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1867 0);
1868
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001869 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001870 hci_dev_put(hdev);
1871
1872 return err;
1873}
1874
1875static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001876 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01001877{
1878 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001879 struct mgmt_cp_remove_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01001880 int err;
1881
1882 BT_DBG("hci%u ", index);
1883
1884 if (len != sizeof(*cp))
1885 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001886 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001887
1888 hdev = hci_dev_get(index);
1889 if (!hdev)
1890 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001891 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001892
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001893 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001894
1895 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1896 if (err < 0)
1897 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001898 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001899 else
1900 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1901 NULL, 0);
1902
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001903 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001904 hci_dev_put(hdev);
1905
1906 return err;
1907}
1908
Johan Hedberg450dfda2011-11-12 11:58:22 +02001909static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001910 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001911{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001912 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04001913 struct pending_cmd *cmd;
1914 struct hci_dev *hdev;
1915 int err;
1916
1917 BT_DBG("hci%u", index);
1918
Johan Hedberg450dfda2011-11-12 11:58:22 +02001919 if (len != sizeof(*cp))
1920 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1921 MGMT_STATUS_INVALID_PARAMS);
1922
Johan Hedberg14a53662011-04-27 10:29:56 -04001923 hdev = hci_dev_get(index);
1924 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001925 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1926 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001927
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001928 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001929
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001930 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001931 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1932 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001933 goto failed;
1934 }
1935
Johan Hedbergff9ef572012-01-04 14:23:45 +02001936 if (hdev->discovery.state != DISCOVERY_STOPPED) {
1937 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1938 MGMT_STATUS_BUSY);
1939 goto failed;
1940 }
1941
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001942 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001943 if (!cmd) {
1944 err = -ENOMEM;
1945 goto failed;
1946 }
1947
Andre Guedes2519a1f2011-11-07 11:45:24 -03001948 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001949 if (err < 0)
1950 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02001951 else
1952 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04001953
1954failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001955 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001956 hci_dev_put(hdev);
1957
1958 return err;
1959}
1960
1961static int stop_discovery(struct sock *sk, u16 index)
1962{
1963 struct hci_dev *hdev;
1964 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001965 struct hci_cp_remote_name_req_cancel cp;
1966 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04001967 int err;
1968
1969 BT_DBG("hci%u", index);
1970
1971 hdev = hci_dev_get(index);
1972 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001973 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1974 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001975
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001976 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001977
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001978 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02001979 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1980 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001981 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02001982 }
1983
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001984 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001985 if (!cmd) {
1986 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001987 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04001988 }
1989
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001990 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
1991 err = hci_cancel_inquiry(hdev);
1992 if (err < 0)
1993 mgmt_pending_remove(cmd);
1994 else
1995 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1996 goto unlock;
1997 }
1998
1999 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2000 if (!e) {
2001 mgmt_pending_remove(cmd);
2002 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2003 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2004 goto unlock;
2005 }
2006
2007 bacpy(&cp.bdaddr, &e->data.bdaddr);
2008 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2009 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002010 if (err < 0)
2011 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002012 else
2013 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002014
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002015unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002016 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002017 hci_dev_put(hdev);
2018
2019 return err;
2020}
2021
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002022static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002023{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002024 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002025 struct inquiry_entry *e;
2026 struct hci_dev *hdev;
2027 int err;
2028
2029 BT_DBG("hci%u", index);
2030
2031 if (len != sizeof(*cp))
2032 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2033 MGMT_STATUS_INVALID_PARAMS);
2034
2035 hdev = hci_dev_get(index);
2036 if (!hdev)
2037 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2038 MGMT_STATUS_INVALID_PARAMS);
2039
2040 hci_dev_lock(hdev);
2041
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002042 if (!hci_discovery_active(hdev)) {
2043 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2044 MGMT_STATUS_FAILED);
2045 goto failed;
2046 }
2047
Johan Hedberg561aafb2012-01-04 13:31:59 +02002048 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr);
2049 if (!e) {
2050 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2051 MGMT_STATUS_INVALID_PARAMS);
2052 goto failed;
2053 }
2054
2055 if (cp->name_known) {
2056 e->name_state = NAME_KNOWN;
2057 list_del(&e->list);
2058 } else {
2059 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002060 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002061 }
2062
2063 err = 0;
2064
2065failed:
2066 hci_dev_unlock(hdev);
2067
2068 return err;
2069}
2070
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002071static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002072{
2073 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002074 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002075 int err;
2076
2077 BT_DBG("hci%u", index);
2078
Antti Julku7fbec222011-06-15 12:01:15 +03002079 if (len != sizeof(*cp))
2080 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002081 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002082
2083 hdev = hci_dev_get(index);
2084 if (!hdev)
2085 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002086 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002087
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002088 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002089
Antti Julku7fbec222011-06-15 12:01:15 +03002090 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03002091 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002092 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2093 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002094 else
2095 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2096 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002097
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002098 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002099 hci_dev_put(hdev);
2100
2101 return err;
2102}
2103
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002104static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002105{
2106 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002107 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002108 int err;
2109
2110 BT_DBG("hci%u", index);
2111
Antti Julku7fbec222011-06-15 12:01:15 +03002112 if (len != sizeof(*cp))
2113 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002114 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002115
2116 hdev = hci_dev_get(index);
2117 if (!hdev)
2118 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002119 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002120
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002121 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002122
Antti Julku7fbec222011-06-15 12:01:15 +03002123 err = hci_blacklist_del(hdev, &cp->bdaddr);
2124
2125 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002126 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2127 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002128 else
2129 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2130 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002131
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002132 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002133 hci_dev_put(hdev);
2134
2135 return err;
2136}
2137
Antti Julkuf6422ec2011-06-22 13:11:56 +03002138static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002139 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002140{
2141 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002142 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002143 struct hci_cp_write_page_scan_activity acp;
2144 u8 type;
2145 int err;
2146
2147 BT_DBG("hci%u", index);
2148
2149 if (len != sizeof(*cp))
2150 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002151 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002152
2153 hdev = hci_dev_get(index);
2154 if (!hdev)
2155 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002156 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002157
2158 hci_dev_lock(hdev);
2159
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002160 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002161 type = PAGE_SCAN_TYPE_INTERLACED;
2162 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2163 } else {
2164 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2165 acp.interval = 0x0800; /* default 1.28 sec page scan */
2166 }
2167
2168 acp.window = 0x0012; /* default 11.25 msec page scan window */
2169
2170 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2171 sizeof(acp), &acp);
2172 if (err < 0) {
2173 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002174 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002175 goto done;
2176 }
2177
2178 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2179 if (err < 0) {
2180 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002181 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002182 goto done;
2183 }
2184
2185 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2186 NULL, 0);
2187done:
2188 hci_dev_unlock(hdev);
2189 hci_dev_put(hdev);
2190
2191 return err;
2192}
2193
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002194static int load_long_term_keys(struct sock *sk, u16 index,
2195 void *cp_data, u16 len)
2196{
2197 struct hci_dev *hdev;
2198 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2199 u16 key_count, expected_len;
2200 int i;
2201
2202 if (len < sizeof(*cp))
2203 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2204 EINVAL);
2205
2206 key_count = get_unaligned_le16(&cp->key_count);
2207
2208 expected_len = sizeof(*cp) + key_count *
2209 sizeof(struct mgmt_ltk_info);
2210 if (expected_len != len) {
2211 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2212 len, expected_len);
2213 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2214 EINVAL);
2215 }
2216
2217 hdev = hci_dev_get(index);
2218 if (!hdev)
2219 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2220 ENODEV);
2221
2222 BT_DBG("hci%u key_count %u", index, key_count);
2223
2224 hci_dev_lock(hdev);
2225
2226 hci_smp_ltks_clear(hdev);
2227
2228 for (i = 0; i < key_count; i++) {
2229 struct mgmt_ltk_info *key = &cp->keys[i];
2230 u8 type;
2231
2232 if (key->master)
2233 type = HCI_SMP_LTK;
2234 else
2235 type = HCI_SMP_LTK_SLAVE;
2236
2237 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2238 type, 0, key->authenticated, key->val,
2239 key->enc_size, key->ediv, key->rand);
2240 }
2241
2242 hci_dev_unlock(hdev);
2243 hci_dev_put(hdev);
2244
2245 return 0;
2246}
2247
Johan Hedberg03811012010-12-08 00:21:06 +02002248int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2249{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002250 void *buf;
2251 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002252 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002253 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002254 int err;
2255
2256 BT_DBG("got %zu bytes", msglen);
2257
2258 if (msglen < sizeof(*hdr))
2259 return -EINVAL;
2260
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002261 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002262 if (!buf)
2263 return -ENOMEM;
2264
2265 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2266 err = -EFAULT;
2267 goto done;
2268 }
2269
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002270 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002271 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002272 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002273 len = get_unaligned_le16(&hdr->len);
2274
2275 if (len != msglen - sizeof(*hdr)) {
2276 err = -EINVAL;
2277 goto done;
2278 }
2279
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002280 cp = buf + sizeof(*hdr);
2281
Johan Hedberg03811012010-12-08 00:21:06 +02002282 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002283 case MGMT_OP_READ_VERSION:
2284 err = read_version(sk);
2285 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002286 case MGMT_OP_READ_INDEX_LIST:
2287 err = read_index_list(sk);
2288 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002289 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002290 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002291 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002292 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002293 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002294 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002295 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002296 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002297 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002298 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002299 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002300 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002301 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002302 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002303 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002304 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002305 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002306 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002307 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002308 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002309 break;
2310 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002311 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002312 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002313 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002314 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002315 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002316 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002317 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002318 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002319 case MGMT_OP_REMOVE_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002320 err = remove_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002321 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002322 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002323 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002324 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002325 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002326 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002327 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002328 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002329 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002330 break;
2331 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002332 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002333 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002334 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002335 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002336 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002337 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002338 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002339 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002340 case MGMT_OP_CANCEL_PAIR_DEVICE:
2341 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2342 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002343 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002344 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002345 break;
2346 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002347 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002348 break;
Brian Gix604086b2011-11-23 08:28:33 -08002349 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002350 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002351 break;
2352 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002353 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002354 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002355 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002356 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002357 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002358 case MGMT_OP_READ_LOCAL_OOB_DATA:
2359 err = read_local_oob_data(sk, index);
2360 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002361 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002362 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002363 break;
2364 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002365 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002366 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002367 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002368 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002369 break;
2370 case MGMT_OP_STOP_DISCOVERY:
2371 err = stop_discovery(sk, index);
2372 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002373 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002374 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002375 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002376 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002377 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002378 break;
2379 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002380 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002381 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002382 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2383 err = load_long_term_keys(sk, index, cp, len);
2384 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002385 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002386 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002387 err = cmd_status(sk, index, opcode,
2388 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002389 break;
2390 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002391
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002392 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002393 goto done;
2394
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002395 err = msglen;
2396
2397done:
2398 kfree(buf);
2399 return err;
2400}
2401
Johan Hedbergb24752f2011-11-03 14:40:33 +02002402static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2403{
2404 u8 *status = data;
2405
2406 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2407 mgmt_pending_remove(cmd);
2408}
2409
Johan Hedberg744cf192011-11-08 20:40:14 +02002410int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002411{
Johan Hedberg744cf192011-11-08 20:40:14 +02002412 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002413}
2414
Johan Hedberg744cf192011-11-08 20:40:14 +02002415int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002416{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002417 u8 status = ENODEV;
2418
Johan Hedberg744cf192011-11-08 20:40:14 +02002419 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002420
Johan Hedberg744cf192011-11-08 20:40:14 +02002421 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002422}
2423
2424struct cmd_lookup {
2425 u8 val;
2426 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002427 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002428};
2429
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002430static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002431{
Johan Hedberg03811012010-12-08 00:21:06 +02002432 struct cmd_lookup *match = data;
2433
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002434 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002435
2436 list_del(&cmd->list);
2437
2438 if (match->sk == NULL) {
2439 match->sk = cmd->sk;
2440 sock_hold(match->sk);
2441 }
2442
2443 mgmt_pending_free(cmd);
2444}
2445
Johan Hedberg744cf192011-11-08 20:40:14 +02002446int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002447{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002448 struct cmd_lookup match = { powered, NULL, hdev };
2449 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002450 int ret;
2451
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002452 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002453
Johan Hedbergb24752f2011-11-03 14:40:33 +02002454 if (!powered) {
2455 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002456 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002457 }
2458
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002459 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002460
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002461 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2462 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002463
2464 if (match.sk)
2465 sock_put(match.sk);
2466
2467 return ret;
2468}
2469
Johan Hedberg744cf192011-11-08 20:40:14 +02002470int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002471{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002472 struct cmd_lookup match = { discoverable, NULL, hdev };
2473 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002474 int ret;
2475
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002476 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002477
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002478 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002479
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002480 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002481 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002482 if (match.sk)
2483 sock_put(match.sk);
2484
2485 return ret;
2486}
2487
Johan Hedberg744cf192011-11-08 20:40:14 +02002488int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002489{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002490 __le32 ev;
2491 struct cmd_lookup match = { connectable, NULL, hdev };
Johan Hedberg03811012010-12-08 00:21:06 +02002492 int ret;
2493
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002494 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2495 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002496
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002497 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002498
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002499 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002500
2501 if (match.sk)
2502 sock_put(match.sk);
2503
2504 return ret;
2505}
2506
Johan Hedberg744cf192011-11-08 20:40:14 +02002507int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002508{
Johan Hedbergca69b792011-11-11 18:10:00 +02002509 u8 mgmt_err = mgmt_status(status);
2510
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002511 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002512 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002513 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002514
2515 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002516 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002517 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002518
2519 return 0;
2520}
2521
Johan Hedberg744cf192011-11-08 20:40:14 +02002522int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2523 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002524{
Johan Hedberg86742e12011-11-07 23:13:38 +02002525 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002526
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002527 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002528
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002529 ev.store_hint = persistent;
2530 bacpy(&ev.key.bdaddr, &key->bdaddr);
2531 ev.key.type = key->type;
2532 memcpy(ev.key.val, key->val, 16);
2533 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002534
Johan Hedberg744cf192011-11-08 20:40:14 +02002535 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002536}
Johan Hedbergf7520542011-01-20 12:34:39 +02002537
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002538int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2539{
2540 struct mgmt_ev_new_long_term_key ev;
2541
2542 memset(&ev, 0, sizeof(ev));
2543
2544 ev.store_hint = persistent;
2545 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2546 ev.key.addr.type = key->bdaddr_type;
2547 ev.key.authenticated = key->authenticated;
2548 ev.key.enc_size = key->enc_size;
2549 ev.key.ediv = key->ediv;
2550
2551 if (key->type == HCI_SMP_LTK)
2552 ev.key.master = 1;
2553
2554 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2555 memcpy(ev.key.val, key->val, sizeof(key->val));
2556
2557 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2558 &ev, sizeof(ev), NULL);
2559}
2560
Johan Hedbergafc747a2012-01-15 18:11:07 +02002561int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002562 u8 addr_type, u8 *name, u8 name_len,
2563 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002564{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002565 char buf[512];
2566 struct mgmt_ev_device_connected *ev = (void *) buf;
2567 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002568
Johan Hedbergb644ba32012-01-17 21:48:47 +02002569 bacpy(&ev->addr.bdaddr, bdaddr);
2570 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002571
Johan Hedbergb644ba32012-01-17 21:48:47 +02002572 if (name_len > 0)
2573 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2574 name, name_len);
2575
2576 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2577 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2578 EIR_CLASS_OF_DEV, dev_class, 3);
2579
2580 put_unaligned_le16(eir_len, &ev->eir_len);
2581
2582 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2583 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002584}
2585
Johan Hedberg8962ee72011-01-20 12:40:27 +02002586static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2587{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002588 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002589 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002590 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002591
Johan Hedberga38528f2011-01-22 06:46:43 +02002592 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002593 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002594
Szymon Janc4e51eae2011-02-25 19:05:48 +01002595 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002596
2597 *sk = cmd->sk;
2598 sock_hold(*sk);
2599
Johan Hedberga664b5b2011-02-19 12:06:02 -03002600 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002601}
2602
Johan Hedberga8a1d192011-11-10 15:54:38 +02002603static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2604{
2605 u8 *status = data;
2606 struct mgmt_cp_remove_keys *cp = cmd->param;
2607 struct mgmt_rp_remove_keys rp;
2608
2609 memset(&rp, 0, sizeof(rp));
2610 bacpy(&rp.bdaddr, &cp->bdaddr);
2611 if (status != NULL)
2612 rp.status = *status;
2613
2614 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2615 sizeof(rp));
2616
2617 mgmt_pending_remove(cmd);
2618}
2619
Johan Hedbergafc747a2012-01-15 18:11:07 +02002620int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2621 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002622{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002623 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002624 struct sock *sk = NULL;
2625 int err;
2626
Johan Hedberg744cf192011-11-08 20:40:14 +02002627 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002628
Johan Hedbergf7520542011-01-20 12:34:39 +02002629 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002630 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002631
Johan Hedbergafc747a2012-01-15 18:11:07 +02002632 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2633 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002634
2635 if (sk)
2636 sock_put(sk);
2637
Johan Hedberga8a1d192011-11-10 15:54:38 +02002638 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2639
Johan Hedberg8962ee72011-01-20 12:40:27 +02002640 return err;
2641}
2642
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002643int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002644{
2645 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002646 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002647 int err;
2648
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002649 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002650 if (!cmd)
2651 return -ENOENT;
2652
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002653 if (bdaddr) {
2654 struct mgmt_rp_disconnect rp;
2655
2656 bacpy(&rp.bdaddr, bdaddr);
2657 rp.status = status;
2658
2659 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2660 &rp, sizeof(rp));
2661 } else
2662 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002663 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002664
Johan Hedberga664b5b2011-02-19 12:06:02 -03002665 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002666
2667 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002668}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002669
Johan Hedberg48264f02011-11-09 13:58:58 +02002670int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2671 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002672{
2673 struct mgmt_ev_connect_failed ev;
2674
Johan Hedberg4c659c32011-11-07 23:13:39 +02002675 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002676 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002677 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002678
Johan Hedberg744cf192011-11-08 20:40:14 +02002679 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002680}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002681
Johan Hedberg744cf192011-11-08 20:40:14 +02002682int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002683{
2684 struct mgmt_ev_pin_code_request ev;
2685
Johan Hedberg980e1a52011-01-22 06:10:07 +02002686 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002687 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002688
Johan Hedberg744cf192011-11-08 20:40:14 +02002689 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002690 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002691}
2692
Johan Hedberg744cf192011-11-08 20:40:14 +02002693int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2694 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002695{
2696 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002697 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002698 int err;
2699
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002700 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002701 if (!cmd)
2702 return -ENOENT;
2703
Johan Hedbergac56fb12011-02-19 12:05:59 -03002704 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002705 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002706
Johan Hedberg744cf192011-11-08 20:40:14 +02002707 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002708 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002709
Johan Hedberga664b5b2011-02-19 12:06:02 -03002710 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002711
2712 return err;
2713}
2714
Johan Hedberg744cf192011-11-08 20:40:14 +02002715int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2716 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002717{
2718 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002719 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002720 int err;
2721
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002722 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002723 if (!cmd)
2724 return -ENOENT;
2725
Johan Hedbergac56fb12011-02-19 12:05:59 -03002726 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002727 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002728
Johan Hedberg744cf192011-11-08 20:40:14 +02002729 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002730 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002731
Johan Hedberga664b5b2011-02-19 12:06:02 -03002732 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002733
2734 return err;
2735}
Johan Hedberga5c29682011-02-19 12:05:57 -03002736
Johan Hedberg744cf192011-11-08 20:40:14 +02002737int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2738 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002739{
2740 struct mgmt_ev_user_confirm_request ev;
2741
Johan Hedberg744cf192011-11-08 20:40:14 +02002742 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002743
Johan Hedberga5c29682011-02-19 12:05:57 -03002744 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002745 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002746 put_unaligned_le32(value, &ev.value);
2747
Johan Hedberg744cf192011-11-08 20:40:14 +02002748 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002749 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002750}
2751
Brian Gix604086b2011-11-23 08:28:33 -08002752int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2753{
2754 struct mgmt_ev_user_passkey_request ev;
2755
2756 BT_DBG("%s", hdev->name);
2757
2758 bacpy(&ev.bdaddr, bdaddr);
2759
2760 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2761 NULL);
2762}
2763
Brian Gix0df4c182011-11-16 13:53:13 -08002764static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002765 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002766{
2767 struct pending_cmd *cmd;
2768 struct mgmt_rp_user_confirm_reply rp;
2769 int err;
2770
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002771 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002772 if (!cmd)
2773 return -ENOENT;
2774
Johan Hedberga5c29682011-02-19 12:05:57 -03002775 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002776 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002777 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002778
Johan Hedberga664b5b2011-02-19 12:06:02 -03002779 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002780
2781 return err;
2782}
2783
Johan Hedberg744cf192011-11-08 20:40:14 +02002784int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2785 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002786{
Brian Gix0df4c182011-11-16 13:53:13 -08002787 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002788 MGMT_OP_USER_CONFIRM_REPLY);
2789}
2790
Johan Hedberg744cf192011-11-08 20:40:14 +02002791int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2792 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002793{
Brian Gix0df4c182011-11-16 13:53:13 -08002794 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002795 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2796}
Johan Hedberg2a611692011-02-19 12:06:00 -03002797
Brian Gix604086b2011-11-23 08:28:33 -08002798int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2799 u8 status)
2800{
2801 return user_pairing_resp_complete(hdev, bdaddr, status,
2802 MGMT_OP_USER_PASSKEY_REPLY);
2803}
2804
2805int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2806 bdaddr_t *bdaddr, u8 status)
2807{
2808 return user_pairing_resp_complete(hdev, bdaddr, status,
2809 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2810}
2811
Johan Hedberg744cf192011-11-08 20:40:14 +02002812int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002813{
2814 struct mgmt_ev_auth_failed ev;
2815
Johan Hedberg2a611692011-02-19 12:06:00 -03002816 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002817 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002818
Johan Hedberg744cf192011-11-08 20:40:14 +02002819 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002820}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002821
Johan Hedberg744cf192011-11-08 20:40:14 +02002822int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002823{
2824 struct pending_cmd *cmd;
2825 struct mgmt_cp_set_local_name ev;
2826 int err;
2827
2828 memset(&ev, 0, sizeof(ev));
2829 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2830
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002831 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002832 if (!cmd)
2833 goto send_event;
2834
2835 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002836 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002837 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002838 goto failed;
2839 }
2840
Johan Hedberg744cf192011-11-08 20:40:14 +02002841 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002842
Johan Hedberg744cf192011-11-08 20:40:14 +02002843 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002844 sizeof(ev));
2845 if (err < 0)
2846 goto failed;
2847
2848send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002849 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002850 cmd ? cmd->sk : NULL);
2851
2852failed:
2853 if (cmd)
2854 mgmt_pending_remove(cmd);
2855 return err;
2856}
Szymon Jancc35938b2011-03-22 13:12:21 +01002857
Johan Hedberg744cf192011-11-08 20:40:14 +02002858int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2859 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002860{
2861 struct pending_cmd *cmd;
2862 int err;
2863
Johan Hedberg744cf192011-11-08 20:40:14 +02002864 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002865
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002866 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002867 if (!cmd)
2868 return -ENOENT;
2869
2870 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002871 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002872 MGMT_OP_READ_LOCAL_OOB_DATA,
2873 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002874 } else {
2875 struct mgmt_rp_read_local_oob_data rp;
2876
2877 memcpy(rp.hash, hash, sizeof(rp.hash));
2878 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2879
Johan Hedberg744cf192011-11-08 20:40:14 +02002880 err = cmd_complete(cmd->sk, hdev->id,
2881 MGMT_OP_READ_LOCAL_OOB_DATA,
2882 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002883 }
2884
2885 mgmt_pending_remove(cmd);
2886
2887 return err;
2888}
Johan Hedberge17acd42011-03-30 23:57:16 +03002889
Johan Hedberg48264f02011-11-09 13:58:58 +02002890int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002891 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02002892 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03002893{
Johan Hedberge319d2e2012-01-15 19:51:59 +02002894 char buf[512];
2895 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02002896 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03002897
Johan Hedberg1dc06092012-01-15 21:01:23 +02002898 /* Leave 5 bytes for a potential CoD field */
2899 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03002900 return -EINVAL;
2901
Johan Hedberg1dc06092012-01-15 21:01:23 +02002902 memset(buf, 0, sizeof(buf));
2903
Johan Hedberge319d2e2012-01-15 19:51:59 +02002904 bacpy(&ev->addr.bdaddr, bdaddr);
2905 ev->addr.type = link_to_mgmt(link_type, addr_type);
2906 ev->rssi = rssi;
2907 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03002908
Johan Hedberg1dc06092012-01-15 21:01:23 +02002909 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02002910 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03002911
Johan Hedberg1dc06092012-01-15 21:01:23 +02002912 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
2913 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
2914 dev_class, 3);
2915
2916 put_unaligned_le16(eir_len, &ev->eir_len);
2917
2918 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03002919
Johan Hedberge319d2e2012-01-15 19:51:59 +02002920 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002921}
Johan Hedberga88a9652011-03-30 13:18:12 +03002922
Johan Hedbergb644ba32012-01-17 21:48:47 +02002923int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2924 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03002925{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002926 struct mgmt_ev_device_found *ev;
2927 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
2928 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03002929
Johan Hedbergb644ba32012-01-17 21:48:47 +02002930 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03002931
Johan Hedbergb644ba32012-01-17 21:48:47 +02002932 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03002933
Johan Hedbergb644ba32012-01-17 21:48:47 +02002934 bacpy(&ev->addr.bdaddr, bdaddr);
2935 ev->addr.type = link_to_mgmt(link_type, addr_type);
2936 ev->rssi = rssi;
2937
2938 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
2939 name_len);
2940
2941 put_unaligned_le16(eir_len, &ev->eir_len);
2942
2943 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002944}
Johan Hedberg314b2382011-04-27 10:29:57 -04002945
Andre Guedes7a135102011-11-09 17:14:25 -03002946int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002947{
2948 struct pending_cmd *cmd;
2949 int err;
2950
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002951 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002952 if (!cmd)
2953 return -ENOENT;
2954
Johan Hedbergca69b792011-11-11 18:10:00 +02002955 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002956 mgmt_pending_remove(cmd);
2957
2958 return err;
2959}
2960
Andre Guedese6d465c2011-11-09 17:14:26 -03002961int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2962{
2963 struct pending_cmd *cmd;
2964 int err;
2965
2966 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2967 if (!cmd)
2968 return -ENOENT;
2969
Andre Guedese75a8b0c2012-01-02 16:50:53 -03002970 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02002971 mgmt_pending_remove(cmd);
2972
2973 return err;
2974}
Johan Hedberg314b2382011-04-27 10:29:57 -04002975
Johan Hedberg744cf192011-11-08 20:40:14 +02002976int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002977{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002978 struct pending_cmd *cmd;
2979
2980 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002981 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002982 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002983 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002984
2985 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002986 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002987 mgmt_pending_remove(cmd);
2988 }
2989
Johan Hedberg744cf192011-11-08 20:40:14 +02002990 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002991 sizeof(discovering), NULL);
2992}
Antti Julku5e762442011-08-25 16:48:02 +03002993
Johan Hedberg744cf192011-11-08 20:40:14 +02002994int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002995{
2996 struct pending_cmd *cmd;
2997 struct mgmt_ev_device_blocked ev;
2998
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002999 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003000
3001 bacpy(&ev.bdaddr, bdaddr);
3002
Johan Hedberg744cf192011-11-08 20:40:14 +02003003 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3004 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003005}
3006
Johan Hedberg744cf192011-11-08 20:40:14 +02003007int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03003008{
3009 struct pending_cmd *cmd;
3010 struct mgmt_ev_device_unblocked ev;
3011
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003012 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003013
3014 bacpy(&ev.bdaddr, bdaddr);
3015
Johan Hedberg744cf192011-11-08 20:40:14 +02003016 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3017 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003018}