blob: cc4ea392ac6a305faa7f084bdba73b858554ef34 [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>
Johan Hedberg03811012010-12-08 00:21:06 +020027#include <asm/unaligned.h>
28
29#include <net/bluetooth/bluetooth.h>
30#include <net/bluetooth/hci_core.h>
31#include <net/bluetooth/mgmt.h>
32
Johan Hedberg02d98122010-12-13 21:07:04 +020033#define MGMT_VERSION 0
34#define MGMT_REVISION 1
35
Andre Guedes2519a1f2011-11-07 11:45:24 -030036#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
37
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020038struct pending_cmd {
39 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020040 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020041 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010042 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020043 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030044 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045};
46
Johan Hedbergca69b792011-11-11 18:10:00 +020047/* HCI to MGMT error code conversion table */
48static u8 mgmt_status_table[] = {
49 MGMT_STATUS_SUCCESS,
50 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
51 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
52 MGMT_STATUS_FAILED, /* Hardware Failure */
53 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
54 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
55 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
56 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
57 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
58 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
59 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
60 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
61 MGMT_STATUS_BUSY, /* Command Disallowed */
62 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
63 MGMT_STATUS_REJECTED, /* Rejected Security */
64 MGMT_STATUS_REJECTED, /* Rejected Personal */
65 MGMT_STATUS_TIMEOUT, /* Host Timeout */
66 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
67 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
68 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
69 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
70 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
71 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
72 MGMT_STATUS_BUSY, /* Repeated Attempts */
73 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
74 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
75 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
76 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
77 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
78 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
79 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
80 MGMT_STATUS_FAILED, /* Unspecified Error */
81 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
82 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
83 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
84 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
85 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
86 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
87 MGMT_STATUS_FAILED, /* Unit Link Key Used */
88 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
89 MGMT_STATUS_TIMEOUT, /* Instant Passed */
90 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
91 MGMT_STATUS_FAILED, /* Transaction Collision */
92 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
93 MGMT_STATUS_REJECTED, /* QoS Rejected */
94 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
95 MGMT_STATUS_REJECTED, /* Insufficient Security */
96 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
97 MGMT_STATUS_BUSY, /* Role Switch Pending */
98 MGMT_STATUS_FAILED, /* Slot Violation */
99 MGMT_STATUS_FAILED, /* Role Switch Failed */
100 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
101 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
102 MGMT_STATUS_BUSY, /* Host Busy Pairing */
103 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
104 MGMT_STATUS_BUSY, /* Controller Busy */
105 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
106 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
107 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
108 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
109 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
110};
111
112static u8 mgmt_status(u8 hci_status)
113{
114 if (hci_status < ARRAY_SIZE(mgmt_status_table))
115 return mgmt_status_table[hci_status];
116
117 return MGMT_STATUS_FAILED;
118}
119
Szymon Janc4e51eae2011-02-25 19:05:48 +0100120static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200121{
122 struct sk_buff *skb;
123 struct mgmt_hdr *hdr;
124 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300125 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200126
Szymon Janc34eb5252011-02-28 14:10:08 +0100127 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200128
129 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
130 if (!skb)
131 return -ENOMEM;
132
133 hdr = (void *) skb_put(skb, sizeof(*hdr));
134
135 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100136 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200137 hdr->len = cpu_to_le16(sizeof(*ev));
138
139 ev = (void *) skb_put(skb, sizeof(*ev));
140 ev->status = status;
141 put_unaligned_le16(cmd, &ev->opcode);
142
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300143 err = sock_queue_rcv_skb(sk, skb);
144 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200145 kfree_skb(skb);
146
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300147 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200148}
149
Szymon Janc4e51eae2011-02-25 19:05:48 +0100150static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
151 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200152{
153 struct sk_buff *skb;
154 struct mgmt_hdr *hdr;
155 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300156 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200157
158 BT_DBG("sock %p", sk);
159
Johan Hedberga38528f2011-01-22 06:46:43 +0200160 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200161 if (!skb)
162 return -ENOMEM;
163
164 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200165
Johan Hedberg02d98122010-12-13 21:07:04 +0200166 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100167 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200168 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200169
Johan Hedberga38528f2011-01-22 06:46:43 +0200170 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
171 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100172
173 if (rp)
174 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200175
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300176 err = sock_queue_rcv_skb(sk, skb);
177 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200178 kfree_skb(skb);
179
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300180 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200181}
182
Johan Hedberga38528f2011-01-22 06:46:43 +0200183static int read_version(struct sock *sk)
184{
185 struct mgmt_rp_read_version rp;
186
187 BT_DBG("sock %p", sk);
188
189 rp.version = MGMT_VERSION;
190 put_unaligned_le16(MGMT_REVISION, &rp.revision);
191
Szymon Janc4e51eae2011-02-25 19:05:48 +0100192 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
193 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200194}
195
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200196static int read_index_list(struct sock *sk)
197{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200198 struct mgmt_rp_read_index_list *rp;
199 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200200 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200202 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200204
205 BT_DBG("sock %p", sk);
206
207 read_lock(&hci_dev_list_lock);
208
209 count = 0;
210 list_for_each(p, &hci_dev_list) {
211 count++;
212 }
213
Johan Hedberga38528f2011-01-22 06:46:43 +0200214 rp_len = sizeof(*rp) + (2 * count);
215 rp = kmalloc(rp_len, GFP_ATOMIC);
216 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100217 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200218 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100219 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200220
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200221 put_unaligned_le16(count, &rp->num_controllers);
222
223 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200224 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberg32435532011-11-07 22:16:04 +0200225 if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200226 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200227
228 if (test_bit(HCI_SETUP, &d->flags))
229 continue;
230
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200231 put_unaligned_le16(d->id, &rp->index[i++]);
232 BT_DBG("Added hci%u", d->id);
233 }
234
235 read_unlock(&hci_dev_list_lock);
236
Szymon Janc4e51eae2011-02-25 19:05:48 +0100237 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
238 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200239
Johan Hedberga38528f2011-01-22 06:46:43 +0200240 kfree(rp);
241
242 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200243}
244
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200245static u32 get_supported_settings(struct hci_dev *hdev)
246{
247 u32 settings = 0;
248
249 settings |= MGMT_SETTING_POWERED;
250 settings |= MGMT_SETTING_CONNECTABLE;
251 settings |= MGMT_SETTING_FAST_CONNECTABLE;
252 settings |= MGMT_SETTING_DISCOVERABLE;
253 settings |= MGMT_SETTING_PAIRABLE;
254
255 if (hdev->features[6] & LMP_SIMPLE_PAIR)
256 settings |= MGMT_SETTING_SSP;
257
258 if (!(hdev->features[4] & LMP_NO_BREDR)) {
259 settings |= MGMT_SETTING_BREDR;
260 settings |= MGMT_SETTING_LINK_SECURITY;
261 }
262
263 if (hdev->features[4] & LMP_LE)
264 settings |= MGMT_SETTING_LE;
265
266 return settings;
267}
268
269static u32 get_current_settings(struct hci_dev *hdev)
270{
271 u32 settings = 0;
272
273 if (test_bit(HCI_UP, &hdev->flags))
274 settings |= MGMT_SETTING_POWERED;
275 else
276 return settings;
277
278 if (test_bit(HCI_PSCAN, &hdev->flags))
279 settings |= MGMT_SETTING_CONNECTABLE;
280
281 if (test_bit(HCI_ISCAN, &hdev->flags))
282 settings |= MGMT_SETTING_DISCOVERABLE;
283
284 if (test_bit(HCI_PAIRABLE, &hdev->flags))
285 settings |= MGMT_SETTING_PAIRABLE;
286
287 if (!(hdev->features[4] & LMP_NO_BREDR))
288 settings |= MGMT_SETTING_BREDR;
289
290 if (hdev->extfeatures[0] & LMP_HOST_LE)
291 settings |= MGMT_SETTING_LE;
292
293 if (test_bit(HCI_AUTH, &hdev->flags))
294 settings |= MGMT_SETTING_LINK_SECURITY;
295
296 if (hdev->ssp_mode > 0)
297 settings |= MGMT_SETTING_SSP;
298
299 return settings;
300}
301
Johan Hedbergef580372011-12-15 00:47:38 +0200302#define EIR_FLAGS 0x01 /* flags */
303#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
304#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
305#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
306#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
307#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
308#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
309#define EIR_NAME_SHORT 0x08 /* shortened local name */
310#define EIR_NAME_COMPLETE 0x09 /* complete local name */
311#define EIR_TX_POWER 0x0A /* transmit power level */
312#define EIR_DEVICE_ID 0x10 /* device ID */
313
314#define PNP_INFO_SVCLASS_ID 0x1200
315
316static u8 bluetooth_base_uuid[] = {
317 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
318 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319};
320
321static u16 get_uuid16(u8 *uuid128)
322{
323 u32 val;
324 int i;
325
326 for (i = 0; i < 12; i++) {
327 if (bluetooth_base_uuid[i] != uuid128[i])
328 return 0;
329 }
330
331 memcpy(&val, &uuid128[12], 4);
332
333 val = le32_to_cpu(val);
334 if (val > 0xffff)
335 return 0;
336
337 return (u16) val;
338}
339
340static void create_eir(struct hci_dev *hdev, u8 *data)
341{
342 u8 *ptr = data;
343 u16 eir_len = 0;
344 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
345 int i, truncated = 0;
346 struct bt_uuid *uuid;
347 size_t name_len;
348
349 name_len = strlen(hdev->dev_name);
350
351 if (name_len > 0) {
352 /* EIR Data type */
353 if (name_len > 48) {
354 name_len = 48;
355 ptr[1] = EIR_NAME_SHORT;
356 } else
357 ptr[1] = EIR_NAME_COMPLETE;
358
359 /* EIR Data length */
360 ptr[0] = name_len + 1;
361
362 memcpy(ptr + 2, hdev->dev_name, name_len);
363
364 eir_len += (name_len + 2);
365 ptr += (name_len + 2);
366 }
367
368 memset(uuid16_list, 0, sizeof(uuid16_list));
369
370 /* Group all UUID16 types */
371 list_for_each_entry(uuid, &hdev->uuids, list) {
372 u16 uuid16;
373
374 uuid16 = get_uuid16(uuid->uuid);
375 if (uuid16 == 0)
376 return;
377
378 if (uuid16 < 0x1100)
379 continue;
380
381 if (uuid16 == PNP_INFO_SVCLASS_ID)
382 continue;
383
384 /* Stop if not enough space to put next UUID */
385 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
386 truncated = 1;
387 break;
388 }
389
390 /* Check for duplicates */
391 for (i = 0; uuid16_list[i] != 0; i++)
392 if (uuid16_list[i] == uuid16)
393 break;
394
395 if (uuid16_list[i] == 0) {
396 uuid16_list[i] = uuid16;
397 eir_len += sizeof(u16);
398 }
399 }
400
401 if (uuid16_list[0] != 0) {
402 u8 *length = ptr;
403
404 /* EIR Data type */
405 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
406
407 ptr += 2;
408 eir_len += 2;
409
410 for (i = 0; uuid16_list[i] != 0; i++) {
411 *ptr++ = (uuid16_list[i] & 0x00ff);
412 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
413 }
414
415 /* EIR Data length */
416 *length = (i * sizeof(u16)) + 1;
417 }
418}
419
420static int update_eir(struct hci_dev *hdev)
421{
422 struct hci_cp_write_eir cp;
423
424 if (!(hdev->features[6] & LMP_EXT_INQ))
425 return 0;
426
427 if (hdev->ssp_mode == 0)
428 return 0;
429
430 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
431 return 0;
432
433 memset(&cp, 0, sizeof(cp));
434
435 create_eir(hdev, cp.data);
436
437 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
438 return 0;
439
440 memcpy(hdev->eir, cp.data, sizeof(cp.data));
441
442 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
443}
444
445static u8 get_service_classes(struct hci_dev *hdev)
446{
447 struct bt_uuid *uuid;
448 u8 val = 0;
449
450 list_for_each_entry(uuid, &hdev->uuids, list)
451 val |= uuid->svc_hint;
452
453 return val;
454}
455
456static int update_class(struct hci_dev *hdev)
457{
458 u8 cod[3];
459
460 BT_DBG("%s", hdev->name);
461
462 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
463 return 0;
464
465 cod[0] = hdev->minor_class;
466 cod[1] = hdev->major_class;
467 cod[2] = get_service_classes(hdev);
468
469 if (memcmp(cod, hdev->dev_class, 3) == 0)
470 return 0;
471
472 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
473}
474
Szymon Janc4e51eae2011-02-25 19:05:48 +0100475static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200476{
Johan Hedberga38528f2011-01-22 06:46:43 +0200477 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200478 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200479
Szymon Janc4e51eae2011-02-25 19:05:48 +0100480 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200481
Szymon Janc4e51eae2011-02-25 19:05:48 +0100482 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200483 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200484 return cmd_status(sk, index, MGMT_OP_READ_INFO,
485 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200486
Johan Hedberg32435532011-11-07 22:16:04 +0200487 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
488 cancel_delayed_work_sync(&hdev->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200489
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300490 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200491
Johan Hedberg14c0b602011-12-15 00:47:37 +0200492 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) {
493 set_bit(HCI_MGMT, &hdev->flags);
494 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
495 }
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200496
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200497 memset(&rp, 0, sizeof(rp));
498
Johan Hedberga38528f2011-01-22 06:46:43 +0200499 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200500
501 rp.version = hdev->hci_ver;
502
Johan Hedberga38528f2011-01-22 06:46:43 +0200503 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200504
505 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
506 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
507
508 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200509
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200510 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
511
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300512 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200513 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200514
Szymon Janc4e51eae2011-02-25 19:05:48 +0100515 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200516}
517
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200518static void mgmt_pending_free(struct pending_cmd *cmd)
519{
520 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100521 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200522 kfree(cmd);
523}
524
Johan Hedberg366a0332011-02-19 12:05:55 -0300525static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200526 struct hci_dev *hdev,
527 void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200528{
529 struct pending_cmd *cmd;
530
531 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
532 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300533 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200534
535 cmd->opcode = opcode;
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200536 cmd->index = hdev->id;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200537
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100538 cmd->param = kmalloc(len, GFP_ATOMIC);
539 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200540 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300541 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200542 }
543
Szymon Janc8fce6352011-03-22 13:12:20 +0100544 if (data)
545 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200546
547 cmd->sk = sk;
548 sock_hold(sk);
549
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200550 list_add(&cmd->list, &hdev->mgmt_pending);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200551
Johan Hedberg366a0332011-02-19 12:05:55 -0300552 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200553}
554
Johan Hedberg744cf192011-11-08 20:40:14 +0200555static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200556 void (*cb)(struct pending_cmd *cmd, void *data),
557 void *data)
558{
559 struct list_head *p, *n;
560
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200561 list_for_each_safe(p, n, &hdev->mgmt_pending) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200562 struct pending_cmd *cmd;
563
564 cmd = list_entry(p, struct pending_cmd, list);
565
Johan Hedbergb24752f2011-11-03 14:40:33 +0200566 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200567 continue;
568
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200569 cb(cmd, data);
570 }
571}
572
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200573static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200574{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200575 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200576
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200577 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberg2aeabcb2011-11-09 13:58:57 +0200578 if (cmd->opcode == opcode)
579 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200580 }
581
582 return NULL;
583}
584
Johan Hedberga664b5b2011-02-19 12:06:02 -0300585static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200586{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200587 list_del(&cmd->list);
588 mgmt_pending_free(cmd);
589}
590
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200591static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200592{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200593 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200594
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200595 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200596}
597
Szymon Janc4e51eae2011-02-25 19:05:48 +0100598static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200599{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200600 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200601 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300602 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300603 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200604
605 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200606
Szymon Janc4e51eae2011-02-25 19:05:48 +0100607 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200608
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100609 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200610 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
611 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100612
Szymon Janc4e51eae2011-02-25 19:05:48 +0100613 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200614 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200615 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
616 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200617
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300618 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200619
620 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200621 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200622 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200623 goto failed;
624 }
625
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200626 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200627 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
628 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200629 goto failed;
630 }
631
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200632 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300633 if (!cmd) {
634 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200635 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300636 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200637
Johan Hedberg72a734e2010-12-30 00:38:22 +0200638 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200639 schedule_work(&hdev->power_on);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200640 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200641 schedule_work(&hdev->power_off.work);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200642
Johan Hedberg366a0332011-02-19 12:05:55 -0300643 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200644
645failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300646 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200647 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300648 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200649}
650
Szymon Janc4e51eae2011-02-25 19:05:48 +0100651static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
652 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200653{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200654 struct mgmt_cp_set_discoverable *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200655 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300656 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200657 u8 scan;
658 int err;
659
660 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200661
Szymon Janc4e51eae2011-02-25 19:05:48 +0100662 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200663
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100664 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200665 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
666 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100667
Szymon Janc4e51eae2011-02-25 19:05:48 +0100668 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200669 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200670 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
671 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200672
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300673 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200674
675 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200676 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
677 MGMT_STATUS_NOT_POWERED);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200678 goto failed;
679 }
680
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200681 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
682 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200683 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
684 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200685 goto failed;
686 }
687
Johan Hedberg72a734e2010-12-30 00:38:22 +0200688 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200689 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200690 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200691 goto failed;
692 }
693
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200694 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300695 if (!cmd) {
696 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200697 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300698 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200699
700 scan = SCAN_PAGE;
701
Johan Hedberg72a734e2010-12-30 00:38:22 +0200702 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200703 scan |= SCAN_INQUIRY;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200704 else
Johan Hedberge0f93092011-11-09 01:44:22 +0200705 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200706
707 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
708 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300709 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200710
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200711 if (cp->val)
712 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
713
Johan Hedberg73f22f62010-12-29 16:00:25 +0200714failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300715 hci_dev_unlock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200716 hci_dev_put(hdev);
717
718 return err;
719}
720
Szymon Janc4e51eae2011-02-25 19:05:48 +0100721static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
722 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200723{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200724 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200725 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300726 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200727 u8 scan;
728 int err;
729
730 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200731
Szymon Janc4e51eae2011-02-25 19:05:48 +0100732 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200733
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100734 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200735 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
736 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100737
Szymon Janc4e51eae2011-02-25 19:05:48 +0100738 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200739 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200740 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
741 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200742
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300743 hci_dev_lock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200744
745 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200746 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
747 MGMT_STATUS_NOT_POWERED);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200748 goto failed;
749 }
750
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200751 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
752 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200753 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
754 MGMT_STATUS_BUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200755 goto failed;
756 }
757
Johan Hedberg72a734e2010-12-30 00:38:22 +0200758 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200759 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200760 goto failed;
761 }
762
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200763 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300764 if (!cmd) {
765 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200766 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300767 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200768
Johan Hedberg72a734e2010-12-30 00:38:22 +0200769 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200770 scan = SCAN_PAGE;
771 else
772 scan = 0;
773
774 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
775 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300776 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200777
778failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300779 hci_dev_unlock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200780 hci_dev_put(hdev);
781
782 return err;
783}
784
Johan Hedberg744cf192011-11-08 20:40:14 +0200785static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
786 u16 data_len, struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200787{
788 struct sk_buff *skb;
789 struct mgmt_hdr *hdr;
790
791 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
792 if (!skb)
793 return -ENOMEM;
794
795 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
796
797 hdr = (void *) skb_put(skb, sizeof(*hdr));
798 hdr->opcode = cpu_to_le16(event);
Johan Hedberg744cf192011-11-08 20:40:14 +0200799 if (hdev)
800 hdr->index = cpu_to_le16(hdev->id);
801 else
802 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergc542a062011-01-26 13:11:03 +0200803 hdr->len = cpu_to_le16(data_len);
804
Szymon Janc4e51eae2011-02-25 19:05:48 +0100805 if (data)
806 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200807
808 hci_send_to_sock(NULL, skb, skip_sk);
809 kfree_skb(skb);
810
811 return 0;
812}
813
Szymon Janc4e51eae2011-02-25 19:05:48 +0100814static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
815 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200816{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200817 struct mgmt_mode *cp;
Johan Hedbergc542a062011-01-26 13:11:03 +0200818 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200819 __le32 ev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200820 int err;
821
822 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200823
Szymon Janc4e51eae2011-02-25 19:05:48 +0100824 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200825
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100826 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200827 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
828 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100829
Szymon Janc4e51eae2011-02-25 19:05:48 +0100830 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200831 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200832 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
833 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergc542a062011-01-26 13:11:03 +0200834
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300835 hci_dev_lock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200836
837 if (cp->val)
838 set_bit(HCI_PAIRABLE, &hdev->flags);
839 else
840 clear_bit(HCI_PAIRABLE, &hdev->flags);
841
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200842 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200843 if (err < 0)
844 goto failed;
845
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200846 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergc542a062011-01-26 13:11:03 +0200847
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200848 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200849
850failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300851 hci_dev_unlock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200852 hci_dev_put(hdev);
853
854 return err;
855}
856
Szymon Janc4e51eae2011-02-25 19:05:48 +0100857static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200858{
859 struct mgmt_cp_add_uuid *cp;
860 struct hci_dev *hdev;
861 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200862 int err;
863
864 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200865
Szymon Janc4e51eae2011-02-25 19:05:48 +0100866 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200867
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100868 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200869 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
870 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100871
Szymon Janc4e51eae2011-02-25 19:05:48 +0100872 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200873 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200874 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
875 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200876
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300877 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200878
879 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
880 if (!uuid) {
881 err = -ENOMEM;
882 goto failed;
883 }
884
885 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200886 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200887
888 list_add(&uuid->list, &hdev->uuids);
889
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200890 err = update_class(hdev);
891 if (err < 0)
892 goto failed;
893
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300894 err = update_eir(hdev);
895 if (err < 0)
896 goto failed;
897
Szymon Janc4e51eae2011-02-25 19:05:48 +0100898 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200899
900failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300901 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200902 hci_dev_put(hdev);
903
904 return err;
905}
906
Szymon Janc4e51eae2011-02-25 19:05:48 +0100907static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200908{
909 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100910 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200911 struct hci_dev *hdev;
912 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 +0200913 int err, found;
914
915 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200916
Szymon Janc4e51eae2011-02-25 19:05:48 +0100917 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200918
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100919 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200920 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
921 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100922
Szymon Janc4e51eae2011-02-25 19:05:48 +0100923 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200924 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200925 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
926 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200927
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300928 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200929
930 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
931 err = hci_uuids_clear(hdev);
932 goto unlock;
933 }
934
935 found = 0;
936
937 list_for_each_safe(p, n, &hdev->uuids) {
938 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
939
940 if (memcmp(match->uuid, cp->uuid, 16) != 0)
941 continue;
942
943 list_del(&match->list);
944 found++;
945 }
946
947 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200948 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
949 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200950 goto unlock;
951 }
952
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200953 err = update_class(hdev);
954 if (err < 0)
955 goto unlock;
956
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300957 err = update_eir(hdev);
958 if (err < 0)
959 goto unlock;
960
Szymon Janc4e51eae2011-02-25 19:05:48 +0100961 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200962
963unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300964 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200965 hci_dev_put(hdev);
966
967 return err;
968}
969
Szymon Janc4e51eae2011-02-25 19:05:48 +0100970static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
971 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200972{
973 struct hci_dev *hdev;
974 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200975 int err;
976
977 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200978
Szymon Janc4e51eae2011-02-25 19:05:48 +0100979 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200980
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100981 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200982 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
983 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100984
Szymon Janc4e51eae2011-02-25 19:05:48 +0100985 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200986 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200987 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
988 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200989
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300990 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200991
992 hdev->major_class = cp->major;
993 hdev->minor_class = cp->minor;
994
Johan Hedberg14c0b602011-12-15 00:47:37 +0200995 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags))
996 update_eir(hdev);
997
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200998 err = update_class(hdev);
999
1000 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001001 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001002
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001003 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001004 hci_dev_put(hdev);
1005
1006 return err;
1007}
1008
Johan Hedberg86742e12011-11-07 23:13:38 +02001009static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
1010 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001011{
1012 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001013 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001014 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001015 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001016
1017 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001018
1019 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001020 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1021 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001022
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001023 key_count = get_unaligned_le16(&cp->key_count);
1024
Johan Hedberg86742e12011-11-07 23:13:38 +02001025 expected_len = sizeof(*cp) + key_count *
1026 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001027 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001028 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001029 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001030 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1031 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001032 }
1033
Szymon Janc4e51eae2011-02-25 19:05:48 +01001034 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001035 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001036 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1037 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001038
Szymon Janc4e51eae2011-02-25 19:05:48 +01001039 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001040 key_count);
1041
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001042 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001043
1044 hci_link_keys_clear(hdev);
1045
1046 set_bit(HCI_LINK_KEYS, &hdev->flags);
1047
1048 if (cp->debug_keys)
1049 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1050 else
1051 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1052
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001053 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001054 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001055
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001056 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001057 key->pin_len);
1058 }
1059
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001060 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1061
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001062 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001063 hci_dev_put(hdev);
1064
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001065 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001066}
1067
Johan Hedberg86742e12011-11-07 23:13:38 +02001068static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
1069 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001070{
1071 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001072 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001073 struct mgmt_rp_remove_keys rp;
1074 struct hci_cp_disconnect dc;
1075 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001076 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001077 int err;
1078
1079 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001080
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001081 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001082 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1083 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001084
Szymon Janc4e51eae2011-02-25 19:05:48 +01001085 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001086 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001087 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1088 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001089
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001090 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001091
Johan Hedberga8a1d192011-11-10 15:54:38 +02001092 memset(&rp, 0, sizeof(rp));
1093 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001094 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001095
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001096 err = hci_remove_link_key(hdev, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001097 if (err < 0) {
1098 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001099 goto unlock;
Johan Hedbergca69b792011-11-11 18:10:00 +02001100 }
Johan Hedberga8a1d192011-11-10 15:54:38 +02001101
1102 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1103 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1104 sizeof(rp));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001105 goto unlock;
1106 }
1107
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001108 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001109 if (!conn) {
1110 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1111 sizeof(rp));
1112 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001113 }
1114
Johan Hedberga8a1d192011-11-10 15:54:38 +02001115 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1116 if (!cmd) {
1117 err = -ENOMEM;
1118 goto unlock;
1119 }
1120
1121 put_unaligned_le16(conn->handle, &dc.handle);
1122 dc.reason = 0x13; /* Remote User Terminated Connection */
1123 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1124 if (err < 0)
1125 mgmt_pending_remove(cmd);
1126
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001127unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001128 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001129 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1130 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001131 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001132 hci_dev_put(hdev);
1133
1134 return err;
1135}
1136
Szymon Janc4e51eae2011-02-25 19:05:48 +01001137static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001138{
1139 struct hci_dev *hdev;
1140 struct mgmt_cp_disconnect *cp;
1141 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001142 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001143 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001144 int err;
1145
1146 BT_DBG("");
1147
1148 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001149
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001150 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001151 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1152 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001153
Szymon Janc4e51eae2011-02-25 19:05:48 +01001154 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001155 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001156 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1157 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001158
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001159 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001160
1161 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001162 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1163 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001164 goto failed;
1165 }
1166
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001167 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001168 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1169 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001170 goto failed;
1171 }
1172
1173 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001174 if (!conn)
1175 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1176
Johan Hedberg8962ee72011-01-20 12:40:27 +02001177 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001178 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1179 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001180 goto failed;
1181 }
1182
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001183 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001184 if (!cmd) {
1185 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001186 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001187 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001188
1189 put_unaligned_le16(conn->handle, &dc.handle);
1190 dc.reason = 0x13; /* Remote User Terminated Connection */
1191
1192 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1193 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001194 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001195
1196failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001197 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001198 hci_dev_put(hdev);
1199
1200 return err;
1201}
1202
Johan Hedberg48264f02011-11-09 13:58:58 +02001203static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001204{
1205 switch (link_type) {
1206 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001207 switch (addr_type) {
1208 case ADDR_LE_DEV_PUBLIC:
1209 return MGMT_ADDR_LE_PUBLIC;
1210 case ADDR_LE_DEV_RANDOM:
1211 return MGMT_ADDR_LE_RANDOM;
1212 default:
1213 return MGMT_ADDR_INVALID;
1214 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001215 case ACL_LINK:
1216 return MGMT_ADDR_BREDR;
1217 default:
1218 return MGMT_ADDR_INVALID;
1219 }
1220}
1221
Szymon Janc8ce62842011-03-01 16:55:32 +01001222static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001223{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001224 struct mgmt_rp_get_connections *rp;
1225 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001226 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001227 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001228 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001229 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001230 int i, err;
1231
1232 BT_DBG("");
1233
Szymon Janc4e51eae2011-02-25 19:05:48 +01001234 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001235 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001236 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1237 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001238
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001239 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001240
1241 count = 0;
1242 list_for_each(p, &hdev->conn_hash.list) {
1243 count++;
1244 }
1245
Johan Hedberg4c659c32011-11-07 23:13:39 +02001246 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001247 rp = kmalloc(rp_len, GFP_ATOMIC);
1248 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001249 err = -ENOMEM;
1250 goto unlock;
1251 }
1252
Johan Hedberg2784eb42011-01-21 13:56:35 +02001253 put_unaligned_le16(count, &rp->conn_count);
1254
Johan Hedberg2784eb42011-01-21 13:56:35 +02001255 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001256 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1257 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001258 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001259 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1260 continue;
1261 i++;
1262 }
1263
1264 /* Recalculate length in case of filtered SCO connections, etc */
1265 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001266
Szymon Janc4e51eae2011-02-25 19:05:48 +01001267 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001268
1269unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001270 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001271 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001272 hci_dev_put(hdev);
1273 return err;
1274}
1275
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001276static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1277 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1278{
1279 struct pending_cmd *cmd;
1280 int err;
1281
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001282 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001283 sizeof(*cp));
1284 if (!cmd)
1285 return -ENOMEM;
1286
1287 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1288 &cp->bdaddr);
1289 if (err < 0)
1290 mgmt_pending_remove(cmd);
1291
1292 return err;
1293}
1294
Szymon Janc4e51eae2011-02-25 19:05:48 +01001295static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1296 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001297{
1298 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001299 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001300 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001301 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001302 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001303 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001304 int err;
1305
1306 BT_DBG("");
1307
1308 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001309
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001310 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001311 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1312 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001313
Szymon Janc4e51eae2011-02-25 19:05:48 +01001314 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001315 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001316 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1317 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001318
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001319 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001320
1321 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001322 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1323 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001324 goto failed;
1325 }
1326
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001327 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1328 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001329 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1330 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001331 goto failed;
1332 }
1333
1334 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1335 bacpy(&ncp.bdaddr, &cp->bdaddr);
1336
1337 BT_ERR("PIN code is not 16 bytes long");
1338
1339 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1340 if (err >= 0)
1341 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001342 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001343
1344 goto failed;
1345 }
1346
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001347 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001348 if (!cmd) {
1349 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001350 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001351 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001352
1353 bacpy(&reply.bdaddr, &cp->bdaddr);
1354 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001355 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001356
1357 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1358 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001359 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001360
1361failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001362 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001363 hci_dev_put(hdev);
1364
1365 return err;
1366}
1367
Szymon Janc4e51eae2011-02-25 19:05:48 +01001368static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1369 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001370{
1371 struct hci_dev *hdev;
1372 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001373 int err;
1374
1375 BT_DBG("");
1376
1377 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001378
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001379 if (len != sizeof(*cp))
1380 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001381 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001382
Szymon Janc4e51eae2011-02-25 19:05:48 +01001383 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001384 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001385 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001386 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001387
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001388 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001389
1390 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001391 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001392 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001393 goto failed;
1394 }
1395
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001396 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001397
1398failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001399 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001400 hci_dev_put(hdev);
1401
1402 return err;
1403}
1404
Szymon Janc4e51eae2011-02-25 19:05:48 +01001405static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1406 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001407{
1408 struct hci_dev *hdev;
1409 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001410
1411 BT_DBG("");
1412
1413 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001414
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001415 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001416 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1417 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001418
Szymon Janc4e51eae2011-02-25 19:05:48 +01001419 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001420 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001421 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1422 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001423
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001424 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001425
1426 hdev->io_capability = cp->io_capability;
1427
1428 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e0f2011-03-01 16:55:34 +01001429 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001430
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001431 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001432 hci_dev_put(hdev);
1433
Szymon Janc4e51eae2011-02-25 19:05:48 +01001434 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001435}
1436
Johan Hedberge9a416b2011-02-19 12:05:56 -03001437static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1438{
1439 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001440 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001441
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001442 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001443 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1444 continue;
1445
Johan Hedberge9a416b2011-02-19 12:05:56 -03001446 if (cmd->user_data != conn)
1447 continue;
1448
1449 return cmd;
1450 }
1451
1452 return NULL;
1453}
1454
1455static void pairing_complete(struct pending_cmd *cmd, u8 status)
1456{
1457 struct mgmt_rp_pair_device rp;
1458 struct hci_conn *conn = cmd->user_data;
1459
Johan Hedbergba4e5642011-11-11 00:07:34 +02001460 bacpy(&rp.addr.bdaddr, &conn->dst);
1461 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001462 rp.status = status;
1463
Szymon Janc4e51eae2011-02-25 19:05:48 +01001464 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001465
1466 /* So we don't get further callbacks for this connection */
1467 conn->connect_cfm_cb = NULL;
1468 conn->security_cfm_cb = NULL;
1469 conn->disconn_cfm_cb = NULL;
1470
1471 hci_conn_put(conn);
1472
Johan Hedberga664b5b2011-02-19 12:06:02 -03001473 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001474}
1475
1476static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1477{
1478 struct pending_cmd *cmd;
1479
1480 BT_DBG("status %u", status);
1481
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001482 cmd = find_pairing(conn);
1483 if (!cmd)
1484 BT_DBG("Unable to find a pending command");
1485 else
1486 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001487}
1488
Szymon Janc4e51eae2011-02-25 19:05:48 +01001489static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001490{
1491 struct hci_dev *hdev;
1492 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001493 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001494 struct pending_cmd *cmd;
1495 u8 sec_level, auth_type;
1496 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001497 int err;
1498
1499 BT_DBG("");
1500
1501 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001502
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001503 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001504 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1505 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001506
Szymon Janc4e51eae2011-02-25 19:05:48 +01001507 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001508 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001509 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1510 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001511
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001512 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001513
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001514 sec_level = BT_SECURITY_MEDIUM;
1515 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001516 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001517 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001518 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001519
Johan Hedbergba4e5642011-11-11 00:07:34 +02001520 if (cp->addr.type == MGMT_ADDR_BREDR)
1521 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001522 auth_type);
1523 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001524 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001525 auth_type);
1526
Johan Hedberg1425acb2011-11-11 00:07:35 +02001527 memset(&rp, 0, sizeof(rp));
1528 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1529 rp.addr.type = cp->addr.type;
1530
Ville Tervo30e76272011-02-22 16:10:53 -03001531 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001532 rp.status = -PTR_ERR(conn);
1533 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1534 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001535 goto unlock;
1536 }
1537
1538 if (conn->connect_cfm_cb) {
1539 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001540 rp.status = EBUSY;
1541 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1542 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001543 goto unlock;
1544 }
1545
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001546 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001547 if (!cmd) {
1548 err = -ENOMEM;
1549 hci_conn_put(conn);
1550 goto unlock;
1551 }
1552
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001553 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001554 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001555 conn->connect_cfm_cb = pairing_complete_cb;
1556
Johan Hedberge9a416b2011-02-19 12:05:56 -03001557 conn->security_cfm_cb = pairing_complete_cb;
1558 conn->disconn_cfm_cb = pairing_complete_cb;
1559 conn->io_capability = cp->io_cap;
1560 cmd->user_data = conn;
1561
1562 if (conn->state == BT_CONNECTED &&
1563 hci_conn_security(conn, sec_level, auth_type))
1564 pairing_complete(cmd, 0);
1565
1566 err = 0;
1567
1568unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001569 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001570 hci_dev_put(hdev);
1571
1572 return err;
1573}
1574
Brian Gix0df4c182011-11-16 13:53:13 -08001575static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1576 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001577{
Johan Hedberga5c29682011-02-19 12:05:57 -03001578 struct pending_cmd *cmd;
1579 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001580 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001581 int err;
1582
Szymon Janc4e51eae2011-02-25 19:05:48 +01001583 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001584 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001585 return cmd_status(sk, index, mgmt_op,
1586 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001587
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001588 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001589
Johan Hedberga5c29682011-02-19 12:05:57 -03001590 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001591 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1592 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001593 }
1594
Brian Gix47c15e22011-11-16 13:53:14 -08001595 /*
1596 * Check for an existing ACL link, if present pair via
1597 * HCI commands.
1598 *
1599 * If no ACL link is present, check for an LE link and if
1600 * present, pair via the SMP engine.
1601 *
1602 * If neither ACL nor LE links are present, fail with error.
1603 */
1604 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1605 if (!conn) {
1606 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1607 if (!conn) {
1608 err = cmd_status(sk, index, mgmt_op,
1609 MGMT_STATUS_NOT_CONNECTED);
1610 goto done;
1611 }
1612
1613 /* Continue with pairing via SMP */
1614
1615 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_SUCCESS);
1616 goto done;
1617 }
1618
Brian Gix0df4c182011-11-16 13:53:13 -08001619 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001620 if (!cmd) {
1621 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001622 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001623 }
1624
Brian Gix0df4c182011-11-16 13:53:13 -08001625 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001626 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1627 struct hci_cp_user_passkey_reply cp;
1628
1629 bacpy(&cp.bdaddr, bdaddr);
1630 cp.passkey = passkey;
1631 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1632 } else
1633 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1634
Johan Hedberga664b5b2011-02-19 12:06:02 -03001635 if (err < 0)
1636 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001637
Brian Gix0df4c182011-11-16 13:53:13 -08001638done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001639 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001640 hci_dev_put(hdev);
1641
1642 return err;
1643}
1644
Brian Gix0df4c182011-11-16 13:53:13 -08001645static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1646{
1647 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1648
1649 BT_DBG("");
1650
1651 if (len != sizeof(*cp))
1652 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1653 MGMT_STATUS_INVALID_PARAMS);
1654
1655 return user_pairing_resp(sk, index, &cp->bdaddr,
1656 MGMT_OP_USER_CONFIRM_REPLY,
1657 HCI_OP_USER_CONFIRM_REPLY, 0);
1658}
1659
1660static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1661 u16 len)
1662{
1663 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1664
1665 BT_DBG("");
1666
1667 if (len != sizeof(*cp))
1668 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1669 MGMT_STATUS_INVALID_PARAMS);
1670
1671 return user_pairing_resp(sk, index, &cp->bdaddr,
1672 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1673 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1674}
1675
Brian Gix604086b2011-11-23 08:28:33 -08001676static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1677{
1678 struct mgmt_cp_user_passkey_reply *cp = (void *) data;
1679
1680 BT_DBG("");
1681
1682 if (len != sizeof(*cp))
1683 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1684 EINVAL);
1685
1686 return user_pairing_resp(sk, index, &cp->bdaddr,
1687 MGMT_OP_USER_PASSKEY_REPLY,
1688 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1689}
1690
1691static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1692 u16 len)
1693{
1694 struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data;
1695
1696 BT_DBG("");
1697
1698 if (len != sizeof(*cp))
1699 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1700 EINVAL);
1701
1702 return user_pairing_resp(sk, index, &cp->bdaddr,
1703 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1704 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1705}
1706
Johan Hedbergb312b1612011-03-16 14:29:37 +02001707static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1708 u16 len)
1709{
1710 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1711 struct hci_cp_write_local_name hci_cp;
1712 struct hci_dev *hdev;
1713 struct pending_cmd *cmd;
1714 int err;
1715
1716 BT_DBG("");
1717
1718 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001719 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1720 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001721
1722 hdev = hci_dev_get(index);
1723 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001724 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1725 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001726
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001727 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001728
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001729 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001730 if (!cmd) {
1731 err = -ENOMEM;
1732 goto failed;
1733 }
1734
1735 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1736 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1737 &hci_cp);
1738 if (err < 0)
1739 mgmt_pending_remove(cmd);
1740
1741failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001742 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001743 hci_dev_put(hdev);
1744
1745 return err;
1746}
1747
Szymon Jancc35938b2011-03-22 13:12:21 +01001748static int read_local_oob_data(struct sock *sk, u16 index)
1749{
1750 struct hci_dev *hdev;
1751 struct pending_cmd *cmd;
1752 int err;
1753
1754 BT_DBG("hci%u", index);
1755
1756 hdev = hci_dev_get(index);
1757 if (!hdev)
1758 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001759 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001760
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001761 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001762
1763 if (!test_bit(HCI_UP, &hdev->flags)) {
1764 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001765 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001766 goto unlock;
1767 }
1768
1769 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1770 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001771 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001772 goto unlock;
1773 }
1774
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001775 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001776 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1777 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001778 goto unlock;
1779 }
1780
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001781 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001782 if (!cmd) {
1783 err = -ENOMEM;
1784 goto unlock;
1785 }
1786
1787 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1788 if (err < 0)
1789 mgmt_pending_remove(cmd);
1790
1791unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001792 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001793 hci_dev_put(hdev);
1794
1795 return err;
1796}
1797
Szymon Janc2763eda2011-03-22 13:12:22 +01001798static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1799 u16 len)
1800{
1801 struct hci_dev *hdev;
1802 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1803 int err;
1804
1805 BT_DBG("hci%u ", index);
1806
1807 if (len != sizeof(*cp))
1808 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001809 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001810
1811 hdev = hci_dev_get(index);
1812 if (!hdev)
1813 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001814 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001815
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001816 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001817
1818 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1819 cp->randomizer);
1820 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001821 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1822 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001823 else
1824 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1825 0);
1826
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001827 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001828 hci_dev_put(hdev);
1829
1830 return err;
1831}
1832
1833static int remove_remote_oob_data(struct sock *sk, u16 index,
1834 unsigned char *data, u16 len)
1835{
1836 struct hci_dev *hdev;
1837 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1838 int err;
1839
1840 BT_DBG("hci%u ", index);
1841
1842 if (len != sizeof(*cp))
1843 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001844 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001845
1846 hdev = hci_dev_get(index);
1847 if (!hdev)
1848 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001849 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001850
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001851 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001852
1853 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1854 if (err < 0)
1855 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001856 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001857 else
1858 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1859 NULL, 0);
1860
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001861 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001862 hci_dev_put(hdev);
1863
1864 return err;
1865}
1866
Johan Hedberg450dfda2011-11-12 11:58:22 +02001867static int start_discovery(struct sock *sk, u16 index,
1868 unsigned char *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001869{
Johan Hedberg450dfda2011-11-12 11:58:22 +02001870 struct mgmt_cp_start_discovery *cp = (void *) data;
Johan Hedberg14a53662011-04-27 10:29:56 -04001871 struct pending_cmd *cmd;
1872 struct hci_dev *hdev;
1873 int err;
1874
1875 BT_DBG("hci%u", index);
1876
Johan Hedberg450dfda2011-11-12 11:58:22 +02001877 if (len != sizeof(*cp))
1878 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1879 MGMT_STATUS_INVALID_PARAMS);
1880
Johan Hedberg14a53662011-04-27 10:29:56 -04001881 hdev = hci_dev_get(index);
1882 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001883 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1884 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001885
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001886 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001887
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001888 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001889 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1890 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001891 goto failed;
1892 }
1893
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001894 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001895 if (!cmd) {
1896 err = -ENOMEM;
1897 goto failed;
1898 }
1899
Andre Guedes2519a1f2011-11-07 11:45:24 -03001900 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001901 if (err < 0)
1902 mgmt_pending_remove(cmd);
1903
1904failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001905 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001906 hci_dev_put(hdev);
1907
1908 return err;
1909}
1910
1911static int stop_discovery(struct sock *sk, u16 index)
1912{
1913 struct hci_dev *hdev;
1914 struct pending_cmd *cmd;
1915 int err;
1916
1917 BT_DBG("hci%u", index);
1918
1919 hdev = hci_dev_get(index);
1920 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001921 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1922 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001923
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001924 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001925
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001926 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001927 if (!cmd) {
1928 err = -ENOMEM;
1929 goto failed;
1930 }
1931
Andre Guedes023d5042011-11-04 14:16:52 -03001932 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001933 if (err < 0)
1934 mgmt_pending_remove(cmd);
1935
1936failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001937 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001938 hci_dev_put(hdev);
1939
1940 return err;
1941}
1942
Antti Julku7fbec222011-06-15 12:01:15 +03001943static int block_device(struct sock *sk, u16 index, unsigned char *data,
1944 u16 len)
1945{
1946 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001947 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001948 int err;
1949
1950 BT_DBG("hci%u", index);
1951
Antti Julku7fbec222011-06-15 12:01:15 +03001952 if (len != sizeof(*cp))
1953 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001954 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001955
1956 hdev = hci_dev_get(index);
1957 if (!hdev)
1958 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001959 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001960
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001961 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03001962
Antti Julku7fbec222011-06-15 12:01:15 +03001963 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001964 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001965 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1966 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03001967 else
1968 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1969 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001970
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001971 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001972 hci_dev_put(hdev);
1973
1974 return err;
1975}
1976
1977static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1978 u16 len)
1979{
1980 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001981 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001982 int err;
1983
1984 BT_DBG("hci%u", index);
1985
Antti Julku7fbec222011-06-15 12:01:15 +03001986 if (len != sizeof(*cp))
1987 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001988 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001989
1990 hdev = hci_dev_get(index);
1991 if (!hdev)
1992 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001993 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001994
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001995 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03001996
Antti Julku7fbec222011-06-15 12:01:15 +03001997 err = hci_blacklist_del(hdev, &cp->bdaddr);
1998
1999 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002000 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2001 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002002 else
2003 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2004 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002005
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002006 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002007 hci_dev_put(hdev);
2008
2009 return err;
2010}
2011
Antti Julkuf6422ec2011-06-22 13:11:56 +03002012static int set_fast_connectable(struct sock *sk, u16 index,
2013 unsigned char *data, u16 len)
2014{
2015 struct hci_dev *hdev;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002016 struct mgmt_mode *cp = (void *) data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002017 struct hci_cp_write_page_scan_activity acp;
2018 u8 type;
2019 int err;
2020
2021 BT_DBG("hci%u", index);
2022
2023 if (len != sizeof(*cp))
2024 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002025 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002026
2027 hdev = hci_dev_get(index);
2028 if (!hdev)
2029 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002030 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002031
2032 hci_dev_lock(hdev);
2033
Johan Hedbergf7c68692011-12-15 00:47:36 +02002034 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002035 type = PAGE_SCAN_TYPE_INTERLACED;
2036 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2037 } else {
2038 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2039 acp.interval = 0x0800; /* default 1.28 sec page scan */
2040 }
2041
2042 acp.window = 0x0012; /* default 11.25 msec page scan window */
2043
2044 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2045 sizeof(acp), &acp);
2046 if (err < 0) {
2047 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002048 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002049 goto done;
2050 }
2051
2052 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2053 if (err < 0) {
2054 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002055 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002056 goto done;
2057 }
2058
2059 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2060 NULL, 0);
2061done:
2062 hci_dev_unlock(hdev);
2063 hci_dev_put(hdev);
2064
2065 return err;
2066}
2067
Johan Hedberg03811012010-12-08 00:21:06 +02002068int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2069{
2070 unsigned char *buf;
2071 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002072 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002073 int err;
2074
2075 BT_DBG("got %zu bytes", msglen);
2076
2077 if (msglen < sizeof(*hdr))
2078 return -EINVAL;
2079
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002080 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002081 if (!buf)
2082 return -ENOMEM;
2083
2084 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2085 err = -EFAULT;
2086 goto done;
2087 }
2088
2089 hdr = (struct mgmt_hdr *) buf;
2090 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002091 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002092 len = get_unaligned_le16(&hdr->len);
2093
2094 if (len != msglen - sizeof(*hdr)) {
2095 err = -EINVAL;
2096 goto done;
2097 }
2098
2099 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002100 case MGMT_OP_READ_VERSION:
2101 err = read_version(sk);
2102 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002103 case MGMT_OP_READ_INDEX_LIST:
2104 err = read_index_list(sk);
2105 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002106 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002107 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002108 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002109 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002110 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002111 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002112 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002113 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002114 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002115 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002116 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002117 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002118 case MGMT_OP_SET_FAST_CONNECTABLE:
2119 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
2120 len);
2121 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002122 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002123 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002124 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002125 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002126 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002127 break;
2128 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002129 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002130 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002131 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002132 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002133 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002134 case MGMT_OP_LOAD_LINK_KEYS:
2135 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002136 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002137 case MGMT_OP_REMOVE_KEYS:
2138 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002139 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002140 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002141 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002142 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002143 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002144 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002145 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002146 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002147 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002148 break;
2149 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002150 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002151 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002152 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002153 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002154 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002155 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002156 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002157 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002158 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002159 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002160 break;
2161 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002162 err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr),
2163 len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002164 break;
Brian Gix604086b2011-11-23 08:28:33 -08002165 case MGMT_OP_USER_PASSKEY_REPLY:
2166 err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len);
2167 break;
2168 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
2169 err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr),
2170 len);
2171 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002172 case MGMT_OP_SET_LOCAL_NAME:
2173 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2174 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002175 case MGMT_OP_READ_LOCAL_OOB_DATA:
2176 err = read_local_oob_data(sk, index);
2177 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002178 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2179 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2180 break;
2181 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2182 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2183 len);
2184 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002185 case MGMT_OP_START_DISCOVERY:
Johan Hedberg450dfda2011-11-12 11:58:22 +02002186 err = start_discovery(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002187 break;
2188 case MGMT_OP_STOP_DISCOVERY:
2189 err = stop_discovery(sk, index);
2190 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002191 case MGMT_OP_BLOCK_DEVICE:
2192 err = block_device(sk, index, buf + sizeof(*hdr), len);
2193 break;
2194 case MGMT_OP_UNBLOCK_DEVICE:
2195 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
2196 break;
Johan Hedberg03811012010-12-08 00:21:06 +02002197 default:
2198 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002199 err = cmd_status(sk, index, opcode,
2200 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg03811012010-12-08 00:21:06 +02002201 break;
2202 }
2203
Johan Hedberge41d8b42010-12-13 21:07:03 +02002204 if (err < 0)
2205 goto done;
2206
Johan Hedberg03811012010-12-08 00:21:06 +02002207 err = msglen;
2208
2209done:
2210 kfree(buf);
2211 return err;
2212}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002213
Johan Hedbergb24752f2011-11-03 14:40:33 +02002214static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2215{
2216 u8 *status = data;
2217
2218 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2219 mgmt_pending_remove(cmd);
2220}
2221
Johan Hedberg744cf192011-11-08 20:40:14 +02002222int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002223{
Johan Hedberg744cf192011-11-08 20:40:14 +02002224 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002225}
2226
Johan Hedberg744cf192011-11-08 20:40:14 +02002227int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002228{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002229 u8 status = ENODEV;
2230
Johan Hedberg744cf192011-11-08 20:40:14 +02002231 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002232
Johan Hedberg744cf192011-11-08 20:40:14 +02002233 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002234}
2235
Johan Hedberg73f22f62010-12-29 16:00:25 +02002236struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002237 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002238 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002239 struct hci_dev *hdev;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002240};
2241
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002242static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002243{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002244 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002245
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002246 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002247
2248 list_del(&cmd->list);
2249
2250 if (match->sk == NULL) {
2251 match->sk = cmd->sk;
2252 sock_hold(match->sk);
2253 }
2254
2255 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002256}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002257
Johan Hedberg744cf192011-11-08 20:40:14 +02002258int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002259{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002260 struct cmd_lookup match = { powered, NULL, hdev };
2261 __le32 ev;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002262 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002263
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002264 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002265
Johan Hedbergb24752f2011-11-03 14:40:33 +02002266 if (!powered) {
2267 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002268 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002269 }
2270
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002271 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002272
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002273 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2274 match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002275
2276 if (match.sk)
2277 sock_put(match.sk);
2278
2279 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002280}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002281
Johan Hedberg744cf192011-11-08 20:40:14 +02002282int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002283{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002284 struct cmd_lookup match = { discoverable, NULL, hdev };
2285 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002286 int ret;
2287
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002288 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002289
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002290 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg73f22f62010-12-29 16:00:25 +02002291
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002292 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002293 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002294 if (match.sk)
2295 sock_put(match.sk);
2296
2297 return ret;
2298}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002299
Johan Hedberg744cf192011-11-08 20:40:14 +02002300int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002301{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002302 __le32 ev;
2303 struct cmd_lookup match = { connectable, NULL, hdev };
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002304 int ret;
2305
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002306 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2307 &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002308
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002309 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002310
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002311 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002312
2313 if (match.sk)
2314 sock_put(match.sk);
2315
2316 return ret;
2317}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002318
Johan Hedberg744cf192011-11-08 20:40:14 +02002319int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002320{
Johan Hedbergca69b792011-11-11 18:10:00 +02002321 u8 mgmt_err = mgmt_status(status);
2322
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002323 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002324 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002325 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002326
2327 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002328 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002329 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002330
2331 return 0;
2332}
2333
Johan Hedberg744cf192011-11-08 20:40:14 +02002334int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2335 u8 persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002336{
Johan Hedberg86742e12011-11-07 23:13:38 +02002337 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002338
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002339 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002340
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002341 ev.store_hint = persistent;
2342 bacpy(&ev.key.bdaddr, &key->bdaddr);
2343 ev.key.type = key->type;
2344 memcpy(ev.key.val, key->val, 16);
2345 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002346
Johan Hedberg744cf192011-11-08 20:40:14 +02002347 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002348}
Johan Hedbergf7520542011-01-20 12:34:39 +02002349
Johan Hedberg48264f02011-11-09 13:58:58 +02002350int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2351 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002352{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002353 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002354
Johan Hedbergf7520542011-01-20 12:34:39 +02002355 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002356 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002357
Johan Hedberg744cf192011-11-08 20:40:14 +02002358 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002359}
2360
Johan Hedberg8962ee72011-01-20 12:40:27 +02002361static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2362{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002363 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002364 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002365 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002366
Johan Hedberga38528f2011-01-22 06:46:43 +02002367 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002368 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002369
Szymon Janc4e51eae2011-02-25 19:05:48 +01002370 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002371
2372 *sk = cmd->sk;
2373 sock_hold(*sk);
2374
Johan Hedberga664b5b2011-02-19 12:06:02 -03002375 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002376}
2377
Johan Hedberga8a1d192011-11-10 15:54:38 +02002378static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2379{
2380 u8 *status = data;
2381 struct mgmt_cp_remove_keys *cp = cmd->param;
2382 struct mgmt_rp_remove_keys rp;
2383
2384 memset(&rp, 0, sizeof(rp));
2385 bacpy(&rp.bdaddr, &cp->bdaddr);
2386 if (status != NULL)
2387 rp.status = *status;
2388
2389 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2390 sizeof(rp));
2391
2392 mgmt_pending_remove(cmd);
2393}
2394
Johan Hedberg48264f02011-11-09 13:58:58 +02002395int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2396 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002397{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002398 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002399 struct sock *sk = NULL;
2400 int err;
2401
Johan Hedberg744cf192011-11-08 20:40:14 +02002402 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002403
Johan Hedbergf7520542011-01-20 12:34:39 +02002404 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002405 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002406
Johan Hedberg744cf192011-11-08 20:40:14 +02002407 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002408
2409 if (sk)
2410 sock_put(sk);
2411
Johan Hedberga8a1d192011-11-10 15:54:38 +02002412 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2413
Johan Hedberg8962ee72011-01-20 12:40:27 +02002414 return err;
2415}
2416
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002417int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002418{
2419 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002420 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002421 int err;
2422
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002423 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002424 if (!cmd)
2425 return -ENOENT;
2426
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002427 if (bdaddr) {
2428 struct mgmt_rp_disconnect rp;
2429
2430 bacpy(&rp.bdaddr, bdaddr);
2431 rp.status = status;
2432
2433 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2434 &rp, sizeof(rp));
2435 } else
2436 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002437 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002438
Johan Hedberga664b5b2011-02-19 12:06:02 -03002439 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002440
2441 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002442}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002443
Johan Hedberg48264f02011-11-09 13:58:58 +02002444int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2445 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002446{
2447 struct mgmt_ev_connect_failed ev;
2448
Johan Hedberg4c659c32011-11-07 23:13:39 +02002449 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002450 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002451 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002452
Johan Hedberg744cf192011-11-08 20:40:14 +02002453 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002454}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002455
Johan Hedberg744cf192011-11-08 20:40:14 +02002456int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002457{
2458 struct mgmt_ev_pin_code_request ev;
2459
Johan Hedberg980e1a52011-01-22 06:10:07 +02002460 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002461 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002462
Johan Hedberg744cf192011-11-08 20:40:14 +02002463 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002464 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002465}
2466
Johan Hedberg744cf192011-11-08 20:40:14 +02002467int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2468 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002469{
2470 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002471 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002472 int err;
2473
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002474 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002475 if (!cmd)
2476 return -ENOENT;
2477
Johan Hedbergac56fb12011-02-19 12:05:59 -03002478 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002479 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002480
Johan Hedberg744cf192011-11-08 20:40:14 +02002481 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002482 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002483
Johan Hedberga664b5b2011-02-19 12:06:02 -03002484 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002485
2486 return err;
2487}
2488
Johan Hedberg744cf192011-11-08 20:40:14 +02002489int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2490 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002491{
2492 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002493 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002494 int err;
2495
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002496 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002497 if (!cmd)
2498 return -ENOENT;
2499
Johan Hedbergac56fb12011-02-19 12:05:59 -03002500 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002501 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002502
Johan Hedberg744cf192011-11-08 20:40:14 +02002503 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002504 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002505
Johan Hedberga664b5b2011-02-19 12:06:02 -03002506 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002507
2508 return err;
2509}
Johan Hedberga5c29682011-02-19 12:05:57 -03002510
Johan Hedberg744cf192011-11-08 20:40:14 +02002511int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2512 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002513{
2514 struct mgmt_ev_user_confirm_request ev;
2515
Johan Hedberg744cf192011-11-08 20:40:14 +02002516 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002517
Johan Hedberga5c29682011-02-19 12:05:57 -03002518 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002519 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002520 put_unaligned_le32(value, &ev.value);
2521
Johan Hedberg744cf192011-11-08 20:40:14 +02002522 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002523 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002524}
2525
Brian Gix604086b2011-11-23 08:28:33 -08002526int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2527{
2528 struct mgmt_ev_user_passkey_request ev;
2529
2530 BT_DBG("%s", hdev->name);
2531
2532 bacpy(&ev.bdaddr, bdaddr);
2533
2534 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2535 NULL);
2536}
2537
Brian Gix0df4c182011-11-16 13:53:13 -08002538static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002539 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002540{
2541 struct pending_cmd *cmd;
2542 struct mgmt_rp_user_confirm_reply rp;
2543 int err;
2544
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002545 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002546 if (!cmd)
2547 return -ENOENT;
2548
Johan Hedberga5c29682011-02-19 12:05:57 -03002549 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002550 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002551 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002552
Johan Hedberga664b5b2011-02-19 12:06:02 -03002553 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002554
2555 return err;
2556}
2557
Johan Hedberg744cf192011-11-08 20:40:14 +02002558int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2559 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002560{
Brian Gix0df4c182011-11-16 13:53:13 -08002561 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002562 MGMT_OP_USER_CONFIRM_REPLY);
2563}
2564
Johan Hedberg744cf192011-11-08 20:40:14 +02002565int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2566 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002567{
Brian Gix0df4c182011-11-16 13:53:13 -08002568 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002569 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2570}
Johan Hedberg2a611692011-02-19 12:06:00 -03002571
Brian Gix604086b2011-11-23 08:28:33 -08002572int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2573 u8 status)
2574{
2575 return user_pairing_resp_complete(hdev, bdaddr, status,
2576 MGMT_OP_USER_PASSKEY_REPLY);
2577}
2578
2579int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2580 bdaddr_t *bdaddr, u8 status)
2581{
2582 return user_pairing_resp_complete(hdev, bdaddr, status,
2583 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2584}
2585
Johan Hedberg744cf192011-11-08 20:40:14 +02002586int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002587{
2588 struct mgmt_ev_auth_failed ev;
2589
Johan Hedberg2a611692011-02-19 12:06:00 -03002590 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002591 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002592
Johan Hedberg744cf192011-11-08 20:40:14 +02002593 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002594}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002595
Johan Hedberg744cf192011-11-08 20:40:14 +02002596int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002597{
2598 struct pending_cmd *cmd;
2599 struct mgmt_cp_set_local_name ev;
2600 int err;
2601
2602 memset(&ev, 0, sizeof(ev));
2603 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2604
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002605 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002606 if (!cmd)
2607 goto send_event;
2608
2609 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002610 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002611 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002612 goto failed;
2613 }
2614
Johan Hedberg744cf192011-11-08 20:40:14 +02002615 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002616
Johan Hedberg744cf192011-11-08 20:40:14 +02002617 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002618 sizeof(ev));
2619 if (err < 0)
2620 goto failed;
2621
2622send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002623 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002624 cmd ? cmd->sk : NULL);
2625
2626failed:
2627 if (cmd)
2628 mgmt_pending_remove(cmd);
2629 return err;
2630}
Szymon Jancc35938b2011-03-22 13:12:21 +01002631
Johan Hedberg744cf192011-11-08 20:40:14 +02002632int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2633 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002634{
2635 struct pending_cmd *cmd;
2636 int err;
2637
Johan Hedberg744cf192011-11-08 20:40:14 +02002638 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002639
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002640 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002641 if (!cmd)
2642 return -ENOENT;
2643
2644 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002645 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002646 MGMT_OP_READ_LOCAL_OOB_DATA,
2647 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002648 } else {
2649 struct mgmt_rp_read_local_oob_data rp;
2650
2651 memcpy(rp.hash, hash, sizeof(rp.hash));
2652 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2653
Johan Hedberg744cf192011-11-08 20:40:14 +02002654 err = cmd_complete(cmd->sk, hdev->id,
2655 MGMT_OP_READ_LOCAL_OOB_DATA,
2656 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002657 }
2658
2659 mgmt_pending_remove(cmd);
2660
2661 return err;
2662}
Johan Hedberge17acd42011-03-30 23:57:16 +03002663
Johan Hedberg48264f02011-11-09 13:58:58 +02002664int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2665 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002666{
2667 struct mgmt_ev_device_found ev;
2668
2669 memset(&ev, 0, sizeof(ev));
2670
Johan Hedberg4c659c32011-11-07 23:13:39 +02002671 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002672 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002673 ev.rssi = rssi;
2674
2675 if (eir)
2676 memcpy(ev.eir, eir, sizeof(ev.eir));
2677
Andre Guedesf8523592011-09-09 18:56:26 -03002678 if (dev_class)
2679 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2680
Johan Hedberg744cf192011-11-08 20:40:14 +02002681 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002682}
Johan Hedberga88a9652011-03-30 13:18:12 +03002683
Johan Hedberg744cf192011-11-08 20:40:14 +02002684int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002685{
2686 struct mgmt_ev_remote_name ev;
2687
2688 memset(&ev, 0, sizeof(ev));
2689
2690 bacpy(&ev.bdaddr, bdaddr);
2691 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2692
Johan Hedberg744cf192011-11-08 20:40:14 +02002693 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002694}
Johan Hedberg314b2382011-04-27 10:29:57 -04002695
Andre Guedes7a135102011-11-09 17:14:25 -03002696int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002697{
2698 struct pending_cmd *cmd;
2699 int err;
2700
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002701 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002702 if (!cmd)
2703 return -ENOENT;
2704
Johan Hedbergca69b792011-11-11 18:10:00 +02002705 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002706 mgmt_pending_remove(cmd);
2707
2708 return err;
2709}
2710
Andre Guedese6d465c2011-11-09 17:14:26 -03002711int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2712{
2713 struct pending_cmd *cmd;
2714 int err;
2715
2716 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2717 if (!cmd)
2718 return -ENOENT;
2719
2720 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
2721 mgmt_pending_remove(cmd);
2722
2723 return err;
2724}
2725
Johan Hedberg744cf192011-11-08 20:40:14 +02002726int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002727{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002728 struct pending_cmd *cmd;
2729
2730 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002731 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002732 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002733 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002734
2735 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002736 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002737 mgmt_pending_remove(cmd);
2738 }
2739
Johan Hedberg744cf192011-11-08 20:40:14 +02002740 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002741 sizeof(discovering), NULL);
2742}
Antti Julku5e762442011-08-25 16:48:02 +03002743
Johan Hedberg744cf192011-11-08 20:40:14 +02002744int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002745{
2746 struct pending_cmd *cmd;
2747 struct mgmt_ev_device_blocked ev;
2748
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002749 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002750
2751 bacpy(&ev.bdaddr, bdaddr);
2752
Johan Hedberg744cf192011-11-08 20:40:14 +02002753 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2754 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002755}
2756
Johan Hedberg744cf192011-11-08 20:40:14 +02002757int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002758{
2759 struct pending_cmd *cmd;
2760 struct mgmt_ev_device_unblocked ev;
2761
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002762 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002763
2764 bacpy(&ev.bdaddr, bdaddr);
2765
Johan Hedberg744cf192011-11-08 20:40:14 +02002766 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2767 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002768}