blob: fbcbef6ecceb633dc8fa8123e1b5b03f210f3549 [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>
33
Johan Hedberg02d98122010-12-13 21:07:04 +020034#define MGMT_VERSION 0
35#define MGMT_REVISION 1
36
Andre Guedes2519a1f2011-11-07 11:45:24 -030037#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
38
Johan Hedberg7d785252011-12-15 00:47:39 +020039#define SERVICE_CACHE_TIMEOUT (5 * 1000)
40
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020041struct pending_cmd {
42 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020043 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020044 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010045 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020046 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030047 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020048};
49
Johan Hedbergca69b792011-11-11 18:10:00 +020050/* HCI to MGMT error code conversion table */
51static u8 mgmt_status_table[] = {
52 MGMT_STATUS_SUCCESS,
53 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
54 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
55 MGMT_STATUS_FAILED, /* Hardware Failure */
56 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
57 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
58 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
59 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
60 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
61 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
62 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
63 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
64 MGMT_STATUS_BUSY, /* Command Disallowed */
65 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
66 MGMT_STATUS_REJECTED, /* Rejected Security */
67 MGMT_STATUS_REJECTED, /* Rejected Personal */
68 MGMT_STATUS_TIMEOUT, /* Host Timeout */
69 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
70 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
71 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
72 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
73 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
74 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
75 MGMT_STATUS_BUSY, /* Repeated Attempts */
76 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
77 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
78 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
79 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
80 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
81 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
82 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
83 MGMT_STATUS_FAILED, /* Unspecified Error */
84 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
85 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
86 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
87 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
88 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
89 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
90 MGMT_STATUS_FAILED, /* Unit Link Key Used */
91 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
92 MGMT_STATUS_TIMEOUT, /* Instant Passed */
93 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
94 MGMT_STATUS_FAILED, /* Transaction Collision */
95 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
96 MGMT_STATUS_REJECTED, /* QoS Rejected */
97 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
98 MGMT_STATUS_REJECTED, /* Insufficient Security */
99 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
100 MGMT_STATUS_BUSY, /* Role Switch Pending */
101 MGMT_STATUS_FAILED, /* Slot Violation */
102 MGMT_STATUS_FAILED, /* Role Switch Failed */
103 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
104 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
105 MGMT_STATUS_BUSY, /* Host Busy Pairing */
106 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
107 MGMT_STATUS_BUSY, /* Controller Busy */
108 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
109 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
110 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
111 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
112 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
113};
114
115static u8 mgmt_status(u8 hci_status)
116{
117 if (hci_status < ARRAY_SIZE(mgmt_status_table))
118 return mgmt_status_table[hci_status];
119
120 return MGMT_STATUS_FAILED;
121}
122
Szymon Janc4e51eae2011-02-25 19:05:48 +0100123static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200124{
125 struct sk_buff *skb;
126 struct mgmt_hdr *hdr;
127 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300128 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200129
Szymon Janc34eb5252011-02-28 14:10:08 +0100130 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200131
132 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
133 if (!skb)
134 return -ENOMEM;
135
136 hdr = (void *) skb_put(skb, sizeof(*hdr));
137
138 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100139 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200140 hdr->len = cpu_to_le16(sizeof(*ev));
141
142 ev = (void *) skb_put(skb, sizeof(*ev));
143 ev->status = status;
144 put_unaligned_le16(cmd, &ev->opcode);
145
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300146 err = sock_queue_rcv_skb(sk, skb);
147 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200148 kfree_skb(skb);
149
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300150 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200151}
152
Szymon Janc4e51eae2011-02-25 19:05:48 +0100153static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
154 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200155{
156 struct sk_buff *skb;
157 struct mgmt_hdr *hdr;
158 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300159 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200160
161 BT_DBG("sock %p", sk);
162
Johan Hedberga38528f2011-01-22 06:46:43 +0200163 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200164 if (!skb)
165 return -ENOMEM;
166
167 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200168
Johan Hedberg02d98122010-12-13 21:07:04 +0200169 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100170 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200171 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200172
Johan Hedberga38528f2011-01-22 06:46:43 +0200173 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
174 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100175
176 if (rp)
177 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200178
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300179 err = sock_queue_rcv_skb(sk, skb);
180 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200181 kfree_skb(skb);
182
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300183 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200184}
185
Johan Hedberga38528f2011-01-22 06:46:43 +0200186static int read_version(struct sock *sk)
187{
188 struct mgmt_rp_read_version rp;
189
190 BT_DBG("sock %p", sk);
191
192 rp.version = MGMT_VERSION;
193 put_unaligned_le16(MGMT_REVISION, &rp.revision);
194
Szymon Janc4e51eae2011-02-25 19:05:48 +0100195 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
196 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200197}
198
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200199static int read_index_list(struct sock *sk)
200{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200201 struct mgmt_rp_read_index_list *rp;
202 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200203 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200204 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200205 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200206 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200207
208 BT_DBG("sock %p", sk);
209
210 read_lock(&hci_dev_list_lock);
211
212 count = 0;
213 list_for_each(p, &hci_dev_list) {
214 count++;
215 }
216
Johan Hedberga38528f2011-01-22 06:46:43 +0200217 rp_len = sizeof(*rp) + (2 * count);
218 rp = kmalloc(rp_len, GFP_ATOMIC);
219 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100220 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200221 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100222 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200223
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200224 put_unaligned_le16(count, &rp->num_controllers);
225
226 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200227 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberg32435532011-11-07 22:16:04 +0200228 if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200229 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200230
231 if (test_bit(HCI_SETUP, &d->flags))
232 continue;
233
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200234 put_unaligned_le16(d->id, &rp->index[i++]);
235 BT_DBG("Added hci%u", d->id);
236 }
237
238 read_unlock(&hci_dev_list_lock);
239
Szymon Janc4e51eae2011-02-25 19:05:48 +0100240 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
241 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200242
Johan Hedberga38528f2011-01-22 06:46:43 +0200243 kfree(rp);
244
245 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200246}
247
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200248static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200249{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200250 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200251
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200252 settings |= MGMT_SETTING_POWERED;
253 settings |= MGMT_SETTING_CONNECTABLE;
254 settings |= MGMT_SETTING_FAST_CONNECTABLE;
255 settings |= MGMT_SETTING_DISCOVERABLE;
256 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200257
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200258 if (hdev->features[6] & LMP_SIMPLE_PAIR)
259 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200260
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200261 if (!(hdev->features[4] & LMP_NO_BREDR)) {
262 settings |= MGMT_SETTING_BREDR;
263 settings |= MGMT_SETTING_LINK_SECURITY;
264 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200265
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200266 if (hdev->features[4] & LMP_LE)
267 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200268
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200269 return settings;
270}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200271
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200272static u32 get_current_settings(struct hci_dev *hdev)
273{
274 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200275
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200276 if (test_bit(HCI_UP, &hdev->flags))
277 settings |= MGMT_SETTING_POWERED;
278 else
279 return settings;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200280
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200281 if (test_bit(HCI_PSCAN, &hdev->flags))
282 settings |= MGMT_SETTING_CONNECTABLE;
283
284 if (test_bit(HCI_ISCAN, &hdev->flags))
285 settings |= MGMT_SETTING_DISCOVERABLE;
286
287 if (test_bit(HCI_PAIRABLE, &hdev->flags))
288 settings |= MGMT_SETTING_PAIRABLE;
289
290 if (!(hdev->features[4] & LMP_NO_BREDR))
291 settings |= MGMT_SETTING_BREDR;
292
293 if (hdev->extfeatures[0] & LMP_HOST_LE)
294 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200295
296 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200297 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200298
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200299 if (hdev->ssp_mode > 0)
300 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200301
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200302 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200303}
304
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300305#define EIR_FLAGS 0x01 /* flags */
306#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
307#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
308#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
309#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
310#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
311#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
312#define EIR_NAME_SHORT 0x08 /* shortened local name */
313#define EIR_NAME_COMPLETE 0x09 /* complete local name */
314#define EIR_TX_POWER 0x0A /* transmit power level */
315#define EIR_DEVICE_ID 0x10 /* device ID */
316
317#define PNP_INFO_SVCLASS_ID 0x1200
318
319static u8 bluetooth_base_uuid[] = {
320 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
321 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
322};
323
324static u16 get_uuid16(u8 *uuid128)
325{
326 u32 val;
327 int i;
328
329 for (i = 0; i < 12; i++) {
330 if (bluetooth_base_uuid[i] != uuid128[i])
331 return 0;
332 }
333
334 memcpy(&val, &uuid128[12], 4);
335
336 val = le32_to_cpu(val);
337 if (val > 0xffff)
338 return 0;
339
340 return (u16) val;
341}
342
343static void create_eir(struct hci_dev *hdev, u8 *data)
344{
345 u8 *ptr = data;
346 u16 eir_len = 0;
347 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
348 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200349 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300350 size_t name_len;
351
352 name_len = strlen(hdev->dev_name);
353
354 if (name_len > 0) {
355 /* EIR Data type */
356 if (name_len > 48) {
357 name_len = 48;
358 ptr[1] = EIR_NAME_SHORT;
359 } else
360 ptr[1] = EIR_NAME_COMPLETE;
361
362 /* EIR Data length */
363 ptr[0] = name_len + 1;
364
365 memcpy(ptr + 2, hdev->dev_name, name_len);
366
367 eir_len += (name_len + 2);
368 ptr += (name_len + 2);
369 }
370
371 memset(uuid16_list, 0, sizeof(uuid16_list));
372
373 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200374 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300375 u16 uuid16;
376
377 uuid16 = get_uuid16(uuid->uuid);
378 if (uuid16 == 0)
379 return;
380
381 if (uuid16 < 0x1100)
382 continue;
383
384 if (uuid16 == PNP_INFO_SVCLASS_ID)
385 continue;
386
387 /* Stop if not enough space to put next UUID */
388 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
389 truncated = 1;
390 break;
391 }
392
393 /* Check for duplicates */
394 for (i = 0; uuid16_list[i] != 0; i++)
395 if (uuid16_list[i] == uuid16)
396 break;
397
398 if (uuid16_list[i] == 0) {
399 uuid16_list[i] = uuid16;
400 eir_len += sizeof(u16);
401 }
402 }
403
404 if (uuid16_list[0] != 0) {
405 u8 *length = ptr;
406
407 /* EIR Data type */
408 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
409
410 ptr += 2;
411 eir_len += 2;
412
413 for (i = 0; uuid16_list[i] != 0; i++) {
414 *ptr++ = (uuid16_list[i] & 0x00ff);
415 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
416 }
417
418 /* EIR Data length */
419 *length = (i * sizeof(u16)) + 1;
420 }
421}
422
423static int update_eir(struct hci_dev *hdev)
424{
425 struct hci_cp_write_eir cp;
426
427 if (!(hdev->features[6] & LMP_EXT_INQ))
428 return 0;
429
430 if (hdev->ssp_mode == 0)
431 return 0;
432
433 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
434 return 0;
435
436 memset(&cp, 0, sizeof(cp));
437
438 create_eir(hdev, cp.data);
439
440 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
441 return 0;
442
443 memcpy(hdev->eir, cp.data, sizeof(cp.data));
444
445 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
446}
447
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200448static u8 get_service_classes(struct hci_dev *hdev)
449{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300450 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200451 u8 val = 0;
452
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300453 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200454 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200455
456 return val;
457}
458
459static int update_class(struct hci_dev *hdev)
460{
461 u8 cod[3];
462
463 BT_DBG("%s", hdev->name);
464
465 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
466 return 0;
467
468 cod[0] = hdev->minor_class;
469 cod[1] = hdev->major_class;
470 cod[2] = get_service_classes(hdev);
471
472 if (memcmp(cod, hdev->dev_class, 3) == 0)
473 return 0;
474
475 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
476}
477
Johan Hedberg7d785252011-12-15 00:47:39 +0200478static void service_cache_off(struct work_struct *work)
479{
480 struct hci_dev *hdev = container_of(work, struct hci_dev,
481 service_cache.work);
482
483 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags))
484 return;
485
486 hci_dev_lock(hdev);
487
488 update_eir(hdev);
489 update_class(hdev);
490
491 hci_dev_unlock(hdev);
492}
493
494static void mgmt_init_hdev(struct hci_dev *hdev)
495{
496 if (!test_and_set_bit(HCI_MGMT, &hdev->flags))
497 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
498
499 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->flags))
500 schedule_delayed_work(&hdev->service_cache,
501 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
502}
503
Johan Hedberg03811012010-12-08 00:21:06 +0200504static int read_controller_info(struct sock *sk, u16 index)
505{
506 struct mgmt_rp_read_info rp;
507 struct hci_dev *hdev;
508
509 BT_DBG("sock %p hci%u", sk, index);
510
511 hdev = hci_dev_get(index);
512 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200513 return cmd_status(sk, index, MGMT_OP_READ_INFO,
514 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200515
516 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
517 cancel_delayed_work_sync(&hdev->power_off);
518
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300519 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200520
Johan Hedberg7d785252011-12-15 00:47:39 +0200521 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
522 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200523
524 memset(&rp, 0, sizeof(rp));
525
Johan Hedberg03811012010-12-08 00:21:06 +0200526 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200527
528 rp.version = hdev->hci_ver;
529
Johan Hedberg03811012010-12-08 00:21:06 +0200530 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200531
532 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
533 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
534
535 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200536
537 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
538
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300539 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200540 hci_dev_put(hdev);
541
542 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
543}
544
545static void mgmt_pending_free(struct pending_cmd *cmd)
546{
547 sock_put(cmd->sk);
548 kfree(cmd->param);
549 kfree(cmd);
550}
551
552static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
553 struct hci_dev *hdev,
554 void *data, u16 len)
555{
556 struct pending_cmd *cmd;
557
558 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
559 if (!cmd)
560 return NULL;
561
562 cmd->opcode = opcode;
563 cmd->index = hdev->id;
564
565 cmd->param = kmalloc(len, GFP_ATOMIC);
566 if (!cmd->param) {
567 kfree(cmd);
568 return NULL;
569 }
570
571 if (data)
572 memcpy(cmd->param, data, len);
573
574 cmd->sk = sk;
575 sock_hold(sk);
576
577 list_add(&cmd->list, &hdev->mgmt_pending);
578
579 return cmd;
580}
581
582static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
583 void (*cb)(struct pending_cmd *cmd, void *data),
584 void *data)
585{
586 struct list_head *p, *n;
587
588 list_for_each_safe(p, n, &hdev->mgmt_pending) {
589 struct pending_cmd *cmd;
590
591 cmd = list_entry(p, struct pending_cmd, list);
592
593 if (opcode > 0 && cmd->opcode != opcode)
594 continue;
595
596 cb(cmd, data);
597 }
598}
599
600static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
601{
602 struct pending_cmd *cmd;
603
604 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
605 if (cmd->opcode == opcode)
606 return cmd;
607 }
608
609 return NULL;
610}
611
612static void mgmt_pending_remove(struct pending_cmd *cmd)
613{
614 list_del(&cmd->list);
615 mgmt_pending_free(cmd);
616}
617
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200618static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200619{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200620 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200621
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200622 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200623}
624
Johan Hedberg03811012010-12-08 00:21:06 +0200625static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
626{
627 struct mgmt_mode *cp;
628 struct hci_dev *hdev;
629 struct pending_cmd *cmd;
630 int err, up;
631
632 cp = (void *) data;
633
634 BT_DBG("request for hci%u", index);
635
636 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200637 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
638 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200639
640 hdev = hci_dev_get(index);
641 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200642 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
643 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200644
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300645 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200646
647 up = test_bit(HCI_UP, &hdev->flags);
648 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200649 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200650 goto failed;
651 }
652
653 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200654 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
655 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200656 goto failed;
657 }
658
659 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
660 if (!cmd) {
661 err = -ENOMEM;
662 goto failed;
663 }
664
665 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200666 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200667 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200668 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200669
670 err = 0;
671
672failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300673 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200674 hci_dev_put(hdev);
675 return err;
676}
677
678static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
679 u16 len)
680{
681 struct mgmt_cp_set_discoverable *cp;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200682 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200683 struct pending_cmd *cmd;
684 u8 scan;
685 int err;
686
687 cp = (void *) data;
688
689 BT_DBG("request for hci%u", index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200690
691 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200692 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
693 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200694
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200695 hdev = hci_dev_get(index);
696 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200697 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
698 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200699
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300700 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200701
702 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200703 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
704 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200705 goto failed;
706 }
707
708 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
709 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200710 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
711 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200712 goto failed;
713 }
714
715 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
716 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200717 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200718 goto failed;
719 }
720
721 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
722 if (!cmd) {
723 err = -ENOMEM;
724 goto failed;
725 }
726
727 scan = SCAN_PAGE;
728
729 if (cp->val)
730 scan |= SCAN_INQUIRY;
731 else
732 cancel_delayed_work(&hdev->discov_off);
733
734 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
735 if (err < 0)
736 mgmt_pending_remove(cmd);
737
Johan Hedberg03811012010-12-08 00:21:06 +0200738 if (cp->val)
739 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
740
Johan Hedberge41d8b42010-12-13 21:07:03 +0200741failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300742 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200743 hci_dev_put(hdev);
744
745 return err;
746}
747
748static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
749 u16 len)
750{
751 struct mgmt_mode *cp;
752 struct hci_dev *hdev;
753 struct pending_cmd *cmd;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200754 u8 scan;
755 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200756
757 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200758
759 BT_DBG("request for hci%u", index);
760
761 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200762 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
763 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200764
765 hdev = hci_dev_get(index);
766 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200767 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
768 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200769
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300770 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200771
772 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200773 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
774 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200775 goto failed;
776 }
777
778 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
779 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200780 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
781 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200782 goto failed;
783 }
784
785 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200786 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200787 goto failed;
788 }
789
790 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
791 if (!cmd) {
792 err = -ENOMEM;
793 goto failed;
794 }
795
796 if (cp->val)
797 scan = SCAN_PAGE;
798 else
799 scan = 0;
800
801 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
802 if (err < 0)
803 mgmt_pending_remove(cmd);
804
805failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300806 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200807 hci_dev_put(hdev);
808
809 return err;
810}
811
812static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
813 u16 data_len, struct sock *skip_sk)
814{
815 struct sk_buff *skb;
816 struct mgmt_hdr *hdr;
817
818 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
819 if (!skb)
820 return -ENOMEM;
821
822 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
823
824 hdr = (void *) skb_put(skb, sizeof(*hdr));
825 hdr->opcode = cpu_to_le16(event);
826 if (hdev)
827 hdr->index = cpu_to_le16(hdev->id);
828 else
829 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
830 hdr->len = cpu_to_le16(data_len);
831
832 if (data)
833 memcpy(skb_put(skb, data_len), data, data_len);
834
835 hci_send_to_sock(NULL, skb, skip_sk);
836 kfree_skb(skb);
837
838 return 0;
839}
840
Johan Hedberg73f22f62010-12-29 16:00:25 +0200841static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
842 u16 len)
843{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200844 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200845 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200846 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200847 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200848
849 cp = (void *) data;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200850
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200851 BT_DBG("request for hci%u", index);
852
853 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200854 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
855 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200856
857 hdev = hci_dev_get(index);
858 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200859 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
860 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200861
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300862 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200863
864 if (cp->val)
865 set_bit(HCI_PAIRABLE, &hdev->flags);
866 else
867 clear_bit(HCI_PAIRABLE, &hdev->flags);
868
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200869 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200870 if (err < 0)
871 goto failed;
872
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200873 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200874
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200875 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200876
877failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300878 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200879 hci_dev_put(hdev);
880
881 return err;
882}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200883
Szymon Janc4e51eae2011-02-25 19:05:48 +0100884static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200885{
886 struct mgmt_cp_add_uuid *cp;
887 struct hci_dev *hdev;
888 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200889 int err;
890
891 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200892
Szymon Janc4e51eae2011-02-25 19:05:48 +0100893 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200894
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100895 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200896 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
897 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100898
Szymon Janc4e51eae2011-02-25 19:05:48 +0100899 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200900 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200901 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
902 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200903
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300904 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200905
906 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
907 if (!uuid) {
908 err = -ENOMEM;
909 goto failed;
910 }
911
912 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200913 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200914
915 list_add(&uuid->list, &hdev->uuids);
916
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200917 err = update_class(hdev);
918 if (err < 0)
919 goto failed;
920
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300921 err = update_eir(hdev);
922 if (err < 0)
923 goto failed;
924
Szymon Janc4e51eae2011-02-25 19:05:48 +0100925 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200926
927failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300928 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200929 hci_dev_put(hdev);
930
931 return err;
932}
933
Szymon Janc4e51eae2011-02-25 19:05:48 +0100934static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200935{
936 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100937 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200938 struct hci_dev *hdev;
939 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 +0200940 int err, found;
941
942 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200943
Szymon Janc4e51eae2011-02-25 19:05:48 +0100944 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200945
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100946 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200947 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
948 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100949
Szymon Janc4e51eae2011-02-25 19:05:48 +0100950 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200951 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200952 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
953 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200954
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300955 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200956
957 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
958 err = hci_uuids_clear(hdev);
959 goto unlock;
960 }
961
962 found = 0;
963
964 list_for_each_safe(p, n, &hdev->uuids) {
965 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
966
967 if (memcmp(match->uuid, cp->uuid, 16) != 0)
968 continue;
969
970 list_del(&match->list);
971 found++;
972 }
973
974 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200975 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
976 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200977 goto unlock;
978 }
979
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200980 err = update_class(hdev);
981 if (err < 0)
982 goto unlock;
983
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300984 err = update_eir(hdev);
985 if (err < 0)
986 goto unlock;
987
Szymon Janc4e51eae2011-02-25 19:05:48 +0100988 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200989
990unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300991 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200992 hci_dev_put(hdev);
993
994 return err;
995}
996
Szymon Janc4e51eae2011-02-25 19:05:48 +0100997static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
998 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200999{
1000 struct hci_dev *hdev;
1001 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001002 int err;
1003
1004 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001005
Szymon Janc4e51eae2011-02-25 19:05:48 +01001006 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001007
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001008 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001009 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1010 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001011
Szymon Janc4e51eae2011-02-25 19:05:48 +01001012 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001013 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001014 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1015 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001016
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001017 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001018
1019 hdev->major_class = cp->major;
1020 hdev->minor_class = cp->minor;
1021
Johan Hedberg7d785252011-12-15 00:47:39 +02001022 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) {
1023 hci_dev_unlock(hdev);
1024 cancel_delayed_work_sync(&hdev->service_cache);
1025 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001026 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001027 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001028
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001029 err = update_class(hdev);
1030
1031 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001032 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001033
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001034 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001035 hci_dev_put(hdev);
1036
1037 return err;
1038}
1039
Johan Hedberg86742e12011-11-07 23:13:38 +02001040static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
1041 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001042{
1043 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001044 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001045 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001046 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001047
1048 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001049
1050 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001051 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1052 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001053
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001054 key_count = get_unaligned_le16(&cp->key_count);
1055
Johan Hedberg86742e12011-11-07 23:13:38 +02001056 expected_len = sizeof(*cp) + key_count *
1057 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001058 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001059 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001060 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001061 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1062 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001063 }
1064
Szymon Janc4e51eae2011-02-25 19:05:48 +01001065 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001066 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001067 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1068 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001069
Szymon Janc4e51eae2011-02-25 19:05:48 +01001070 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001071 key_count);
1072
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001073 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001074
1075 hci_link_keys_clear(hdev);
1076
1077 set_bit(HCI_LINK_KEYS, &hdev->flags);
1078
1079 if (cp->debug_keys)
1080 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1081 else
1082 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1083
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001084 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001085 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001086
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001087 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001088 key->pin_len);
1089 }
1090
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001091 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1092
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001093 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001094 hci_dev_put(hdev);
1095
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001096 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001097}
1098
Johan Hedberg86742e12011-11-07 23:13:38 +02001099static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
1100 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001101{
1102 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001103 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001104 struct mgmt_rp_remove_keys rp;
1105 struct hci_cp_disconnect dc;
1106 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001107 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001108 int err;
1109
1110 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001111
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001112 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001113 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1114 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001115
Szymon Janc4e51eae2011-02-25 19:05:48 +01001116 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001117 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001118 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1119 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001120
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001121 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001122
Johan Hedberga8a1d192011-11-10 15:54:38 +02001123 memset(&rp, 0, sizeof(rp));
1124 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001125 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001126
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001127 err = hci_remove_link_key(hdev, &cp->bdaddr);
1128 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001129 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001130 goto unlock;
1131 }
1132
Johan Hedberga8a1d192011-11-10 15:54:38 +02001133 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1134 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1135 sizeof(rp));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001136 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001137 }
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001138
1139 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001140 if (!conn) {
1141 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1142 sizeof(rp));
1143 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001144 }
1145
Johan Hedberga8a1d192011-11-10 15:54:38 +02001146 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1147 if (!cmd) {
1148 err = -ENOMEM;
1149 goto unlock;
1150 }
1151
1152 put_unaligned_le16(conn->handle, &dc.handle);
1153 dc.reason = 0x13; /* Remote User Terminated Connection */
1154 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1155 if (err < 0)
1156 mgmt_pending_remove(cmd);
1157
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001158unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001159 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001160 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1161 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001162 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001163 hci_dev_put(hdev);
1164
1165 return err;
1166}
1167
Szymon Janc4e51eae2011-02-25 19:05:48 +01001168static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001169{
1170 struct hci_dev *hdev;
1171 struct mgmt_cp_disconnect *cp;
1172 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001173 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001174 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001175 int err;
1176
1177 BT_DBG("");
1178
1179 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001180
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001181 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001182 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1183 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001184
Szymon Janc4e51eae2011-02-25 19:05:48 +01001185 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001186 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001187 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1188 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001189
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001190 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001191
1192 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001193 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1194 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001195 goto failed;
1196 }
1197
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001198 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001199 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1200 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001201 goto failed;
1202 }
1203
1204 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001205 if (!conn)
1206 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1207
Johan Hedberg8962ee72011-01-20 12:40:27 +02001208 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001209 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1210 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001211 goto failed;
1212 }
1213
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001214 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001215 if (!cmd) {
1216 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001217 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001218 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001219
1220 put_unaligned_le16(conn->handle, &dc.handle);
1221 dc.reason = 0x13; /* Remote User Terminated Connection */
1222
1223 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1224 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001225 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001226
1227failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001228 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001229 hci_dev_put(hdev);
1230
1231 return err;
1232}
1233
Johan Hedberg48264f02011-11-09 13:58:58 +02001234static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001235{
1236 switch (link_type) {
1237 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001238 switch (addr_type) {
1239 case ADDR_LE_DEV_PUBLIC:
1240 return MGMT_ADDR_LE_PUBLIC;
1241 case ADDR_LE_DEV_RANDOM:
1242 return MGMT_ADDR_LE_RANDOM;
1243 default:
1244 return MGMT_ADDR_INVALID;
1245 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001246 case ACL_LINK:
1247 return MGMT_ADDR_BREDR;
1248 default:
1249 return MGMT_ADDR_INVALID;
1250 }
1251}
1252
Szymon Janc8ce62842011-03-01 16:55:32 +01001253static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001254{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001255 struct mgmt_rp_get_connections *rp;
1256 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001257 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001258 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001259 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001260 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001261 int i, err;
1262
1263 BT_DBG("");
1264
Szymon Janc4e51eae2011-02-25 19:05:48 +01001265 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001266 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001267 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1268 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001269
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001270 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001271
1272 count = 0;
1273 list_for_each(p, &hdev->conn_hash.list) {
1274 count++;
1275 }
1276
Johan Hedberg4c659c32011-11-07 23:13:39 +02001277 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001278 rp = kmalloc(rp_len, GFP_ATOMIC);
1279 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001280 err = -ENOMEM;
1281 goto unlock;
1282 }
1283
Johan Hedberg2784eb42011-01-21 13:56:35 +02001284 put_unaligned_le16(count, &rp->conn_count);
1285
Johan Hedberg2784eb42011-01-21 13:56:35 +02001286 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001287 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1288 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001289 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001290 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1291 continue;
1292 i++;
1293 }
1294
1295 /* Recalculate length in case of filtered SCO connections, etc */
1296 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001297
Szymon Janc4e51eae2011-02-25 19:05:48 +01001298 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001299
1300unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001301 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001302 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001303 hci_dev_put(hdev);
1304 return err;
1305}
1306
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001307static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1308 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1309{
1310 struct pending_cmd *cmd;
1311 int err;
1312
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001313 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001314 sizeof(*cp));
1315 if (!cmd)
1316 return -ENOMEM;
1317
1318 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1319 &cp->bdaddr);
1320 if (err < 0)
1321 mgmt_pending_remove(cmd);
1322
1323 return err;
1324}
1325
Szymon Janc4e51eae2011-02-25 19:05:48 +01001326static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1327 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001328{
1329 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001330 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001331 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001332 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001333 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001334 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001335 int err;
1336
1337 BT_DBG("");
1338
1339 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001340
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001341 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001342 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1343 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001344
Szymon Janc4e51eae2011-02-25 19:05:48 +01001345 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001346 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001347 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1348 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001349
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001350 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001351
1352 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001353 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1354 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001355 goto failed;
1356 }
1357
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001358 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1359 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001360 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1361 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001362 goto failed;
1363 }
1364
1365 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1366 bacpy(&ncp.bdaddr, &cp->bdaddr);
1367
1368 BT_ERR("PIN code is not 16 bytes long");
1369
1370 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1371 if (err >= 0)
1372 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001373 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001374
1375 goto failed;
1376 }
1377
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001378 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001379 if (!cmd) {
1380 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001381 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001382 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001383
1384 bacpy(&reply.bdaddr, &cp->bdaddr);
1385 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001386 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001387
1388 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1389 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001390 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001391
1392failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001393 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001394 hci_dev_put(hdev);
1395
1396 return err;
1397}
1398
Szymon Janc4e51eae2011-02-25 19:05:48 +01001399static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1400 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001401{
1402 struct hci_dev *hdev;
1403 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001404 int err;
1405
1406 BT_DBG("");
1407
1408 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001409
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001410 if (len != sizeof(*cp))
1411 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001412 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001413
Szymon Janc4e51eae2011-02-25 19:05:48 +01001414 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001415 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001416 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001417 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001418
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001419 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001420
1421 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001422 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001423 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001424 goto failed;
1425 }
1426
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001427 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001428
1429failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001430 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001431 hci_dev_put(hdev);
1432
1433 return err;
1434}
1435
Szymon Janc4e51eae2011-02-25 19:05:48 +01001436static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1437 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001438{
1439 struct hci_dev *hdev;
1440 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001441
1442 BT_DBG("");
1443
1444 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001445
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001446 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001447 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1448 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001449
Szymon Janc4e51eae2011-02-25 19:05:48 +01001450 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001451 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001452 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1453 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001454
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001455 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001456
1457 hdev->io_capability = cp->io_capability;
1458
1459 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001460 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001461
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001462 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001463 hci_dev_put(hdev);
1464
Szymon Janc4e51eae2011-02-25 19:05:48 +01001465 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001466}
1467
Johan Hedberge9a416b2011-02-19 12:05:56 -03001468static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1469{
1470 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001471 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001472
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001473 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001474 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1475 continue;
1476
Johan Hedberge9a416b2011-02-19 12:05:56 -03001477 if (cmd->user_data != conn)
1478 continue;
1479
1480 return cmd;
1481 }
1482
1483 return NULL;
1484}
1485
1486static void pairing_complete(struct pending_cmd *cmd, u8 status)
1487{
1488 struct mgmt_rp_pair_device rp;
1489 struct hci_conn *conn = cmd->user_data;
1490
Johan Hedbergba4e5642011-11-11 00:07:34 +02001491 bacpy(&rp.addr.bdaddr, &conn->dst);
1492 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001493 rp.status = status;
1494
Szymon Janc4e51eae2011-02-25 19:05:48 +01001495 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001496
1497 /* So we don't get further callbacks for this connection */
1498 conn->connect_cfm_cb = NULL;
1499 conn->security_cfm_cb = NULL;
1500 conn->disconn_cfm_cb = NULL;
1501
1502 hci_conn_put(conn);
1503
Johan Hedberga664b5b2011-02-19 12:06:02 -03001504 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001505}
1506
1507static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1508{
1509 struct pending_cmd *cmd;
1510
1511 BT_DBG("status %u", status);
1512
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001513 cmd = find_pairing(conn);
1514 if (!cmd)
1515 BT_DBG("Unable to find a pending command");
1516 else
1517 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001518}
1519
Szymon Janc4e51eae2011-02-25 19:05:48 +01001520static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001521{
1522 struct hci_dev *hdev;
1523 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001524 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001525 struct pending_cmd *cmd;
1526 u8 sec_level, auth_type;
1527 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001528 int err;
1529
1530 BT_DBG("");
1531
1532 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001533
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001534 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001535 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1536 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001537
Szymon Janc4e51eae2011-02-25 19:05:48 +01001538 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001539 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001540 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1541 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001542
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001543 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001544
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001545 sec_level = BT_SECURITY_MEDIUM;
1546 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001547 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001548 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001549 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001550
Johan Hedbergba4e5642011-11-11 00:07:34 +02001551 if (cp->addr.type == MGMT_ADDR_BREDR)
1552 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001553 auth_type);
1554 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001555 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001556 auth_type);
1557
Johan Hedberg1425acb2011-11-11 00:07:35 +02001558 memset(&rp, 0, sizeof(rp));
1559 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1560 rp.addr.type = cp->addr.type;
1561
Ville Tervo30e76272011-02-22 16:10:53 -03001562 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001563 rp.status = -PTR_ERR(conn);
1564 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1565 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001566 goto unlock;
1567 }
1568
1569 if (conn->connect_cfm_cb) {
1570 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001571 rp.status = EBUSY;
1572 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1573 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001574 goto unlock;
1575 }
1576
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001577 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001578 if (!cmd) {
1579 err = -ENOMEM;
1580 hci_conn_put(conn);
1581 goto unlock;
1582 }
1583
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001584 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001585 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001586 conn->connect_cfm_cb = pairing_complete_cb;
1587
Johan Hedberge9a416b2011-02-19 12:05:56 -03001588 conn->security_cfm_cb = pairing_complete_cb;
1589 conn->disconn_cfm_cb = pairing_complete_cb;
1590 conn->io_capability = cp->io_cap;
1591 cmd->user_data = conn;
1592
1593 if (conn->state == BT_CONNECTED &&
1594 hci_conn_security(conn, sec_level, auth_type))
1595 pairing_complete(cmd, 0);
1596
1597 err = 0;
1598
1599unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001600 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001601 hci_dev_put(hdev);
1602
1603 return err;
1604}
1605
Brian Gix0df4c182011-11-16 13:53:13 -08001606static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1607 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001608{
Johan Hedberga5c29682011-02-19 12:05:57 -03001609 struct pending_cmd *cmd;
1610 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001611 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001612 int err;
1613
Szymon Janc4e51eae2011-02-25 19:05:48 +01001614 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001615 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001616 return cmd_status(sk, index, mgmt_op,
1617 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001618
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001619 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001620
Johan Hedberga5c29682011-02-19 12:05:57 -03001621 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001622 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1623 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001624 }
1625
Brian Gix47c15e22011-11-16 13:53:14 -08001626 /*
1627 * Check for an existing ACL link, if present pair via
1628 * HCI commands.
1629 *
1630 * If no ACL link is present, check for an LE link and if
1631 * present, pair via the SMP engine.
1632 *
1633 * If neither ACL nor LE links are present, fail with error.
1634 */
1635 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1636 if (!conn) {
1637 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1638 if (!conn) {
1639 err = cmd_status(sk, index, mgmt_op,
1640 MGMT_STATUS_NOT_CONNECTED);
1641 goto done;
1642 }
1643
1644 /* Continue with pairing via SMP */
1645
1646 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_SUCCESS);
1647 goto done;
1648 }
1649
Brian Gix0df4c182011-11-16 13:53:13 -08001650 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001651 if (!cmd) {
1652 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001653 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001654 }
1655
Brian Gix0df4c182011-11-16 13:53:13 -08001656 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001657 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1658 struct hci_cp_user_passkey_reply cp;
1659
1660 bacpy(&cp.bdaddr, bdaddr);
1661 cp.passkey = passkey;
1662 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1663 } else
1664 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1665
Johan Hedberga664b5b2011-02-19 12:06:02 -03001666 if (err < 0)
1667 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001668
Brian Gix0df4c182011-11-16 13:53:13 -08001669done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001670 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001671 hci_dev_put(hdev);
1672
1673 return err;
1674}
1675
Brian Gix0df4c182011-11-16 13:53:13 -08001676static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1677{
1678 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1679
1680 BT_DBG("");
1681
1682 if (len != sizeof(*cp))
1683 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1684 MGMT_STATUS_INVALID_PARAMS);
1685
1686 return user_pairing_resp(sk, index, &cp->bdaddr,
1687 MGMT_OP_USER_CONFIRM_REPLY,
1688 HCI_OP_USER_CONFIRM_REPLY, 0);
1689}
1690
1691static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1692 u16 len)
1693{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001694 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001695
1696 BT_DBG("");
1697
1698 if (len != sizeof(*cp))
1699 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1700 MGMT_STATUS_INVALID_PARAMS);
1701
1702 return user_pairing_resp(sk, index, &cp->bdaddr,
1703 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1704 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1705}
1706
Brian Gix604086b2011-11-23 08:28:33 -08001707static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1708{
1709 struct mgmt_cp_user_passkey_reply *cp = (void *) data;
1710
1711 BT_DBG("");
1712
1713 if (len != sizeof(*cp))
1714 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1715 EINVAL);
1716
1717 return user_pairing_resp(sk, index, &cp->bdaddr,
1718 MGMT_OP_USER_PASSKEY_REPLY,
1719 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1720}
1721
1722static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1723 u16 len)
1724{
1725 struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data;
1726
1727 BT_DBG("");
1728
1729 if (len != sizeof(*cp))
1730 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1731 EINVAL);
1732
1733 return user_pairing_resp(sk, index, &cp->bdaddr,
1734 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1735 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1736}
1737
Johan Hedbergb312b1612011-03-16 14:29:37 +02001738static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1739 u16 len)
1740{
1741 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1742 struct hci_cp_write_local_name hci_cp;
1743 struct hci_dev *hdev;
1744 struct pending_cmd *cmd;
1745 int err;
1746
1747 BT_DBG("");
1748
1749 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001750 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1751 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001752
1753 hdev = hci_dev_get(index);
1754 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001755 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1756 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001757
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001758 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001759
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001760 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001761 if (!cmd) {
1762 err = -ENOMEM;
1763 goto failed;
1764 }
1765
1766 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1767 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1768 &hci_cp);
1769 if (err < 0)
1770 mgmt_pending_remove(cmd);
1771
1772failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001773 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001774 hci_dev_put(hdev);
1775
1776 return err;
1777}
1778
Szymon Jancc35938b2011-03-22 13:12:21 +01001779static int read_local_oob_data(struct sock *sk, u16 index)
1780{
1781 struct hci_dev *hdev;
1782 struct pending_cmd *cmd;
1783 int err;
1784
1785 BT_DBG("hci%u", index);
1786
1787 hdev = hci_dev_get(index);
1788 if (!hdev)
1789 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001790 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001791
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001792 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001793
1794 if (!test_bit(HCI_UP, &hdev->flags)) {
1795 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001796 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001797 goto unlock;
1798 }
1799
1800 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1801 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001802 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001803 goto unlock;
1804 }
1805
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001806 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001807 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1808 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001809 goto unlock;
1810 }
1811
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001812 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001813 if (!cmd) {
1814 err = -ENOMEM;
1815 goto unlock;
1816 }
1817
1818 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1819 if (err < 0)
1820 mgmt_pending_remove(cmd);
1821
1822unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001823 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001824 hci_dev_put(hdev);
1825
1826 return err;
1827}
1828
Szymon Janc2763eda2011-03-22 13:12:22 +01001829static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1830 u16 len)
1831{
1832 struct hci_dev *hdev;
1833 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1834 int err;
1835
1836 BT_DBG("hci%u ", index);
1837
1838 if (len != sizeof(*cp))
1839 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001840 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001841
1842 hdev = hci_dev_get(index);
1843 if (!hdev)
1844 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001845 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001846
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001847 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001848
1849 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1850 cp->randomizer);
1851 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001852 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1853 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001854 else
1855 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1856 0);
1857
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001858 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001859 hci_dev_put(hdev);
1860
1861 return err;
1862}
1863
1864static int remove_remote_oob_data(struct sock *sk, u16 index,
1865 unsigned char *data, u16 len)
1866{
1867 struct hci_dev *hdev;
1868 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1869 int err;
1870
1871 BT_DBG("hci%u ", index);
1872
1873 if (len != sizeof(*cp))
1874 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001875 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001876
1877 hdev = hci_dev_get(index);
1878 if (!hdev)
1879 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001880 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001881
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001882 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001883
1884 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1885 if (err < 0)
1886 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001887 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001888 else
1889 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1890 NULL, 0);
1891
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001892 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001893 hci_dev_put(hdev);
1894
1895 return err;
1896}
1897
Johan Hedberg450dfda2011-11-12 11:58:22 +02001898static int start_discovery(struct sock *sk, u16 index,
1899 unsigned char *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001900{
Johan Hedberg450dfda2011-11-12 11:58:22 +02001901 struct mgmt_cp_start_discovery *cp = (void *) data;
Johan Hedberg14a53662011-04-27 10:29:56 -04001902 struct pending_cmd *cmd;
1903 struct hci_dev *hdev;
1904 int err;
1905
1906 BT_DBG("hci%u", index);
1907
Johan Hedberg450dfda2011-11-12 11:58:22 +02001908 if (len != sizeof(*cp))
1909 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1910 MGMT_STATUS_INVALID_PARAMS);
1911
Johan Hedberg14a53662011-04-27 10:29:56 -04001912 hdev = hci_dev_get(index);
1913 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001914 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1915 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001916
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001917 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001918
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001919 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001920 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1921 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001922 goto failed;
1923 }
1924
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001925 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001926 if (!cmd) {
1927 err = -ENOMEM;
1928 goto failed;
1929 }
1930
Andre Guedes2519a1f2011-11-07 11:45:24 -03001931 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001932 if (err < 0)
1933 mgmt_pending_remove(cmd);
1934
1935failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001936 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001937 hci_dev_put(hdev);
1938
1939 return err;
1940}
1941
1942static int stop_discovery(struct sock *sk, u16 index)
1943{
1944 struct hci_dev *hdev;
1945 struct pending_cmd *cmd;
1946 int err;
1947
1948 BT_DBG("hci%u", index);
1949
1950 hdev = hci_dev_get(index);
1951 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001952 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1953 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001954
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001955 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001956
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001957 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001958 if (!cmd) {
1959 err = -ENOMEM;
1960 goto failed;
1961 }
1962
Andre Guedes023d5042011-11-04 14:16:52 -03001963 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001964 if (err < 0)
1965 mgmt_pending_remove(cmd);
1966
1967failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001968 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001969 hci_dev_put(hdev);
1970
1971 return err;
1972}
1973
Antti Julku7fbec222011-06-15 12:01:15 +03001974static int block_device(struct sock *sk, u16 index, unsigned char *data,
1975 u16 len)
1976{
1977 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001978 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001979 int err;
1980
1981 BT_DBG("hci%u", index);
1982
Antti Julku7fbec222011-06-15 12:01:15 +03001983 if (len != sizeof(*cp))
1984 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001985 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001986
1987 hdev = hci_dev_get(index);
1988 if (!hdev)
1989 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001990 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001991
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001992 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03001993
Antti Julku7fbec222011-06-15 12:01:15 +03001994 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001995 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001996 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1997 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03001998 else
1999 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2000 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002001
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002002 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002003 hci_dev_put(hdev);
2004
2005 return err;
2006}
2007
2008static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
2009 u16 len)
2010{
2011 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03002012 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03002013 int err;
2014
2015 BT_DBG("hci%u", index);
2016
Antti Julku7fbec222011-06-15 12:01:15 +03002017 if (len != sizeof(*cp))
2018 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002019 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002020
2021 hdev = hci_dev_get(index);
2022 if (!hdev)
2023 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002024 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002025
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002026 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002027
Antti Julku7fbec222011-06-15 12:01:15 +03002028 err = hci_blacklist_del(hdev, &cp->bdaddr);
2029
2030 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002031 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2032 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002033 else
2034 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2035 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002036
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002037 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002038 hci_dev_put(hdev);
2039
2040 return err;
2041}
2042
Antti Julkuf6422ec2011-06-22 13:11:56 +03002043static int set_fast_connectable(struct sock *sk, u16 index,
2044 unsigned char *data, u16 len)
2045{
2046 struct hci_dev *hdev;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002047 struct mgmt_mode *cp = (void *) data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002048 struct hci_cp_write_page_scan_activity acp;
2049 u8 type;
2050 int err;
2051
2052 BT_DBG("hci%u", index);
2053
2054 if (len != sizeof(*cp))
2055 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002056 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002057
2058 hdev = hci_dev_get(index);
2059 if (!hdev)
2060 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002061 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002062
2063 hci_dev_lock(hdev);
2064
Johan Hedbergf7c68692011-12-15 00:47:36 +02002065 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002066 type = PAGE_SCAN_TYPE_INTERLACED;
2067 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2068 } else {
2069 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2070 acp.interval = 0x0800; /* default 1.28 sec page scan */
2071 }
2072
2073 acp.window = 0x0012; /* default 11.25 msec page scan window */
2074
2075 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2076 sizeof(acp), &acp);
2077 if (err < 0) {
2078 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002079 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002080 goto done;
2081 }
2082
2083 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2084 if (err < 0) {
2085 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002086 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002087 goto done;
2088 }
2089
2090 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2091 NULL, 0);
2092done:
2093 hci_dev_unlock(hdev);
2094 hci_dev_put(hdev);
2095
2096 return err;
2097}
2098
Johan Hedberg03811012010-12-08 00:21:06 +02002099int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2100{
2101 unsigned char *buf;
2102 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002103 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002104 int err;
2105
2106 BT_DBG("got %zu bytes", msglen);
2107
2108 if (msglen < sizeof(*hdr))
2109 return -EINVAL;
2110
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002111 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002112 if (!buf)
2113 return -ENOMEM;
2114
2115 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2116 err = -EFAULT;
2117 goto done;
2118 }
2119
2120 hdr = (struct mgmt_hdr *) buf;
2121 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002122 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002123 len = get_unaligned_le16(&hdr->len);
2124
2125 if (len != msglen - sizeof(*hdr)) {
2126 err = -EINVAL;
2127 goto done;
2128 }
2129
2130 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002131 case MGMT_OP_READ_VERSION:
2132 err = read_version(sk);
2133 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002134 case MGMT_OP_READ_INDEX_LIST:
2135 err = read_index_list(sk);
2136 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002137 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002138 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002139 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002140 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002141 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002142 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002143 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002144 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002145 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002146 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002147 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002148 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002149 case MGMT_OP_SET_FAST_CONNECTABLE:
2150 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
2151 len);
2152 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002153 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002154 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002155 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002156 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002157 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002158 break;
2159 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002160 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002161 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002162 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002163 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002164 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002165 case MGMT_OP_LOAD_LINK_KEYS:
2166 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002167 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002168 case MGMT_OP_REMOVE_KEYS:
2169 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002170 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002171 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002172 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002173 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002174 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002175 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002176 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002177 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002178 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002179 break;
2180 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002181 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002182 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002183 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002184 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002185 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002186 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002187 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002188 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002189 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002190 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002191 break;
2192 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002193 err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr),
2194 len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002195 break;
Brian Gix604086b2011-11-23 08:28:33 -08002196 case MGMT_OP_USER_PASSKEY_REPLY:
2197 err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len);
2198 break;
2199 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
2200 err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr),
2201 len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002202 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002203 case MGMT_OP_SET_LOCAL_NAME:
2204 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2205 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002206 case MGMT_OP_READ_LOCAL_OOB_DATA:
2207 err = read_local_oob_data(sk, index);
2208 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002209 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2210 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2211 break;
2212 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2213 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2214 len);
2215 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002216 case MGMT_OP_START_DISCOVERY:
Johan Hedberg450dfda2011-11-12 11:58:22 +02002217 err = start_discovery(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002218 break;
2219 case MGMT_OP_STOP_DISCOVERY:
2220 err = stop_discovery(sk, index);
2221 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002222 case MGMT_OP_BLOCK_DEVICE:
2223 err = block_device(sk, index, buf + sizeof(*hdr), len);
2224 break;
2225 case MGMT_OP_UNBLOCK_DEVICE:
2226 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
2227 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002228 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002229 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002230 err = cmd_status(sk, index, opcode,
2231 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002232 break;
2233 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002234
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002235 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002236 goto done;
2237
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002238 err = msglen;
2239
2240done:
2241 kfree(buf);
2242 return err;
2243}
2244
Johan Hedbergb24752f2011-11-03 14:40:33 +02002245static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2246{
2247 u8 *status = data;
2248
2249 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2250 mgmt_pending_remove(cmd);
2251}
2252
Johan Hedberg744cf192011-11-08 20:40:14 +02002253int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002254{
Johan Hedberg744cf192011-11-08 20:40:14 +02002255 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002256}
2257
Johan Hedberg744cf192011-11-08 20:40:14 +02002258int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002259{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002260 u8 status = ENODEV;
2261
Johan Hedberg744cf192011-11-08 20:40:14 +02002262 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002263
Johan Hedberg744cf192011-11-08 20:40:14 +02002264 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002265}
2266
2267struct cmd_lookup {
2268 u8 val;
2269 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002270 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002271};
2272
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002273static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002274{
Johan Hedberg03811012010-12-08 00:21:06 +02002275 struct cmd_lookup *match = data;
2276
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002277 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002278
2279 list_del(&cmd->list);
2280
2281 if (match->sk == NULL) {
2282 match->sk = cmd->sk;
2283 sock_hold(match->sk);
2284 }
2285
2286 mgmt_pending_free(cmd);
2287}
2288
Johan Hedberg744cf192011-11-08 20:40:14 +02002289int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002290{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002291 struct cmd_lookup match = { powered, NULL, hdev };
2292 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002293 int ret;
2294
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002295 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002296
Johan Hedbergb24752f2011-11-03 14:40:33 +02002297 if (!powered) {
2298 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002299 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002300 }
2301
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002302 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002303
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002304 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2305 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002306
2307 if (match.sk)
2308 sock_put(match.sk);
2309
2310 return ret;
2311}
2312
Johan Hedberg744cf192011-11-08 20:40:14 +02002313int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002314{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002315 struct cmd_lookup match = { discoverable, NULL, hdev };
2316 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002317 int ret;
2318
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002319 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002320
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002321 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002322
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002323 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002324 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002325 if (match.sk)
2326 sock_put(match.sk);
2327
2328 return ret;
2329}
2330
Johan Hedberg744cf192011-11-08 20:40:14 +02002331int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002332{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002333 __le32 ev;
2334 struct cmd_lookup match = { connectable, NULL, hdev };
Johan Hedberg03811012010-12-08 00:21:06 +02002335 int ret;
2336
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002337 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2338 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002339
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002340 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002341
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002342 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002343
2344 if (match.sk)
2345 sock_put(match.sk);
2346
2347 return ret;
2348}
2349
Johan Hedberg744cf192011-11-08 20:40:14 +02002350int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002351{
Johan Hedbergca69b792011-11-11 18:10:00 +02002352 u8 mgmt_err = mgmt_status(status);
2353
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002354 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002355 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002356 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002357
2358 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002359 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002360 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002361
2362 return 0;
2363}
2364
Johan Hedberg744cf192011-11-08 20:40:14 +02002365int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2366 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002367{
Johan Hedberg86742e12011-11-07 23:13:38 +02002368 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002369
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002370 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002371
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002372 ev.store_hint = persistent;
2373 bacpy(&ev.key.bdaddr, &key->bdaddr);
2374 ev.key.type = key->type;
2375 memcpy(ev.key.val, key->val, 16);
2376 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002377
Johan Hedberg744cf192011-11-08 20:40:14 +02002378 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002379}
Johan Hedbergf7520542011-01-20 12:34:39 +02002380
Johan Hedberg48264f02011-11-09 13:58:58 +02002381int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2382 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002383{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002384 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002385
Johan Hedbergf7520542011-01-20 12:34:39 +02002386 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002387 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002388
Johan Hedberg744cf192011-11-08 20:40:14 +02002389 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002390}
2391
Johan Hedberg8962ee72011-01-20 12:40:27 +02002392static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2393{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002394 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002395 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002396 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002397
Johan Hedberga38528f2011-01-22 06:46:43 +02002398 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002399 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002400
Szymon Janc4e51eae2011-02-25 19:05:48 +01002401 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002402
2403 *sk = cmd->sk;
2404 sock_hold(*sk);
2405
Johan Hedberga664b5b2011-02-19 12:06:02 -03002406 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002407}
2408
Johan Hedberga8a1d192011-11-10 15:54:38 +02002409static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2410{
2411 u8 *status = data;
2412 struct mgmt_cp_remove_keys *cp = cmd->param;
2413 struct mgmt_rp_remove_keys rp;
2414
2415 memset(&rp, 0, sizeof(rp));
2416 bacpy(&rp.bdaddr, &cp->bdaddr);
2417 if (status != NULL)
2418 rp.status = *status;
2419
2420 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2421 sizeof(rp));
2422
2423 mgmt_pending_remove(cmd);
2424}
2425
Johan Hedberg48264f02011-11-09 13:58:58 +02002426int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2427 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002428{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002429 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002430 struct sock *sk = NULL;
2431 int err;
2432
Johan Hedberg744cf192011-11-08 20:40:14 +02002433 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002434
Johan Hedbergf7520542011-01-20 12:34:39 +02002435 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002436 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002437
Johan Hedberg744cf192011-11-08 20:40:14 +02002438 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002439
2440 if (sk)
2441 sock_put(sk);
2442
Johan Hedberga8a1d192011-11-10 15:54:38 +02002443 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2444
Johan Hedberg8962ee72011-01-20 12:40:27 +02002445 return err;
2446}
2447
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002448int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002449{
2450 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002451 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002452 int err;
2453
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002454 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002455 if (!cmd)
2456 return -ENOENT;
2457
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002458 if (bdaddr) {
2459 struct mgmt_rp_disconnect rp;
2460
2461 bacpy(&rp.bdaddr, bdaddr);
2462 rp.status = status;
2463
2464 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2465 &rp, sizeof(rp));
2466 } else
2467 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002468 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002469
Johan Hedberga664b5b2011-02-19 12:06:02 -03002470 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002471
2472 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002473}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002474
Johan Hedberg48264f02011-11-09 13:58:58 +02002475int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2476 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002477{
2478 struct mgmt_ev_connect_failed ev;
2479
Johan Hedberg4c659c32011-11-07 23:13:39 +02002480 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002481 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002482 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002483
Johan Hedberg744cf192011-11-08 20:40:14 +02002484 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002485}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002486
Johan Hedberg744cf192011-11-08 20:40:14 +02002487int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002488{
2489 struct mgmt_ev_pin_code_request ev;
2490
Johan Hedberg980e1a52011-01-22 06:10:07 +02002491 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002492 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002493
Johan Hedberg744cf192011-11-08 20:40:14 +02002494 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002495 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002496}
2497
Johan Hedberg744cf192011-11-08 20:40:14 +02002498int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2499 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002500{
2501 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002502 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002503 int err;
2504
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002505 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002506 if (!cmd)
2507 return -ENOENT;
2508
Johan Hedbergac56fb12011-02-19 12:05:59 -03002509 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002510 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002511
Johan Hedberg744cf192011-11-08 20:40:14 +02002512 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002513 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002514
Johan Hedberga664b5b2011-02-19 12:06:02 -03002515 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002516
2517 return err;
2518}
2519
Johan Hedberg744cf192011-11-08 20:40:14 +02002520int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2521 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002522{
2523 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002524 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002525 int err;
2526
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002527 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002528 if (!cmd)
2529 return -ENOENT;
2530
Johan Hedbergac56fb12011-02-19 12:05:59 -03002531 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002532 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002533
Johan Hedberg744cf192011-11-08 20:40:14 +02002534 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002535 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002536
Johan Hedberga664b5b2011-02-19 12:06:02 -03002537 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002538
2539 return err;
2540}
Johan Hedberga5c29682011-02-19 12:05:57 -03002541
Johan Hedberg744cf192011-11-08 20:40:14 +02002542int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2543 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002544{
2545 struct mgmt_ev_user_confirm_request ev;
2546
Johan Hedberg744cf192011-11-08 20:40:14 +02002547 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002548
Johan Hedberga5c29682011-02-19 12:05:57 -03002549 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002550 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002551 put_unaligned_le32(value, &ev.value);
2552
Johan Hedberg744cf192011-11-08 20:40:14 +02002553 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002554 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002555}
2556
Brian Gix604086b2011-11-23 08:28:33 -08002557int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2558{
2559 struct mgmt_ev_user_passkey_request ev;
2560
2561 BT_DBG("%s", hdev->name);
2562
2563 bacpy(&ev.bdaddr, bdaddr);
2564
2565 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2566 NULL);
2567}
2568
Brian Gix0df4c182011-11-16 13:53:13 -08002569static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002570 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002571{
2572 struct pending_cmd *cmd;
2573 struct mgmt_rp_user_confirm_reply rp;
2574 int err;
2575
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002576 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002577 if (!cmd)
2578 return -ENOENT;
2579
Johan Hedberga5c29682011-02-19 12:05:57 -03002580 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002581 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002582 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002583
Johan Hedberga664b5b2011-02-19 12:06:02 -03002584 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002585
2586 return err;
2587}
2588
Johan Hedberg744cf192011-11-08 20:40:14 +02002589int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2590 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002591{
Brian Gix0df4c182011-11-16 13:53:13 -08002592 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002593 MGMT_OP_USER_CONFIRM_REPLY);
2594}
2595
Johan Hedberg744cf192011-11-08 20:40:14 +02002596int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2597 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002598{
Brian Gix0df4c182011-11-16 13:53:13 -08002599 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002600 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2601}
Johan Hedberg2a611692011-02-19 12:06:00 -03002602
Brian Gix604086b2011-11-23 08:28:33 -08002603int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2604 u8 status)
2605{
2606 return user_pairing_resp_complete(hdev, bdaddr, status,
2607 MGMT_OP_USER_PASSKEY_REPLY);
2608}
2609
2610int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2611 bdaddr_t *bdaddr, u8 status)
2612{
2613 return user_pairing_resp_complete(hdev, bdaddr, status,
2614 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2615}
2616
Johan Hedberg744cf192011-11-08 20:40:14 +02002617int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002618{
2619 struct mgmt_ev_auth_failed ev;
2620
Johan Hedberg2a611692011-02-19 12:06:00 -03002621 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002622 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002623
Johan Hedberg744cf192011-11-08 20:40:14 +02002624 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002625}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002626
Johan Hedberg744cf192011-11-08 20:40:14 +02002627int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002628{
2629 struct pending_cmd *cmd;
2630 struct mgmt_cp_set_local_name ev;
2631 int err;
2632
2633 memset(&ev, 0, sizeof(ev));
2634 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2635
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002636 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002637 if (!cmd)
2638 goto send_event;
2639
2640 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002641 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002642 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002643 goto failed;
2644 }
2645
Johan Hedberg744cf192011-11-08 20:40:14 +02002646 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002647
Johan Hedberg744cf192011-11-08 20:40:14 +02002648 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002649 sizeof(ev));
2650 if (err < 0)
2651 goto failed;
2652
2653send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002654 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002655 cmd ? cmd->sk : NULL);
2656
2657failed:
2658 if (cmd)
2659 mgmt_pending_remove(cmd);
2660 return err;
2661}
Szymon Jancc35938b2011-03-22 13:12:21 +01002662
Johan Hedberg744cf192011-11-08 20:40:14 +02002663int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2664 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002665{
2666 struct pending_cmd *cmd;
2667 int err;
2668
Johan Hedberg744cf192011-11-08 20:40:14 +02002669 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002670
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002671 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002672 if (!cmd)
2673 return -ENOENT;
2674
2675 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002676 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002677 MGMT_OP_READ_LOCAL_OOB_DATA,
2678 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002679 } else {
2680 struct mgmt_rp_read_local_oob_data rp;
2681
2682 memcpy(rp.hash, hash, sizeof(rp.hash));
2683 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2684
Johan Hedberg744cf192011-11-08 20:40:14 +02002685 err = cmd_complete(cmd->sk, hdev->id,
2686 MGMT_OP_READ_LOCAL_OOB_DATA,
2687 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002688 }
2689
2690 mgmt_pending_remove(cmd);
2691
2692 return err;
2693}
Johan Hedberge17acd42011-03-30 23:57:16 +03002694
Johan Hedberg48264f02011-11-09 13:58:58 +02002695int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2696 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002697{
2698 struct mgmt_ev_device_found ev;
2699
2700 memset(&ev, 0, sizeof(ev));
2701
Johan Hedberg4c659c32011-11-07 23:13:39 +02002702 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002703 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002704 ev.rssi = rssi;
2705
2706 if (eir)
2707 memcpy(ev.eir, eir, sizeof(ev.eir));
2708
Andre Guedesf8523592011-09-09 18:56:26 -03002709 if (dev_class)
2710 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2711
Johan Hedberg744cf192011-11-08 20:40:14 +02002712 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002713}
Johan Hedberga88a9652011-03-30 13:18:12 +03002714
Johan Hedberg744cf192011-11-08 20:40:14 +02002715int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002716{
2717 struct mgmt_ev_remote_name ev;
2718
2719 memset(&ev, 0, sizeof(ev));
2720
2721 bacpy(&ev.bdaddr, bdaddr);
2722 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2723
Johan Hedberg744cf192011-11-08 20:40:14 +02002724 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002725}
Johan Hedberg314b2382011-04-27 10:29:57 -04002726
Andre Guedes7a135102011-11-09 17:14:25 -03002727int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002728{
2729 struct pending_cmd *cmd;
2730 int err;
2731
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002732 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002733 if (!cmd)
2734 return -ENOENT;
2735
Johan Hedbergca69b792011-11-11 18:10:00 +02002736 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002737 mgmt_pending_remove(cmd);
2738
2739 return err;
2740}
2741
Andre Guedese6d465c2011-11-09 17:14:26 -03002742int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2743{
2744 struct pending_cmd *cmd;
2745 int err;
2746
2747 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2748 if (!cmd)
2749 return -ENOENT;
2750
Johan Hedberg03811012010-12-08 00:21:06 +02002751 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
2752 mgmt_pending_remove(cmd);
2753
2754 return err;
2755}
Johan Hedberg314b2382011-04-27 10:29:57 -04002756
Johan Hedberg744cf192011-11-08 20:40:14 +02002757int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002758{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002759 struct pending_cmd *cmd;
2760
2761 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002762 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002763 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002764 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002765
2766 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002767 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002768 mgmt_pending_remove(cmd);
2769 }
2770
Johan Hedberg744cf192011-11-08 20:40:14 +02002771 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002772 sizeof(discovering), NULL);
2773}
Antti Julku5e762442011-08-25 16:48:02 +03002774
Johan Hedberg744cf192011-11-08 20:40:14 +02002775int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002776{
2777 struct pending_cmd *cmd;
2778 struct mgmt_ev_device_blocked ev;
2779
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002780 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002781
2782 bacpy(&ev.bdaddr, bdaddr);
2783
Johan Hedberg744cf192011-11-08 20:40:14 +02002784 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2785 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002786}
2787
Johan Hedberg744cf192011-11-08 20:40:14 +02002788int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002789{
2790 struct pending_cmd *cmd;
2791 struct mgmt_ev_device_unblocked ev;
2792
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002793 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002794
2795 bacpy(&ev.bdaddr, bdaddr);
2796
Johan Hedberg744cf192011-11-08 20:40:14 +02002797 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2798 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002799}