blob: 2dae2e8f6234c410cfca60701c287f2bb1d9c544 [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 Hedberg69ab39e2011-12-15 00:47:35 +0200300 if (hdev->ssp_mode > 0)
301 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
419 if (hdev->ssp_mode == 0)
420 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
Johan Hedberg03811012010-12-08 00:21:06 +0200614static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
615{
616 struct mgmt_mode *cp;
617 struct hci_dev *hdev;
618 struct pending_cmd *cmd;
619 int err, up;
620
621 cp = (void *) data;
622
623 BT_DBG("request for hci%u", index);
624
625 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200626 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
627 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200628
629 hdev = hci_dev_get(index);
630 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200631 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
632 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300634 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200635
636 up = test_bit(HCI_UP, &hdev->flags);
637 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200638 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200639 goto failed;
640 }
641
642 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200643 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
644 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200645 goto failed;
646 }
647
648 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
649 if (!cmd) {
650 err = -ENOMEM;
651 goto failed;
652 }
653
654 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200655 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200656 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200657 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200658
659 err = 0;
660
661failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300662 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200663 hci_dev_put(hdev);
664 return err;
665}
666
667static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
668 u16 len)
669{
670 struct mgmt_cp_set_discoverable *cp;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200671 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200672 struct pending_cmd *cmd;
673 u8 scan;
674 int err;
675
676 cp = (void *) data;
677
678 BT_DBG("request for hci%u", index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200679
680 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200681 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
682 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200683
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200684 hdev = hci_dev_get(index);
685 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200686 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
687 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200688
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300689 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200690
691 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200692 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
693 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200694 goto failed;
695 }
696
697 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
698 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200699 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
700 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200701 goto failed;
702 }
703
704 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
705 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200706 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200707 goto failed;
708 }
709
710 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
711 if (!cmd) {
712 err = -ENOMEM;
713 goto failed;
714 }
715
716 scan = SCAN_PAGE;
717
718 if (cp->val)
719 scan |= SCAN_INQUIRY;
720 else
721 cancel_delayed_work(&hdev->discov_off);
722
723 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
724 if (err < 0)
725 mgmt_pending_remove(cmd);
726
Johan Hedberg03811012010-12-08 00:21:06 +0200727 if (cp->val)
728 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
729
Johan Hedberge41d8b42010-12-13 21:07:03 +0200730failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300731 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200732 hci_dev_put(hdev);
733
734 return err;
735}
736
737static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
738 u16 len)
739{
740 struct mgmt_mode *cp;
741 struct hci_dev *hdev;
742 struct pending_cmd *cmd;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200743 u8 scan;
744 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200745
746 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200747
748 BT_DBG("request for hci%u", index);
749
750 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200751 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
752 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200753
754 hdev = hci_dev_get(index);
755 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200756 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
757 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200758
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300759 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200760
761 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200762 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
763 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200764 goto failed;
765 }
766
767 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
768 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200769 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
770 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200771 goto failed;
772 }
773
774 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200775 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200776 goto failed;
777 }
778
779 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
780 if (!cmd) {
781 err = -ENOMEM;
782 goto failed;
783 }
784
785 if (cp->val)
786 scan = SCAN_PAGE;
787 else
788 scan = 0;
789
790 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
791 if (err < 0)
792 mgmt_pending_remove(cmd);
793
794failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300795 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200796 hci_dev_put(hdev);
797
798 return err;
799}
800
801static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
802 u16 data_len, struct sock *skip_sk)
803{
804 struct sk_buff *skb;
805 struct mgmt_hdr *hdr;
806
807 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
808 if (!skb)
809 return -ENOMEM;
810
811 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
812
813 hdr = (void *) skb_put(skb, sizeof(*hdr));
814 hdr->opcode = cpu_to_le16(event);
815 if (hdev)
816 hdr->index = cpu_to_le16(hdev->id);
817 else
818 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
819 hdr->len = cpu_to_le16(data_len);
820
821 if (data)
822 memcpy(skb_put(skb, data_len), data, data_len);
823
824 hci_send_to_sock(NULL, skb, skip_sk);
825 kfree_skb(skb);
826
827 return 0;
828}
829
Johan Hedberg73f22f62010-12-29 16:00:25 +0200830static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
831 u16 len)
832{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200833 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200834 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200835 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200836 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200837
838 cp = (void *) data;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200839
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200840 BT_DBG("request for hci%u", index);
841
842 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200843 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
844 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200845
846 hdev = hci_dev_get(index);
847 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200848 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
849 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200850
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300851 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200852
853 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200854 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200855 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200856 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200857
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200858 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200859 if (err < 0)
860 goto failed;
861
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200862 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200863
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200864 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200865
866failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300867 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200868 hci_dev_put(hdev);
869
870 return err;
871}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200872
Szymon Janc4e51eae2011-02-25 19:05:48 +0100873static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200874{
875 struct mgmt_cp_add_uuid *cp;
876 struct hci_dev *hdev;
877 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200878 int err;
879
880 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200881
Szymon Janc4e51eae2011-02-25 19:05:48 +0100882 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200883
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100884 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200885 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
886 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100887
Szymon Janc4e51eae2011-02-25 19:05:48 +0100888 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200889 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200890 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
891 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200892
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300893 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200894
895 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
896 if (!uuid) {
897 err = -ENOMEM;
898 goto failed;
899 }
900
901 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200902 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200903
904 list_add(&uuid->list, &hdev->uuids);
905
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200906 err = update_class(hdev);
907 if (err < 0)
908 goto failed;
909
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300910 err = update_eir(hdev);
911 if (err < 0)
912 goto failed;
913
Szymon Janc4e51eae2011-02-25 19:05:48 +0100914 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200915
916failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300917 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200918 hci_dev_put(hdev);
919
920 return err;
921}
922
Szymon Janc4e51eae2011-02-25 19:05:48 +0100923static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200924{
925 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100926 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200927 struct hci_dev *hdev;
928 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 +0200929 int err, found;
930
931 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200932
Szymon Janc4e51eae2011-02-25 19:05:48 +0100933 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200934
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100935 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200936 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
937 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100938
Szymon Janc4e51eae2011-02-25 19:05:48 +0100939 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200940 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200941 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
942 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200943
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300944 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200945
946 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
947 err = hci_uuids_clear(hdev);
948 goto unlock;
949 }
950
951 found = 0;
952
953 list_for_each_safe(p, n, &hdev->uuids) {
954 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
955
956 if (memcmp(match->uuid, cp->uuid, 16) != 0)
957 continue;
958
959 list_del(&match->list);
960 found++;
961 }
962
963 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200964 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
965 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200966 goto unlock;
967 }
968
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200969 err = update_class(hdev);
970 if (err < 0)
971 goto unlock;
972
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300973 err = update_eir(hdev);
974 if (err < 0)
975 goto unlock;
976
Szymon Janc4e51eae2011-02-25 19:05:48 +0100977 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200978
979unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300980 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200981 hci_dev_put(hdev);
982
983 return err;
984}
985
Szymon Janc4e51eae2011-02-25 19:05:48 +0100986static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
987 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200988{
989 struct hci_dev *hdev;
990 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200991 int err;
992
993 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200994
Szymon Janc4e51eae2011-02-25 19:05:48 +0100995 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200996
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100997 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200998 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
999 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001000
Szymon Janc4e51eae2011-02-25 19:05:48 +01001001 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001002 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001003 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1004 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001005
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001006 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001007
1008 hdev->major_class = cp->major;
1009 hdev->minor_class = cp->minor;
1010
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001011 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001012 hci_dev_unlock(hdev);
1013 cancel_delayed_work_sync(&hdev->service_cache);
1014 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001015 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001016 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001017
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001018 err = update_class(hdev);
1019
1020 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001021 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001022
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001023 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001024 hci_dev_put(hdev);
1025
1026 return err;
1027}
1028
Johan Hedberg86742e12011-11-07 23:13:38 +02001029static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
1030 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001031{
1032 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001033 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001034 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001035 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001036
1037 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001038
1039 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001040 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1041 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001042
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001043 key_count = get_unaligned_le16(&cp->key_count);
1044
Johan Hedberg86742e12011-11-07 23:13:38 +02001045 expected_len = sizeof(*cp) + key_count *
1046 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001047 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001048 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001049 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001050 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1051 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001052 }
1053
Szymon Janc4e51eae2011-02-25 19:05:48 +01001054 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001055 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001056 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1057 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001058
Szymon Janc4e51eae2011-02-25 19:05:48 +01001059 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001060 key_count);
1061
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001062 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001063
1064 hci_link_keys_clear(hdev);
1065
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001066 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001067
1068 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001069 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001070 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001071 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001072
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001073 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001074 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001075
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001076 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001077 key->pin_len);
1078 }
1079
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001080 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1081
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001082 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001083 hci_dev_put(hdev);
1084
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001085 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001086}
1087
Johan Hedberg86742e12011-11-07 23:13:38 +02001088static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
1089 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001090{
1091 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001092 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001093 struct mgmt_rp_remove_keys rp;
1094 struct hci_cp_disconnect dc;
1095 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001096 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001097 int err;
1098
1099 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001100
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001101 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001102 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1103 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001104
Szymon Janc4e51eae2011-02-25 19:05:48 +01001105 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001106 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001107 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1108 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001109
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001110 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001111
Johan Hedberga8a1d192011-11-10 15:54:38 +02001112 memset(&rp, 0, sizeof(rp));
1113 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001114 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001115
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001116 err = hci_remove_link_key(hdev, &cp->bdaddr);
1117 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001118 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001119 goto unlock;
1120 }
1121
Johan Hedberga8a1d192011-11-10 15:54:38 +02001122 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1123 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1124 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001125 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001126 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001127
1128 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001129 if (!conn) {
1130 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1131 sizeof(rp));
1132 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001133 }
1134
Johan Hedberga8a1d192011-11-10 15:54:38 +02001135 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1136 if (!cmd) {
1137 err = -ENOMEM;
1138 goto unlock;
1139 }
1140
1141 put_unaligned_le16(conn->handle, &dc.handle);
1142 dc.reason = 0x13; /* Remote User Terminated Connection */
1143 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1144 if (err < 0)
1145 mgmt_pending_remove(cmd);
1146
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001147unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001148 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001149 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1150 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001151 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001152 hci_dev_put(hdev);
1153
1154 return err;
1155}
1156
Szymon Janc4e51eae2011-02-25 19:05:48 +01001157static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001158{
1159 struct hci_dev *hdev;
1160 struct mgmt_cp_disconnect *cp;
1161 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001162 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001163 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001164 int err;
1165
1166 BT_DBG("");
1167
1168 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001169
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001170 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001171 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1172 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001173
Szymon Janc4e51eae2011-02-25 19:05:48 +01001174 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001175 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001176 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1177 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001178
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001179 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001180
1181 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001182 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1183 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001184 goto failed;
1185 }
1186
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001187 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001188 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1189 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001190 goto failed;
1191 }
1192
1193 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001194 if (!conn)
1195 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1196
Johan Hedberg8962ee72011-01-20 12:40:27 +02001197 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001198 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1199 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001200 goto failed;
1201 }
1202
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001203 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001204 if (!cmd) {
1205 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001206 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001207 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001208
1209 put_unaligned_le16(conn->handle, &dc.handle);
1210 dc.reason = 0x13; /* Remote User Terminated Connection */
1211
1212 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1213 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001214 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001215
1216failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001217 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001218 hci_dev_put(hdev);
1219
1220 return err;
1221}
1222
Johan Hedberg48264f02011-11-09 13:58:58 +02001223static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001224{
1225 switch (link_type) {
1226 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001227 switch (addr_type) {
1228 case ADDR_LE_DEV_PUBLIC:
1229 return MGMT_ADDR_LE_PUBLIC;
1230 case ADDR_LE_DEV_RANDOM:
1231 return MGMT_ADDR_LE_RANDOM;
1232 default:
1233 return MGMT_ADDR_INVALID;
1234 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001235 case ACL_LINK:
1236 return MGMT_ADDR_BREDR;
1237 default:
1238 return MGMT_ADDR_INVALID;
1239 }
1240}
1241
Szymon Janc8ce62842011-03-01 16:55:32 +01001242static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001243{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001244 struct mgmt_rp_get_connections *rp;
1245 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001246 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001247 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001248 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001249 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001250 int i, err;
1251
1252 BT_DBG("");
1253
Szymon Janc4e51eae2011-02-25 19:05:48 +01001254 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001255 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001256 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1257 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001258
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001259 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001260
1261 count = 0;
1262 list_for_each(p, &hdev->conn_hash.list) {
1263 count++;
1264 }
1265
Johan Hedberg4c659c32011-11-07 23:13:39 +02001266 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001267 rp = kmalloc(rp_len, GFP_ATOMIC);
1268 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001269 err = -ENOMEM;
1270 goto unlock;
1271 }
1272
Johan Hedberg2784eb42011-01-21 13:56:35 +02001273 put_unaligned_le16(count, &rp->conn_count);
1274
Johan Hedberg2784eb42011-01-21 13:56:35 +02001275 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001276 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1277 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001278 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001279 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1280 continue;
1281 i++;
1282 }
1283
1284 /* Recalculate length in case of filtered SCO connections, etc */
1285 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001286
Szymon Janc4e51eae2011-02-25 19:05:48 +01001287 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001288
1289unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001290 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001291 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001292 hci_dev_put(hdev);
1293 return err;
1294}
1295
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001296static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1297 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1298{
1299 struct pending_cmd *cmd;
1300 int err;
1301
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001302 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001303 sizeof(*cp));
1304 if (!cmd)
1305 return -ENOMEM;
1306
1307 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1308 &cp->bdaddr);
1309 if (err < 0)
1310 mgmt_pending_remove(cmd);
1311
1312 return err;
1313}
1314
Szymon Janc4e51eae2011-02-25 19:05:48 +01001315static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1316 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001317{
1318 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001319 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001320 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001321 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001322 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001323 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001324 int err;
1325
1326 BT_DBG("");
1327
1328 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001329
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001330 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001331 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1332 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001333
Szymon Janc4e51eae2011-02-25 19:05:48 +01001334 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001335 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001336 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1337 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001338
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001339 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001340
1341 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001342 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1343 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001344 goto failed;
1345 }
1346
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001347 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1348 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001349 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1350 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001351 goto failed;
1352 }
1353
1354 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1355 bacpy(&ncp.bdaddr, &cp->bdaddr);
1356
1357 BT_ERR("PIN code is not 16 bytes long");
1358
1359 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1360 if (err >= 0)
1361 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001362 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001363
1364 goto failed;
1365 }
1366
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001367 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001368 if (!cmd) {
1369 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001370 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001371 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001372
1373 bacpy(&reply.bdaddr, &cp->bdaddr);
1374 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001375 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001376
1377 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1378 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001379 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001380
1381failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001382 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001383 hci_dev_put(hdev);
1384
1385 return err;
1386}
1387
Szymon Janc4e51eae2011-02-25 19:05:48 +01001388static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1389 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001390{
1391 struct hci_dev *hdev;
1392 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001393 int err;
1394
1395 BT_DBG("");
1396
1397 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001398
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001399 if (len != sizeof(*cp))
1400 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001401 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001402
Szymon Janc4e51eae2011-02-25 19:05:48 +01001403 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001404 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001405 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001406 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001407
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001408 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001409
1410 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001411 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001412 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001413 goto failed;
1414 }
1415
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001416 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001417
1418failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001419 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001420 hci_dev_put(hdev);
1421
1422 return err;
1423}
1424
Szymon Janc4e51eae2011-02-25 19:05:48 +01001425static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1426 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001427{
1428 struct hci_dev *hdev;
1429 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001430
1431 BT_DBG("");
1432
1433 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001434
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001435 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001436 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1437 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001438
Szymon Janc4e51eae2011-02-25 19:05:48 +01001439 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001440 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001441 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1442 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001443
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001444 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001445
1446 hdev->io_capability = cp->io_capability;
1447
1448 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001449 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001450
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001451 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001452 hci_dev_put(hdev);
1453
Szymon Janc4e51eae2011-02-25 19:05:48 +01001454 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001455}
1456
Johan Hedberge9a416b2011-02-19 12:05:56 -03001457static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1458{
1459 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001460 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001461
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001462 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001463 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1464 continue;
1465
Johan Hedberge9a416b2011-02-19 12:05:56 -03001466 if (cmd->user_data != conn)
1467 continue;
1468
1469 return cmd;
1470 }
1471
1472 return NULL;
1473}
1474
1475static void pairing_complete(struct pending_cmd *cmd, u8 status)
1476{
1477 struct mgmt_rp_pair_device rp;
1478 struct hci_conn *conn = cmd->user_data;
1479
Johan Hedbergba4e5642011-11-11 00:07:34 +02001480 bacpy(&rp.addr.bdaddr, &conn->dst);
1481 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001482 rp.status = status;
1483
Szymon Janc4e51eae2011-02-25 19:05:48 +01001484 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001485
1486 /* So we don't get further callbacks for this connection */
1487 conn->connect_cfm_cb = NULL;
1488 conn->security_cfm_cb = NULL;
1489 conn->disconn_cfm_cb = NULL;
1490
1491 hci_conn_put(conn);
1492
Johan Hedberga664b5b2011-02-19 12:06:02 -03001493 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001494}
1495
1496static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1497{
1498 struct pending_cmd *cmd;
1499
1500 BT_DBG("status %u", status);
1501
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001502 cmd = find_pairing(conn);
1503 if (!cmd)
1504 BT_DBG("Unable to find a pending command");
1505 else
1506 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001507}
1508
Szymon Janc4e51eae2011-02-25 19:05:48 +01001509static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001510{
1511 struct hci_dev *hdev;
1512 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001513 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001514 struct pending_cmd *cmd;
1515 u8 sec_level, auth_type;
1516 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001517 int err;
1518
1519 BT_DBG("");
1520
1521 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001522
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001523 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001524 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1525 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001526
Szymon Janc4e51eae2011-02-25 19:05:48 +01001527 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001528 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001529 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1530 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001531
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001532 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001533
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001534 sec_level = BT_SECURITY_MEDIUM;
1535 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001536 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001537 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001538 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001539
Johan Hedbergba4e5642011-11-11 00:07:34 +02001540 if (cp->addr.type == MGMT_ADDR_BREDR)
1541 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001542 auth_type);
1543 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001544 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001545 auth_type);
1546
Johan Hedberg1425acb2011-11-11 00:07:35 +02001547 memset(&rp, 0, sizeof(rp));
1548 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1549 rp.addr.type = cp->addr.type;
1550
Ville Tervo30e76272011-02-22 16:10:53 -03001551 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001552 rp.status = -PTR_ERR(conn);
1553 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1554 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001555 goto unlock;
1556 }
1557
1558 if (conn->connect_cfm_cb) {
1559 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001560 rp.status = EBUSY;
1561 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1562 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001563 goto unlock;
1564 }
1565
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001566 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001567 if (!cmd) {
1568 err = -ENOMEM;
1569 hci_conn_put(conn);
1570 goto unlock;
1571 }
1572
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001573 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001574 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001575 conn->connect_cfm_cb = pairing_complete_cb;
1576
Johan Hedberge9a416b2011-02-19 12:05:56 -03001577 conn->security_cfm_cb = pairing_complete_cb;
1578 conn->disconn_cfm_cb = pairing_complete_cb;
1579 conn->io_capability = cp->io_cap;
1580 cmd->user_data = conn;
1581
1582 if (conn->state == BT_CONNECTED &&
1583 hci_conn_security(conn, sec_level, auth_type))
1584 pairing_complete(cmd, 0);
1585
1586 err = 0;
1587
1588unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001589 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001590 hci_dev_put(hdev);
1591
1592 return err;
1593}
1594
Brian Gix0df4c182011-11-16 13:53:13 -08001595static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1596 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001597{
Johan Hedberga5c29682011-02-19 12:05:57 -03001598 struct pending_cmd *cmd;
1599 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001600 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001601 int err;
1602
Szymon Janc4e51eae2011-02-25 19:05:48 +01001603 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001604 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001605 return cmd_status(sk, index, mgmt_op,
1606 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001607
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001608 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001609
Johan Hedberga5c29682011-02-19 12:05:57 -03001610 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001611 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1612 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001613 }
1614
Brian Gix47c15e22011-11-16 13:53:14 -08001615 /*
1616 * Check for an existing ACL link, if present pair via
1617 * HCI commands.
1618 *
1619 * If no ACL link is present, check for an LE link and if
1620 * present, pair via the SMP engine.
1621 *
1622 * If neither ACL nor LE links are present, fail with error.
1623 */
1624 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1625 if (!conn) {
1626 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1627 if (!conn) {
1628 err = cmd_status(sk, index, mgmt_op,
1629 MGMT_STATUS_NOT_CONNECTED);
1630 goto done;
1631 }
1632
1633 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001634 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001635
Brian Gix5fe57d92011-12-21 16:12:13 -08001636 if (!err)
1637 err = cmd_status(sk, index, mgmt_op,
1638 MGMT_STATUS_SUCCESS);
1639 else
1640 err = cmd_status(sk, index, mgmt_op,
1641 MGMT_STATUS_FAILED);
1642
Brian Gix47c15e22011-11-16 13:53:14 -08001643 goto done;
1644 }
1645
Brian Gix0df4c182011-11-16 13:53:13 -08001646 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001647 if (!cmd) {
1648 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001649 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001650 }
1651
Brian Gix0df4c182011-11-16 13:53:13 -08001652 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001653 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1654 struct hci_cp_user_passkey_reply cp;
1655
1656 bacpy(&cp.bdaddr, bdaddr);
1657 cp.passkey = passkey;
1658 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1659 } else
1660 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1661
Johan Hedberga664b5b2011-02-19 12:06:02 -03001662 if (err < 0)
1663 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001664
Brian Gix0df4c182011-11-16 13:53:13 -08001665done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001666 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001667 hci_dev_put(hdev);
1668
1669 return err;
1670}
1671
Brian Gix0df4c182011-11-16 13:53:13 -08001672static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1673{
1674 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1675
1676 BT_DBG("");
1677
1678 if (len != sizeof(*cp))
1679 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1680 MGMT_STATUS_INVALID_PARAMS);
1681
1682 return user_pairing_resp(sk, index, &cp->bdaddr,
1683 MGMT_OP_USER_CONFIRM_REPLY,
1684 HCI_OP_USER_CONFIRM_REPLY, 0);
1685}
1686
1687static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1688 u16 len)
1689{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001690 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001691
1692 BT_DBG("");
1693
1694 if (len != sizeof(*cp))
1695 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1696 MGMT_STATUS_INVALID_PARAMS);
1697
1698 return user_pairing_resp(sk, index, &cp->bdaddr,
1699 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1700 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1701}
1702
Brian Gix604086b2011-11-23 08:28:33 -08001703static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1704{
1705 struct mgmt_cp_user_passkey_reply *cp = (void *) data;
1706
1707 BT_DBG("");
1708
1709 if (len != sizeof(*cp))
1710 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1711 EINVAL);
1712
1713 return user_pairing_resp(sk, index, &cp->bdaddr,
1714 MGMT_OP_USER_PASSKEY_REPLY,
1715 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1716}
1717
1718static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1719 u16 len)
1720{
1721 struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data;
1722
1723 BT_DBG("");
1724
1725 if (len != sizeof(*cp))
1726 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1727 EINVAL);
1728
1729 return user_pairing_resp(sk, index, &cp->bdaddr,
1730 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1731 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1732}
1733
Johan Hedbergb312b1612011-03-16 14:29:37 +02001734static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1735 u16 len)
1736{
1737 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1738 struct hci_cp_write_local_name hci_cp;
1739 struct hci_dev *hdev;
1740 struct pending_cmd *cmd;
1741 int err;
1742
1743 BT_DBG("");
1744
1745 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001746 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1747 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001748
1749 hdev = hci_dev_get(index);
1750 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001751 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1752 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001753
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001754 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001755
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001756 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001757 if (!cmd) {
1758 err = -ENOMEM;
1759 goto failed;
1760 }
1761
1762 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1763 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1764 &hci_cp);
1765 if (err < 0)
1766 mgmt_pending_remove(cmd);
1767
1768failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001769 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001770 hci_dev_put(hdev);
1771
1772 return err;
1773}
1774
Szymon Jancc35938b2011-03-22 13:12:21 +01001775static int read_local_oob_data(struct sock *sk, u16 index)
1776{
1777 struct hci_dev *hdev;
1778 struct pending_cmd *cmd;
1779 int err;
1780
1781 BT_DBG("hci%u", index);
1782
1783 hdev = hci_dev_get(index);
1784 if (!hdev)
1785 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001786 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001787
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001788 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001789
1790 if (!test_bit(HCI_UP, &hdev->flags)) {
1791 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001792 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001793 goto unlock;
1794 }
1795
1796 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1797 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001798 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001799 goto unlock;
1800 }
1801
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001802 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001803 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1804 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001805 goto unlock;
1806 }
1807
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001808 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001809 if (!cmd) {
1810 err = -ENOMEM;
1811 goto unlock;
1812 }
1813
1814 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1815 if (err < 0)
1816 mgmt_pending_remove(cmd);
1817
1818unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001819 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001820 hci_dev_put(hdev);
1821
1822 return err;
1823}
1824
Szymon Janc2763eda2011-03-22 13:12:22 +01001825static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1826 u16 len)
1827{
1828 struct hci_dev *hdev;
1829 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1830 int err;
1831
1832 BT_DBG("hci%u ", index);
1833
1834 if (len != sizeof(*cp))
1835 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001836 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001837
1838 hdev = hci_dev_get(index);
1839 if (!hdev)
1840 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001841 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001842
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001843 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001844
1845 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1846 cp->randomizer);
1847 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001848 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1849 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001850 else
1851 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1852 0);
1853
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001854 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001855 hci_dev_put(hdev);
1856
1857 return err;
1858}
1859
1860static int remove_remote_oob_data(struct sock *sk, u16 index,
1861 unsigned char *data, u16 len)
1862{
1863 struct hci_dev *hdev;
1864 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1865 int err;
1866
1867 BT_DBG("hci%u ", index);
1868
1869 if (len != sizeof(*cp))
1870 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001871 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001872
1873 hdev = hci_dev_get(index);
1874 if (!hdev)
1875 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001876 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001877
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001878 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001879
1880 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1881 if (err < 0)
1882 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001883 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001884 else
1885 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1886 NULL, 0);
1887
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001888 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001889 hci_dev_put(hdev);
1890
1891 return err;
1892}
1893
Johan Hedberg450dfda2011-11-12 11:58:22 +02001894static int start_discovery(struct sock *sk, u16 index,
1895 unsigned char *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001896{
Johan Hedberg450dfda2011-11-12 11:58:22 +02001897 struct mgmt_cp_start_discovery *cp = (void *) data;
Johan Hedberg14a53662011-04-27 10:29:56 -04001898 struct pending_cmd *cmd;
1899 struct hci_dev *hdev;
1900 int err;
1901
1902 BT_DBG("hci%u", index);
1903
Johan Hedberg450dfda2011-11-12 11:58:22 +02001904 if (len != sizeof(*cp))
1905 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1906 MGMT_STATUS_INVALID_PARAMS);
1907
Johan Hedberg14a53662011-04-27 10:29:56 -04001908 hdev = hci_dev_get(index);
1909 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001910 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1911 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001912
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001913 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001914
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001915 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001916 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1917 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001918 goto failed;
1919 }
1920
Johan Hedbergff9ef572012-01-04 14:23:45 +02001921 if (hdev->discovery.state != DISCOVERY_STOPPED) {
1922 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1923 MGMT_STATUS_BUSY);
1924 goto failed;
1925 }
1926
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001927 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001928 if (!cmd) {
1929 err = -ENOMEM;
1930 goto failed;
1931 }
1932
Andre Guedes2519a1f2011-11-07 11:45:24 -03001933 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001934 if (err < 0)
1935 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02001936 else
1937 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04001938
1939failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001940 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001941 hci_dev_put(hdev);
1942
1943 return err;
1944}
1945
1946static int stop_discovery(struct sock *sk, u16 index)
1947{
1948 struct hci_dev *hdev;
1949 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001950 struct hci_cp_remote_name_req_cancel cp;
1951 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04001952 int err;
1953
1954 BT_DBG("hci%u", index);
1955
1956 hdev = hci_dev_get(index);
1957 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001958 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1959 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001960
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001961 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001962
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001963 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02001964 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1965 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001966 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02001967 }
1968
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001969 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001970 if (!cmd) {
1971 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001972 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04001973 }
1974
Johan Hedberg30dc78e2012-01-04 15:44:20 +02001975 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
1976 err = hci_cancel_inquiry(hdev);
1977 if (err < 0)
1978 mgmt_pending_remove(cmd);
1979 else
1980 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
1981 goto unlock;
1982 }
1983
1984 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
1985 if (!e) {
1986 mgmt_pending_remove(cmd);
1987 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
1988 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
1989 goto unlock;
1990 }
1991
1992 bacpy(&cp.bdaddr, &e->data.bdaddr);
1993 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
1994 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04001995 if (err < 0)
1996 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02001997 else
1998 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04001999
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002000unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002001 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002002 hci_dev_put(hdev);
2003
2004 return err;
2005}
2006
Johan Hedberg561aafb2012-01-04 13:31:59 +02002007static int confirm_name(struct sock *sk, u16 index, unsigned char *data,
2008 u16 len)
2009{
2010 struct mgmt_cp_confirm_name *cp = (void *) data;
2011 struct inquiry_entry *e;
2012 struct hci_dev *hdev;
2013 int err;
2014
2015 BT_DBG("hci%u", index);
2016
2017 if (len != sizeof(*cp))
2018 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2019 MGMT_STATUS_INVALID_PARAMS);
2020
2021 hdev = hci_dev_get(index);
2022 if (!hdev)
2023 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2024 MGMT_STATUS_INVALID_PARAMS);
2025
2026 hci_dev_lock(hdev);
2027
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002028 if (!hci_discovery_active(hdev)) {
2029 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2030 MGMT_STATUS_FAILED);
2031 goto failed;
2032 }
2033
Johan Hedberg561aafb2012-01-04 13:31:59 +02002034 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr);
2035 if (!e) {
2036 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2037 MGMT_STATUS_INVALID_PARAMS);
2038 goto failed;
2039 }
2040
2041 if (cp->name_known) {
2042 e->name_state = NAME_KNOWN;
2043 list_del(&e->list);
2044 } else {
2045 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002046 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002047 }
2048
2049 err = 0;
2050
2051failed:
2052 hci_dev_unlock(hdev);
2053
2054 return err;
2055}
2056
Antti Julku7fbec222011-06-15 12:01:15 +03002057static int block_device(struct sock *sk, u16 index, unsigned char *data,
2058 u16 len)
2059{
2060 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03002061 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03002062 int err;
2063
2064 BT_DBG("hci%u", index);
2065
Antti Julku7fbec222011-06-15 12:01:15 +03002066 if (len != sizeof(*cp))
2067 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002068 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002069
2070 hdev = hci_dev_get(index);
2071 if (!hdev)
2072 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002073 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002074
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002075 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002076
Antti Julku7fbec222011-06-15 12:01:15 +03002077 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03002078 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002079 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2080 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002081 else
2082 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2083 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002084
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002085 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002086 hci_dev_put(hdev);
2087
2088 return err;
2089}
2090
2091static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
2092 u16 len)
2093{
2094 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03002095 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03002096 int err;
2097
2098 BT_DBG("hci%u", index);
2099
Antti Julku7fbec222011-06-15 12:01:15 +03002100 if (len != sizeof(*cp))
2101 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002102 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002103
2104 hdev = hci_dev_get(index);
2105 if (!hdev)
2106 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002107 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002108
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002109 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002110
Antti Julku7fbec222011-06-15 12:01:15 +03002111 err = hci_blacklist_del(hdev, &cp->bdaddr);
2112
2113 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002114 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2115 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002116 else
2117 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2118 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002119
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002120 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002121 hci_dev_put(hdev);
2122
2123 return err;
2124}
2125
Antti Julkuf6422ec2011-06-22 13:11:56 +03002126static int set_fast_connectable(struct sock *sk, u16 index,
2127 unsigned char *data, u16 len)
2128{
2129 struct hci_dev *hdev;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002130 struct mgmt_mode *cp = (void *) data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002131 struct hci_cp_write_page_scan_activity acp;
2132 u8 type;
2133 int err;
2134
2135 BT_DBG("hci%u", index);
2136
2137 if (len != sizeof(*cp))
2138 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002139 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002140
2141 hdev = hci_dev_get(index);
2142 if (!hdev)
2143 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002144 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002145
2146 hci_dev_lock(hdev);
2147
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002148 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002149 type = PAGE_SCAN_TYPE_INTERLACED;
2150 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2151 } else {
2152 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2153 acp.interval = 0x0800; /* default 1.28 sec page scan */
2154 }
2155
2156 acp.window = 0x0012; /* default 11.25 msec page scan window */
2157
2158 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2159 sizeof(acp), &acp);
2160 if (err < 0) {
2161 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002162 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002163 goto done;
2164 }
2165
2166 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2167 if (err < 0) {
2168 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002169 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002170 goto done;
2171 }
2172
2173 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2174 NULL, 0);
2175done:
2176 hci_dev_unlock(hdev);
2177 hci_dev_put(hdev);
2178
2179 return err;
2180}
2181
Johan Hedberg03811012010-12-08 00:21:06 +02002182int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2183{
2184 unsigned char *buf;
2185 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002186 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002187 int err;
2188
2189 BT_DBG("got %zu bytes", msglen);
2190
2191 if (msglen < sizeof(*hdr))
2192 return -EINVAL;
2193
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002194 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002195 if (!buf)
2196 return -ENOMEM;
2197
2198 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2199 err = -EFAULT;
2200 goto done;
2201 }
2202
2203 hdr = (struct mgmt_hdr *) buf;
2204 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002205 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002206 len = get_unaligned_le16(&hdr->len);
2207
2208 if (len != msglen - sizeof(*hdr)) {
2209 err = -EINVAL;
2210 goto done;
2211 }
2212
2213 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002214 case MGMT_OP_READ_VERSION:
2215 err = read_version(sk);
2216 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002217 case MGMT_OP_READ_INDEX_LIST:
2218 err = read_index_list(sk);
2219 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002220 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002221 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002222 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002223 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002224 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002225 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002226 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002227 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002228 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002229 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002230 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002231 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002232 case MGMT_OP_SET_FAST_CONNECTABLE:
2233 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
2234 len);
2235 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002236 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002237 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002238 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002239 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002240 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002241 break;
2242 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002243 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002244 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002245 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002246 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002247 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002248 case MGMT_OP_LOAD_LINK_KEYS:
2249 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002250 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002251 case MGMT_OP_REMOVE_KEYS:
2252 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002253 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002254 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002255 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002256 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002257 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002258 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002259 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002260 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002261 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002262 break;
2263 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002264 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002265 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002266 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002267 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002268 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002269 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002270 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002271 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002272 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002273 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002274 break;
2275 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002276 err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr),
2277 len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002278 break;
Brian Gix604086b2011-11-23 08:28:33 -08002279 case MGMT_OP_USER_PASSKEY_REPLY:
2280 err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len);
2281 break;
2282 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
2283 err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr),
2284 len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002285 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002286 case MGMT_OP_SET_LOCAL_NAME:
2287 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2288 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002289 case MGMT_OP_READ_LOCAL_OOB_DATA:
2290 err = read_local_oob_data(sk, index);
2291 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002292 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2293 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2294 break;
2295 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2296 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2297 len);
2298 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002299 case MGMT_OP_START_DISCOVERY:
Johan Hedberg450dfda2011-11-12 11:58:22 +02002300 err = start_discovery(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002301 break;
2302 case MGMT_OP_STOP_DISCOVERY:
2303 err = stop_discovery(sk, index);
2304 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002305 case MGMT_OP_CONFIRM_NAME:
2306 err = confirm_name(sk, index, buf + sizeof(*hdr), len);
2307 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002308 case MGMT_OP_BLOCK_DEVICE:
2309 err = block_device(sk, index, buf + sizeof(*hdr), len);
2310 break;
2311 case MGMT_OP_UNBLOCK_DEVICE:
2312 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
2313 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002314 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002315 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002316 err = cmd_status(sk, index, opcode,
2317 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002318 break;
2319 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002320
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002321 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002322 goto done;
2323
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002324 err = msglen;
2325
2326done:
2327 kfree(buf);
2328 return err;
2329}
2330
Johan Hedbergb24752f2011-11-03 14:40:33 +02002331static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2332{
2333 u8 *status = data;
2334
2335 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2336 mgmt_pending_remove(cmd);
2337}
2338
Johan Hedberg744cf192011-11-08 20:40:14 +02002339int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002340{
Johan Hedberg744cf192011-11-08 20:40:14 +02002341 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002342}
2343
Johan Hedberg744cf192011-11-08 20:40:14 +02002344int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002345{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002346 u8 status = ENODEV;
2347
Johan Hedberg744cf192011-11-08 20:40:14 +02002348 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002349
Johan Hedberg744cf192011-11-08 20:40:14 +02002350 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002351}
2352
2353struct cmd_lookup {
2354 u8 val;
2355 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002356 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002357};
2358
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002359static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002360{
Johan Hedberg03811012010-12-08 00:21:06 +02002361 struct cmd_lookup *match = data;
2362
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002363 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002364
2365 list_del(&cmd->list);
2366
2367 if (match->sk == NULL) {
2368 match->sk = cmd->sk;
2369 sock_hold(match->sk);
2370 }
2371
2372 mgmt_pending_free(cmd);
2373}
2374
Johan Hedberg744cf192011-11-08 20:40:14 +02002375int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002376{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002377 struct cmd_lookup match = { powered, NULL, hdev };
2378 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002379 int ret;
2380
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002381 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002382
Johan Hedbergb24752f2011-11-03 14:40:33 +02002383 if (!powered) {
2384 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002385 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002386 }
2387
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002388 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002389
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002390 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2391 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002392
2393 if (match.sk)
2394 sock_put(match.sk);
2395
2396 return ret;
2397}
2398
Johan Hedberg744cf192011-11-08 20:40:14 +02002399int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002400{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002401 struct cmd_lookup match = { discoverable, NULL, hdev };
2402 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002403 int ret;
2404
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002405 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002406
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002407 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002408
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002409 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002410 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002411 if (match.sk)
2412 sock_put(match.sk);
2413
2414 return ret;
2415}
2416
Johan Hedberg744cf192011-11-08 20:40:14 +02002417int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002418{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002419 __le32 ev;
2420 struct cmd_lookup match = { connectable, NULL, hdev };
Johan Hedberg03811012010-12-08 00:21:06 +02002421 int ret;
2422
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002423 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2424 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002425
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002426 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002427
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002428 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002429
2430 if (match.sk)
2431 sock_put(match.sk);
2432
2433 return ret;
2434}
2435
Johan Hedberg744cf192011-11-08 20:40:14 +02002436int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002437{
Johan Hedbergca69b792011-11-11 18:10:00 +02002438 u8 mgmt_err = mgmt_status(status);
2439
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002440 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002441 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002442 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002443
2444 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002445 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002446 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002447
2448 return 0;
2449}
2450
Johan Hedberg744cf192011-11-08 20:40:14 +02002451int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2452 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002453{
Johan Hedberg86742e12011-11-07 23:13:38 +02002454 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002455
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002456 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002457
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002458 ev.store_hint = persistent;
2459 bacpy(&ev.key.bdaddr, &key->bdaddr);
2460 ev.key.type = key->type;
2461 memcpy(ev.key.val, key->val, 16);
2462 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002463
Johan Hedberg744cf192011-11-08 20:40:14 +02002464 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002465}
Johan Hedbergf7520542011-01-20 12:34:39 +02002466
Johan Hedberg48264f02011-11-09 13:58:58 +02002467int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2468 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002469{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002470 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002471
Johan Hedbergf7520542011-01-20 12:34:39 +02002472 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002473 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002474
Johan Hedberg744cf192011-11-08 20:40:14 +02002475 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002476}
2477
Johan Hedberg8962ee72011-01-20 12:40:27 +02002478static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2479{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002480 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002481 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002482 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002483
Johan Hedberga38528f2011-01-22 06:46:43 +02002484 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002485 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002486
Szymon Janc4e51eae2011-02-25 19:05:48 +01002487 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002488
2489 *sk = cmd->sk;
2490 sock_hold(*sk);
2491
Johan Hedberga664b5b2011-02-19 12:06:02 -03002492 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002493}
2494
Johan Hedberga8a1d192011-11-10 15:54:38 +02002495static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2496{
2497 u8 *status = data;
2498 struct mgmt_cp_remove_keys *cp = cmd->param;
2499 struct mgmt_rp_remove_keys rp;
2500
2501 memset(&rp, 0, sizeof(rp));
2502 bacpy(&rp.bdaddr, &cp->bdaddr);
2503 if (status != NULL)
2504 rp.status = *status;
2505
2506 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2507 sizeof(rp));
2508
2509 mgmt_pending_remove(cmd);
2510}
2511
Johan Hedberg48264f02011-11-09 13:58:58 +02002512int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2513 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002514{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002515 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002516 struct sock *sk = NULL;
2517 int err;
2518
Johan Hedberg744cf192011-11-08 20:40:14 +02002519 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002520
Johan Hedbergf7520542011-01-20 12:34:39 +02002521 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002522 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002523
Johan Hedberg744cf192011-11-08 20:40:14 +02002524 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002525
2526 if (sk)
2527 sock_put(sk);
2528
Johan Hedberga8a1d192011-11-10 15:54:38 +02002529 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2530
Johan Hedberg8962ee72011-01-20 12:40:27 +02002531 return err;
2532}
2533
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002534int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002535{
2536 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002537 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002538 int err;
2539
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002540 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002541 if (!cmd)
2542 return -ENOENT;
2543
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002544 if (bdaddr) {
2545 struct mgmt_rp_disconnect rp;
2546
2547 bacpy(&rp.bdaddr, bdaddr);
2548 rp.status = status;
2549
2550 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2551 &rp, sizeof(rp));
2552 } else
2553 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002554 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002555
Johan Hedberga664b5b2011-02-19 12:06:02 -03002556 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002557
2558 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002559}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002560
Johan Hedberg48264f02011-11-09 13:58:58 +02002561int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2562 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002563{
2564 struct mgmt_ev_connect_failed ev;
2565
Johan Hedberg4c659c32011-11-07 23:13:39 +02002566 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002567 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002568 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002569
Johan Hedberg744cf192011-11-08 20:40:14 +02002570 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002571}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002572
Johan Hedberg744cf192011-11-08 20:40:14 +02002573int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002574{
2575 struct mgmt_ev_pin_code_request ev;
2576
Johan Hedberg980e1a52011-01-22 06:10:07 +02002577 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002578 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002579
Johan Hedberg744cf192011-11-08 20:40:14 +02002580 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002581 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002582}
2583
Johan Hedberg744cf192011-11-08 20:40:14 +02002584int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2585 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002586{
2587 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002588 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002589 int err;
2590
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002591 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002592 if (!cmd)
2593 return -ENOENT;
2594
Johan Hedbergac56fb12011-02-19 12:05:59 -03002595 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002596 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002597
Johan Hedberg744cf192011-11-08 20:40:14 +02002598 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002599 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002600
Johan Hedberga664b5b2011-02-19 12:06:02 -03002601 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002602
2603 return err;
2604}
2605
Johan Hedberg744cf192011-11-08 20:40:14 +02002606int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2607 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002608{
2609 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002610 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002611 int err;
2612
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002613 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002614 if (!cmd)
2615 return -ENOENT;
2616
Johan Hedbergac56fb12011-02-19 12:05:59 -03002617 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002618 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002619
Johan Hedberg744cf192011-11-08 20:40:14 +02002620 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002621 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002622
Johan Hedberga664b5b2011-02-19 12:06:02 -03002623 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002624
2625 return err;
2626}
Johan Hedberga5c29682011-02-19 12:05:57 -03002627
Johan Hedberg744cf192011-11-08 20:40:14 +02002628int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2629 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002630{
2631 struct mgmt_ev_user_confirm_request ev;
2632
Johan Hedberg744cf192011-11-08 20:40:14 +02002633 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002634
Johan Hedberga5c29682011-02-19 12:05:57 -03002635 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002636 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002637 put_unaligned_le32(value, &ev.value);
2638
Johan Hedberg744cf192011-11-08 20:40:14 +02002639 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002640 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002641}
2642
Brian Gix604086b2011-11-23 08:28:33 -08002643int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2644{
2645 struct mgmt_ev_user_passkey_request ev;
2646
2647 BT_DBG("%s", hdev->name);
2648
2649 bacpy(&ev.bdaddr, bdaddr);
2650
2651 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2652 NULL);
2653}
2654
Brian Gix0df4c182011-11-16 13:53:13 -08002655static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002656 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002657{
2658 struct pending_cmd *cmd;
2659 struct mgmt_rp_user_confirm_reply rp;
2660 int err;
2661
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002662 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002663 if (!cmd)
2664 return -ENOENT;
2665
Johan Hedberga5c29682011-02-19 12:05:57 -03002666 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002667 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002668 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002669
Johan Hedberga664b5b2011-02-19 12:06:02 -03002670 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002671
2672 return err;
2673}
2674
Johan Hedberg744cf192011-11-08 20:40:14 +02002675int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2676 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002677{
Brian Gix0df4c182011-11-16 13:53:13 -08002678 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002679 MGMT_OP_USER_CONFIRM_REPLY);
2680}
2681
Johan Hedberg744cf192011-11-08 20:40:14 +02002682int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2683 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002684{
Brian Gix0df4c182011-11-16 13:53:13 -08002685 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002686 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2687}
Johan Hedberg2a611692011-02-19 12:06:00 -03002688
Brian Gix604086b2011-11-23 08:28:33 -08002689int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2690 u8 status)
2691{
2692 return user_pairing_resp_complete(hdev, bdaddr, status,
2693 MGMT_OP_USER_PASSKEY_REPLY);
2694}
2695
2696int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2697 bdaddr_t *bdaddr, u8 status)
2698{
2699 return user_pairing_resp_complete(hdev, bdaddr, status,
2700 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2701}
2702
Johan Hedberg744cf192011-11-08 20:40:14 +02002703int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002704{
2705 struct mgmt_ev_auth_failed ev;
2706
Johan Hedberg2a611692011-02-19 12:06:00 -03002707 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002708 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002709
Johan Hedberg744cf192011-11-08 20:40:14 +02002710 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002711}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002712
Johan Hedberg744cf192011-11-08 20:40:14 +02002713int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002714{
2715 struct pending_cmd *cmd;
2716 struct mgmt_cp_set_local_name ev;
2717 int err;
2718
2719 memset(&ev, 0, sizeof(ev));
2720 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2721
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002722 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002723 if (!cmd)
2724 goto send_event;
2725
2726 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002727 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002728 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002729 goto failed;
2730 }
2731
Johan Hedberg744cf192011-11-08 20:40:14 +02002732 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002733
Johan Hedberg744cf192011-11-08 20:40:14 +02002734 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002735 sizeof(ev));
2736 if (err < 0)
2737 goto failed;
2738
2739send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002740 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002741 cmd ? cmd->sk : NULL);
2742
2743failed:
2744 if (cmd)
2745 mgmt_pending_remove(cmd);
2746 return err;
2747}
Szymon Jancc35938b2011-03-22 13:12:21 +01002748
Johan Hedberg744cf192011-11-08 20:40:14 +02002749int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2750 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002751{
2752 struct pending_cmd *cmd;
2753 int err;
2754
Johan Hedberg744cf192011-11-08 20:40:14 +02002755 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002756
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002757 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002758 if (!cmd)
2759 return -ENOENT;
2760
2761 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002762 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002763 MGMT_OP_READ_LOCAL_OOB_DATA,
2764 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002765 } else {
2766 struct mgmt_rp_read_local_oob_data rp;
2767
2768 memcpy(rp.hash, hash, sizeof(rp.hash));
2769 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2770
Johan Hedberg744cf192011-11-08 20:40:14 +02002771 err = cmd_complete(cmd->sk, hdev->id,
2772 MGMT_OP_READ_LOCAL_OOB_DATA,
2773 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002774 }
2775
2776 mgmt_pending_remove(cmd);
2777
2778 return err;
2779}
Johan Hedberge17acd42011-03-30 23:57:16 +03002780
Johan Hedberg48264f02011-11-09 13:58:58 +02002781int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002782 u8 addr_type, u8 *dev_class, s8 rssi,
2783 u8 cfm_name, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002784{
2785 struct mgmt_ev_device_found ev;
2786
2787 memset(&ev, 0, sizeof(ev));
2788
Johan Hedberg4c659c32011-11-07 23:13:39 +02002789 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002790 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002791 ev.rssi = rssi;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002792 ev.confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03002793
2794 if (eir)
2795 memcpy(ev.eir, eir, sizeof(ev.eir));
2796
Andre Guedesf8523592011-09-09 18:56:26 -03002797 if (dev_class)
2798 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2799
Johan Hedberg744cf192011-11-08 20:40:14 +02002800 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002801}
Johan Hedberga88a9652011-03-30 13:18:12 +03002802
Johan Hedberg744cf192011-11-08 20:40:14 +02002803int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002804{
2805 struct mgmt_ev_remote_name ev;
2806
2807 memset(&ev, 0, sizeof(ev));
2808
2809 bacpy(&ev.bdaddr, bdaddr);
2810 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2811
Johan Hedberg744cf192011-11-08 20:40:14 +02002812 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002813}
Johan Hedberg314b2382011-04-27 10:29:57 -04002814
Andre Guedes7a135102011-11-09 17:14:25 -03002815int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002816{
2817 struct pending_cmd *cmd;
2818 int err;
2819
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002820 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002821 if (!cmd)
2822 return -ENOENT;
2823
Johan Hedbergca69b792011-11-11 18:10:00 +02002824 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002825 mgmt_pending_remove(cmd);
2826
2827 return err;
2828}
2829
Andre Guedese6d465c2011-11-09 17:14:26 -03002830int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2831{
2832 struct pending_cmd *cmd;
2833 int err;
2834
2835 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2836 if (!cmd)
2837 return -ENOENT;
2838
Andre Guedese75a8b0c2012-01-02 16:50:53 -03002839 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02002840 mgmt_pending_remove(cmd);
2841
2842 return err;
2843}
Johan Hedberg314b2382011-04-27 10:29:57 -04002844
Johan Hedberg744cf192011-11-08 20:40:14 +02002845int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002846{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002847 struct pending_cmd *cmd;
2848
2849 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002850 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002851 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002852 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002853
2854 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002855 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002856 mgmt_pending_remove(cmd);
2857 }
2858
Johan Hedberg744cf192011-11-08 20:40:14 +02002859 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002860 sizeof(discovering), NULL);
2861}
Antti Julku5e762442011-08-25 16:48:02 +03002862
Johan Hedberg744cf192011-11-08 20:40:14 +02002863int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002864{
2865 struct pending_cmd *cmd;
2866 struct mgmt_ev_device_blocked ev;
2867
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002868 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002869
2870 bacpy(&ev.bdaddr, bdaddr);
2871
Johan Hedberg744cf192011-11-08 20:40:14 +02002872 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2873 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002874}
2875
Johan Hedberg744cf192011-11-08 20:40:14 +02002876int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002877{
2878 struct pending_cmd *cmd;
2879 struct mgmt_ev_device_unblocked ev;
2880
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002881 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002882
2883 bacpy(&ev.bdaddr, bdaddr);
2884
Johan Hedberg744cf192011-11-08 20:40:14 +02002885 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2886 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002887}