blob: bc8e59dda78e2bf72f81c3eeacea748d5cbd78ae [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Johan Hedbergca69b792011-11-11 18:10:00 +020025#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Johan Hedberg02d98122010-12-13 21:07:04 +020035#define MGMT_VERSION 0
36#define MGMT_REVISION 1
37
Andre Guedes2519a1f2011-11-07 11:45:24 -030038#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
39
Johan Hedberg7d785252011-12-15 00:47:39 +020040#define SERVICE_CACHE_TIMEOUT (5 * 1000)
41
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042struct pending_cmd {
43 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020044 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010046 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020047 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030048 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020049};
50
Johan Hedbergca69b792011-11-11 18:10:00 +020051/* HCI to MGMT error code conversion table */
52static u8 mgmt_status_table[] = {
53 MGMT_STATUS_SUCCESS,
54 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
55 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
56 MGMT_STATUS_FAILED, /* Hardware Failure */
57 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
58 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
59 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
60 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
61 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
62 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
63 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
64 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
65 MGMT_STATUS_BUSY, /* Command Disallowed */
66 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
67 MGMT_STATUS_REJECTED, /* Rejected Security */
68 MGMT_STATUS_REJECTED, /* Rejected Personal */
69 MGMT_STATUS_TIMEOUT, /* Host Timeout */
70 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
71 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
72 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
73 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
74 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
75 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
76 MGMT_STATUS_BUSY, /* Repeated Attempts */
77 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
78 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
79 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
80 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
81 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
82 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
83 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
84 MGMT_STATUS_FAILED, /* Unspecified Error */
85 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
86 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
87 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
88 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
89 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
90 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
91 MGMT_STATUS_FAILED, /* Unit Link Key Used */
92 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
93 MGMT_STATUS_TIMEOUT, /* Instant Passed */
94 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
95 MGMT_STATUS_FAILED, /* Transaction Collision */
96 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
97 MGMT_STATUS_REJECTED, /* QoS Rejected */
98 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
99 MGMT_STATUS_REJECTED, /* Insufficient Security */
100 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
101 MGMT_STATUS_BUSY, /* Role Switch Pending */
102 MGMT_STATUS_FAILED, /* Slot Violation */
103 MGMT_STATUS_FAILED, /* Role Switch Failed */
104 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
105 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
106 MGMT_STATUS_BUSY, /* Host Busy Pairing */
107 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
108 MGMT_STATUS_BUSY, /* Controller Busy */
109 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
110 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
111 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
112 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
113 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
114};
115
116static u8 mgmt_status(u8 hci_status)
117{
118 if (hci_status < ARRAY_SIZE(mgmt_status_table))
119 return mgmt_status_table[hci_status];
120
121 return MGMT_STATUS_FAILED;
122}
123
Szymon Janc4e51eae2011-02-25 19:05:48 +0100124static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200125{
126 struct sk_buff *skb;
127 struct mgmt_hdr *hdr;
128 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300129 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200130
Szymon Janc34eb5252011-02-28 14:10:08 +0100131 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200132
133 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
134 if (!skb)
135 return -ENOMEM;
136
137 hdr = (void *) skb_put(skb, sizeof(*hdr));
138
139 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100140 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200141 hdr->len = cpu_to_le16(sizeof(*ev));
142
143 ev = (void *) skb_put(skb, sizeof(*ev));
144 ev->status = status;
145 put_unaligned_le16(cmd, &ev->opcode);
146
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300147 err = sock_queue_rcv_skb(sk, skb);
148 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200149 kfree_skb(skb);
150
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300151 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200152}
153
Szymon Janc4e51eae2011-02-25 19:05:48 +0100154static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
155 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200156{
157 struct sk_buff *skb;
158 struct mgmt_hdr *hdr;
159 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300160 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200161
162 BT_DBG("sock %p", sk);
163
Johan Hedberga38528f2011-01-22 06:46:43 +0200164 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200165 if (!skb)
166 return -ENOMEM;
167
168 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200169
Johan Hedberg02d98122010-12-13 21:07:04 +0200170 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100171 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200172 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200173
Johan Hedberga38528f2011-01-22 06:46:43 +0200174 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
175 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100176
177 if (rp)
178 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200179
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300180 err = sock_queue_rcv_skb(sk, skb);
181 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200182 kfree_skb(skb);
183
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300184 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200185}
186
Johan Hedberga38528f2011-01-22 06:46:43 +0200187static int read_version(struct sock *sk)
188{
189 struct mgmt_rp_read_version rp;
190
191 BT_DBG("sock %p", sk);
192
193 rp.version = MGMT_VERSION;
194 put_unaligned_le16(MGMT_REVISION, &rp.revision);
195
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
197 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200198}
199
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200200static int read_index_list(struct sock *sk)
201{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200202 struct mgmt_rp_read_index_list *rp;
203 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200204 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200205 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200206 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200207 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200208
209 BT_DBG("sock %p", sk);
210
211 read_lock(&hci_dev_list_lock);
212
213 count = 0;
214 list_for_each(p, &hci_dev_list) {
215 count++;
216 }
217
Johan Hedberga38528f2011-01-22 06:46:43 +0200218 rp_len = sizeof(*rp) + (2 * count);
219 rp = kmalloc(rp_len, GFP_ATOMIC);
220 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100221 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200222 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100223 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200224
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200225 put_unaligned_le16(count, &rp->num_controllers);
226
227 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200228 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberg32435532011-11-07 22:16:04 +0200229 if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200230 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200231
232 if (test_bit(HCI_SETUP, &d->flags))
233 continue;
234
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200235 put_unaligned_le16(d->id, &rp->index[i++]);
236 BT_DBG("Added hci%u", d->id);
237 }
238
239 read_unlock(&hci_dev_list_lock);
240
Szymon Janc4e51eae2011-02-25 19:05:48 +0100241 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
242 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200243
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 kfree(rp);
245
246 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200247}
248
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200249static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200250{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200251 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200252
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200253 settings |= MGMT_SETTING_POWERED;
254 settings |= MGMT_SETTING_CONNECTABLE;
255 settings |= MGMT_SETTING_FAST_CONNECTABLE;
256 settings |= MGMT_SETTING_DISCOVERABLE;
257 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200258
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200259 if (hdev->features[6] & LMP_SIMPLE_PAIR)
260 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200261
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200262 if (!(hdev->features[4] & LMP_NO_BREDR)) {
263 settings |= MGMT_SETTING_BREDR;
264 settings |= MGMT_SETTING_LINK_SECURITY;
265 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200266
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200267 if (hdev->features[4] & LMP_LE)
268 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200269
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200270 return settings;
271}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200272
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200273static u32 get_current_settings(struct hci_dev *hdev)
274{
275 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200276
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200277 if (test_bit(HCI_UP, &hdev->flags))
278 settings |= MGMT_SETTING_POWERED;
279 else
280 return settings;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200281
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200282 if (test_bit(HCI_PSCAN, &hdev->flags))
283 settings |= MGMT_SETTING_CONNECTABLE;
284
285 if (test_bit(HCI_ISCAN, &hdev->flags))
286 settings |= MGMT_SETTING_DISCOVERABLE;
287
288 if (test_bit(HCI_PAIRABLE, &hdev->flags))
289 settings |= MGMT_SETTING_PAIRABLE;
290
291 if (!(hdev->features[4] & LMP_NO_BREDR))
292 settings |= MGMT_SETTING_BREDR;
293
Andre Guedes59e29402011-12-30 10:34:03 -0300294 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200295 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200296
297 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200298 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200299
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200300 if (hdev->ssp_mode > 0)
301 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200302
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200303 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200304}
305
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300306#define EIR_FLAGS 0x01 /* flags */
307#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
308#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
309#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
310#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
311#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
312#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
313#define EIR_NAME_SHORT 0x08 /* shortened local name */
314#define EIR_NAME_COMPLETE 0x09 /* complete local name */
315#define EIR_TX_POWER 0x0A /* transmit power level */
316#define EIR_DEVICE_ID 0x10 /* device ID */
317
318#define PNP_INFO_SVCLASS_ID 0x1200
319
320static u8 bluetooth_base_uuid[] = {
321 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
322 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
323};
324
325static u16 get_uuid16(u8 *uuid128)
326{
327 u32 val;
328 int i;
329
330 for (i = 0; i < 12; i++) {
331 if (bluetooth_base_uuid[i] != uuid128[i])
332 return 0;
333 }
334
335 memcpy(&val, &uuid128[12], 4);
336
337 val = le32_to_cpu(val);
338 if (val > 0xffff)
339 return 0;
340
341 return (u16) val;
342}
343
344static void create_eir(struct hci_dev *hdev, u8 *data)
345{
346 u8 *ptr = data;
347 u16 eir_len = 0;
348 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
349 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200350 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300351 size_t name_len;
352
353 name_len = strlen(hdev->dev_name);
354
355 if (name_len > 0) {
356 /* EIR Data type */
357 if (name_len > 48) {
358 name_len = 48;
359 ptr[1] = EIR_NAME_SHORT;
360 } else
361 ptr[1] = EIR_NAME_COMPLETE;
362
363 /* EIR Data length */
364 ptr[0] = name_len + 1;
365
366 memcpy(ptr + 2, hdev->dev_name, name_len);
367
368 eir_len += (name_len + 2);
369 ptr += (name_len + 2);
370 }
371
372 memset(uuid16_list, 0, sizeof(uuid16_list));
373
374 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200375 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300376 u16 uuid16;
377
378 uuid16 = get_uuid16(uuid->uuid);
379 if (uuid16 == 0)
380 return;
381
382 if (uuid16 < 0x1100)
383 continue;
384
385 if (uuid16 == PNP_INFO_SVCLASS_ID)
386 continue;
387
388 /* Stop if not enough space to put next UUID */
389 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
390 truncated = 1;
391 break;
392 }
393
394 /* Check for duplicates */
395 for (i = 0; uuid16_list[i] != 0; i++)
396 if (uuid16_list[i] == uuid16)
397 break;
398
399 if (uuid16_list[i] == 0) {
400 uuid16_list[i] = uuid16;
401 eir_len += sizeof(u16);
402 }
403 }
404
405 if (uuid16_list[0] != 0) {
406 u8 *length = ptr;
407
408 /* EIR Data type */
409 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
410
411 ptr += 2;
412 eir_len += 2;
413
414 for (i = 0; uuid16_list[i] != 0; i++) {
415 *ptr++ = (uuid16_list[i] & 0x00ff);
416 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
417 }
418
419 /* EIR Data length */
420 *length = (i * sizeof(u16)) + 1;
421 }
422}
423
424static int update_eir(struct hci_dev *hdev)
425{
426 struct hci_cp_write_eir cp;
427
428 if (!(hdev->features[6] & LMP_EXT_INQ))
429 return 0;
430
431 if (hdev->ssp_mode == 0)
432 return 0;
433
434 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
435 return 0;
436
437 memset(&cp, 0, sizeof(cp));
438
439 create_eir(hdev, cp.data);
440
441 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
442 return 0;
443
444 memcpy(hdev->eir, cp.data, sizeof(cp.data));
445
446 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
447}
448
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200449static u8 get_service_classes(struct hci_dev *hdev)
450{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300451 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200452 u8 val = 0;
453
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300454 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200455 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200456
457 return val;
458}
459
460static int update_class(struct hci_dev *hdev)
461{
462 u8 cod[3];
463
464 BT_DBG("%s", hdev->name);
465
466 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
467 return 0;
468
469 cod[0] = hdev->minor_class;
470 cod[1] = hdev->major_class;
471 cod[2] = get_service_classes(hdev);
472
473 if (memcmp(cod, hdev->dev_class, 3) == 0)
474 return 0;
475
476 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
477}
478
Johan Hedberg7d785252011-12-15 00:47:39 +0200479static void service_cache_off(struct work_struct *work)
480{
481 struct hci_dev *hdev = container_of(work, struct hci_dev,
482 service_cache.work);
483
484 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags))
485 return;
486
487 hci_dev_lock(hdev);
488
489 update_eir(hdev);
490 update_class(hdev);
491
492 hci_dev_unlock(hdev);
493}
494
495static void mgmt_init_hdev(struct hci_dev *hdev)
496{
497 if (!test_and_set_bit(HCI_MGMT, &hdev->flags))
498 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
499
500 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->flags))
501 schedule_delayed_work(&hdev->service_cache,
502 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
503}
504
Johan Hedberg03811012010-12-08 00:21:06 +0200505static int read_controller_info(struct sock *sk, u16 index)
506{
507 struct mgmt_rp_read_info rp;
508 struct hci_dev *hdev;
509
510 BT_DBG("sock %p hci%u", sk, index);
511
512 hdev = hci_dev_get(index);
513 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200514 return cmd_status(sk, index, MGMT_OP_READ_INFO,
515 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200516
517 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
518 cancel_delayed_work_sync(&hdev->power_off);
519
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300520 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200521
Johan Hedberg7d785252011-12-15 00:47:39 +0200522 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
523 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200524
525 memset(&rp, 0, sizeof(rp));
526
Johan Hedberg03811012010-12-08 00:21:06 +0200527 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200528
529 rp.version = hdev->hci_ver;
530
Johan Hedberg03811012010-12-08 00:21:06 +0200531 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200532
533 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
534 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
535
536 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200537
538 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
539
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300540 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200541 hci_dev_put(hdev);
542
543 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
544}
545
546static void mgmt_pending_free(struct pending_cmd *cmd)
547{
548 sock_put(cmd->sk);
549 kfree(cmd->param);
550 kfree(cmd);
551}
552
553static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
554 struct hci_dev *hdev,
555 void *data, u16 len)
556{
557 struct pending_cmd *cmd;
558
559 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
560 if (!cmd)
561 return NULL;
562
563 cmd->opcode = opcode;
564 cmd->index = hdev->id;
565
566 cmd->param = kmalloc(len, GFP_ATOMIC);
567 if (!cmd->param) {
568 kfree(cmd);
569 return NULL;
570 }
571
572 if (data)
573 memcpy(cmd->param, data, len);
574
575 cmd->sk = sk;
576 sock_hold(sk);
577
578 list_add(&cmd->list, &hdev->mgmt_pending);
579
580 return cmd;
581}
582
583static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
584 void (*cb)(struct pending_cmd *cmd, void *data),
585 void *data)
586{
587 struct list_head *p, *n;
588
589 list_for_each_safe(p, n, &hdev->mgmt_pending) {
590 struct pending_cmd *cmd;
591
592 cmd = list_entry(p, struct pending_cmd, list);
593
594 if (opcode > 0 && cmd->opcode != opcode)
595 continue;
596
597 cb(cmd, data);
598 }
599}
600
601static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
602{
603 struct pending_cmd *cmd;
604
605 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
606 if (cmd->opcode == opcode)
607 return cmd;
608 }
609
610 return NULL;
611}
612
613static void mgmt_pending_remove(struct pending_cmd *cmd)
614{
615 list_del(&cmd->list);
616 mgmt_pending_free(cmd);
617}
618
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200619static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200620{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200621 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200622
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200623 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200624}
625
Johan Hedberg03811012010-12-08 00:21:06 +0200626static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
627{
628 struct mgmt_mode *cp;
629 struct hci_dev *hdev;
630 struct pending_cmd *cmd;
631 int err, up;
632
633 cp = (void *) data;
634
635 BT_DBG("request for hci%u", index);
636
637 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200638 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
639 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200640
641 hdev = hci_dev_get(index);
642 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200643 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
644 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200645
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300646 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200647
648 up = test_bit(HCI_UP, &hdev->flags);
649 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200650 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200651 goto failed;
652 }
653
654 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200655 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
656 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200657 goto failed;
658 }
659
660 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
661 if (!cmd) {
662 err = -ENOMEM;
663 goto failed;
664 }
665
666 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200667 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200668 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200669 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200670
671 err = 0;
672
673failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300674 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200675 hci_dev_put(hdev);
676 return err;
677}
678
679static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
680 u16 len)
681{
682 struct mgmt_cp_set_discoverable *cp;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200683 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200684 struct pending_cmd *cmd;
685 u8 scan;
686 int err;
687
688 cp = (void *) data;
689
690 BT_DBG("request for hci%u", index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200691
692 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200693 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
694 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200695
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200696 hdev = hci_dev_get(index);
697 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200698 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
699 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200700
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300701 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200702
703 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200704 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
705 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200706 goto failed;
707 }
708
709 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
710 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200711 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
712 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200713 goto failed;
714 }
715
716 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
717 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200718 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200719 goto failed;
720 }
721
722 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
723 if (!cmd) {
724 err = -ENOMEM;
725 goto failed;
726 }
727
728 scan = SCAN_PAGE;
729
730 if (cp->val)
731 scan |= SCAN_INQUIRY;
732 else
733 cancel_delayed_work(&hdev->discov_off);
734
735 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
736 if (err < 0)
737 mgmt_pending_remove(cmd);
738
Johan Hedberg03811012010-12-08 00:21:06 +0200739 if (cp->val)
740 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
741
Johan Hedberge41d8b42010-12-13 21:07:03 +0200742failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300743 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200744 hci_dev_put(hdev);
745
746 return err;
747}
748
749static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
750 u16 len)
751{
752 struct mgmt_mode *cp;
753 struct hci_dev *hdev;
754 struct pending_cmd *cmd;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200755 u8 scan;
756 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200757
758 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200759
760 BT_DBG("request for hci%u", index);
761
762 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200763 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
764 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200765
766 hdev = hci_dev_get(index);
767 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200768 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
769 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200770
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300771 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200772
773 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200774 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
775 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200776 goto failed;
777 }
778
779 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
780 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200781 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
782 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200783 goto failed;
784 }
785
786 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200787 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200788 goto failed;
789 }
790
791 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
792 if (!cmd) {
793 err = -ENOMEM;
794 goto failed;
795 }
796
797 if (cp->val)
798 scan = SCAN_PAGE;
799 else
800 scan = 0;
801
802 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
803 if (err < 0)
804 mgmt_pending_remove(cmd);
805
806failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300807 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200808 hci_dev_put(hdev);
809
810 return err;
811}
812
813static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
814 u16 data_len, struct sock *skip_sk)
815{
816 struct sk_buff *skb;
817 struct mgmt_hdr *hdr;
818
819 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
820 if (!skb)
821 return -ENOMEM;
822
823 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
824
825 hdr = (void *) skb_put(skb, sizeof(*hdr));
826 hdr->opcode = cpu_to_le16(event);
827 if (hdev)
828 hdr->index = cpu_to_le16(hdev->id);
829 else
830 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
831 hdr->len = cpu_to_le16(data_len);
832
833 if (data)
834 memcpy(skb_put(skb, data_len), data, data_len);
835
836 hci_send_to_sock(NULL, skb, skip_sk);
837 kfree_skb(skb);
838
839 return 0;
840}
841
Johan Hedberg73f22f62010-12-29 16:00:25 +0200842static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
843 u16 len)
844{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200845 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200846 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200847 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200848 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200849
850 cp = (void *) data;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200851
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200852 BT_DBG("request for hci%u", index);
853
854 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200855 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
856 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200857
858 hdev = hci_dev_get(index);
859 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200860 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
861 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200862
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300863 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200864
865 if (cp->val)
866 set_bit(HCI_PAIRABLE, &hdev->flags);
867 else
868 clear_bit(HCI_PAIRABLE, &hdev->flags);
869
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200870 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200871 if (err < 0)
872 goto failed;
873
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200874 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200875
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200876 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200877
878failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300879 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200880 hci_dev_put(hdev);
881
882 return err;
883}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200884
Szymon Janc4e51eae2011-02-25 19:05:48 +0100885static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200886{
887 struct mgmt_cp_add_uuid *cp;
888 struct hci_dev *hdev;
889 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200890 int err;
891
892 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200893
Szymon Janc4e51eae2011-02-25 19:05:48 +0100894 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200895
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100896 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200897 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
898 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100899
Szymon Janc4e51eae2011-02-25 19:05:48 +0100900 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200901 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200902 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
903 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200904
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300905 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200906
907 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
908 if (!uuid) {
909 err = -ENOMEM;
910 goto failed;
911 }
912
913 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200914 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200915
916 list_add(&uuid->list, &hdev->uuids);
917
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200918 err = update_class(hdev);
919 if (err < 0)
920 goto failed;
921
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300922 err = update_eir(hdev);
923 if (err < 0)
924 goto failed;
925
Szymon Janc4e51eae2011-02-25 19:05:48 +0100926 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200927
928failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300929 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200930 hci_dev_put(hdev);
931
932 return err;
933}
934
Szymon Janc4e51eae2011-02-25 19:05:48 +0100935static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200936{
937 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100938 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200939 struct hci_dev *hdev;
940 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 +0200941 int err, found;
942
943 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200944
Szymon Janc4e51eae2011-02-25 19:05:48 +0100945 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200946
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100947 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200948 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
949 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100950
Szymon Janc4e51eae2011-02-25 19:05:48 +0100951 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200952 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200953 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
954 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200955
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300956 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200957
958 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
959 err = hci_uuids_clear(hdev);
960 goto unlock;
961 }
962
963 found = 0;
964
965 list_for_each_safe(p, n, &hdev->uuids) {
966 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
967
968 if (memcmp(match->uuid, cp->uuid, 16) != 0)
969 continue;
970
971 list_del(&match->list);
972 found++;
973 }
974
975 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200976 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
977 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200978 goto unlock;
979 }
980
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200981 err = update_class(hdev);
982 if (err < 0)
983 goto unlock;
984
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300985 err = update_eir(hdev);
986 if (err < 0)
987 goto unlock;
988
Szymon Janc4e51eae2011-02-25 19:05:48 +0100989 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200990
991unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300992 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200993 hci_dev_put(hdev);
994
995 return err;
996}
997
Szymon Janc4e51eae2011-02-25 19:05:48 +0100998static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
999 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001000{
1001 struct hci_dev *hdev;
1002 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001003 int err;
1004
1005 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001006
Szymon Janc4e51eae2011-02-25 19:05:48 +01001007 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001008
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001009 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001010 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1011 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001012
Szymon Janc4e51eae2011-02-25 19:05:48 +01001013 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001014 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001015 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1016 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001017
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001018 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001019
1020 hdev->major_class = cp->major;
1021 hdev->minor_class = cp->minor;
1022
Johan Hedberg7d785252011-12-15 00:47:39 +02001023 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) {
1024 hci_dev_unlock(hdev);
1025 cancel_delayed_work_sync(&hdev->service_cache);
1026 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001027 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001028 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001029
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001030 err = update_class(hdev);
1031
1032 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001033 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001034
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001035 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001036 hci_dev_put(hdev);
1037
1038 return err;
1039}
1040
Johan Hedberg86742e12011-11-07 23:13:38 +02001041static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
1042 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001043{
1044 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001045 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001046 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001047 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001048
1049 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001050
1051 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001052 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1053 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001054
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001055 key_count = get_unaligned_le16(&cp->key_count);
1056
Johan Hedberg86742e12011-11-07 23:13:38 +02001057 expected_len = sizeof(*cp) + key_count *
1058 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001059 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001060 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001061 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001062 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1063 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001064 }
1065
Szymon Janc4e51eae2011-02-25 19:05:48 +01001066 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001067 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001068 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1069 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001070
Szymon Janc4e51eae2011-02-25 19:05:48 +01001071 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001072 key_count);
1073
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001074 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001075
1076 hci_link_keys_clear(hdev);
1077
1078 set_bit(HCI_LINK_KEYS, &hdev->flags);
1079
1080 if (cp->debug_keys)
1081 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1082 else
1083 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1084
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001085 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001086 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001087
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001088 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001089 key->pin_len);
1090 }
1091
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001092 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1093
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001094 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001095 hci_dev_put(hdev);
1096
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001097 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001098}
1099
Johan Hedberg86742e12011-11-07 23:13:38 +02001100static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
1101 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001102{
1103 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001104 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001105 struct mgmt_rp_remove_keys rp;
1106 struct hci_cp_disconnect dc;
1107 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001108 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001109 int err;
1110
1111 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001112
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001113 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001114 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1115 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001116
Szymon Janc4e51eae2011-02-25 19:05:48 +01001117 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001118 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001119 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1120 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001121
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001122 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001123
Johan Hedberga8a1d192011-11-10 15:54:38 +02001124 memset(&rp, 0, sizeof(rp));
1125 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001126 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001127
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001128 err = hci_remove_link_key(hdev, &cp->bdaddr);
1129 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001130 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001131 goto unlock;
1132 }
1133
Johan Hedberga8a1d192011-11-10 15:54:38 +02001134 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1135 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1136 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001137 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001138 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001139
1140 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001141 if (!conn) {
1142 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1143 sizeof(rp));
1144 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001145 }
1146
Johan Hedberga8a1d192011-11-10 15:54:38 +02001147 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1148 if (!cmd) {
1149 err = -ENOMEM;
1150 goto unlock;
1151 }
1152
1153 put_unaligned_le16(conn->handle, &dc.handle);
1154 dc.reason = 0x13; /* Remote User Terminated Connection */
1155 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1156 if (err < 0)
1157 mgmt_pending_remove(cmd);
1158
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001159unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001160 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001161 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1162 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001163 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001164 hci_dev_put(hdev);
1165
1166 return err;
1167}
1168
Szymon Janc4e51eae2011-02-25 19:05:48 +01001169static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001170{
1171 struct hci_dev *hdev;
1172 struct mgmt_cp_disconnect *cp;
1173 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001174 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001175 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001176 int err;
1177
1178 BT_DBG("");
1179
1180 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001181
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001182 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001183 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1184 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001185
Szymon Janc4e51eae2011-02-25 19:05:48 +01001186 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001187 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001188 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1189 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001190
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001191 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001192
1193 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001194 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1195 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001196 goto failed;
1197 }
1198
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001199 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001200 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1201 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001202 goto failed;
1203 }
1204
1205 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001206 if (!conn)
1207 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1208
Johan Hedberg8962ee72011-01-20 12:40:27 +02001209 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001210 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1211 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001212 goto failed;
1213 }
1214
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001215 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001216 if (!cmd) {
1217 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001218 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001219 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001220
1221 put_unaligned_le16(conn->handle, &dc.handle);
1222 dc.reason = 0x13; /* Remote User Terminated Connection */
1223
1224 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1225 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001226 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001227
1228failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001229 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001230 hci_dev_put(hdev);
1231
1232 return err;
1233}
1234
Johan Hedberg48264f02011-11-09 13:58:58 +02001235static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001236{
1237 switch (link_type) {
1238 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001239 switch (addr_type) {
1240 case ADDR_LE_DEV_PUBLIC:
1241 return MGMT_ADDR_LE_PUBLIC;
1242 case ADDR_LE_DEV_RANDOM:
1243 return MGMT_ADDR_LE_RANDOM;
1244 default:
1245 return MGMT_ADDR_INVALID;
1246 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001247 case ACL_LINK:
1248 return MGMT_ADDR_BREDR;
1249 default:
1250 return MGMT_ADDR_INVALID;
1251 }
1252}
1253
Szymon Janc8ce62842011-03-01 16:55:32 +01001254static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001255{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001256 struct mgmt_rp_get_connections *rp;
1257 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001258 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001259 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001260 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001261 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001262 int i, err;
1263
1264 BT_DBG("");
1265
Szymon Janc4e51eae2011-02-25 19:05:48 +01001266 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001267 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001268 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1269 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001270
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001271 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001272
1273 count = 0;
1274 list_for_each(p, &hdev->conn_hash.list) {
1275 count++;
1276 }
1277
Johan Hedberg4c659c32011-11-07 23:13:39 +02001278 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001279 rp = kmalloc(rp_len, GFP_ATOMIC);
1280 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001281 err = -ENOMEM;
1282 goto unlock;
1283 }
1284
Johan Hedberg2784eb42011-01-21 13:56:35 +02001285 put_unaligned_le16(count, &rp->conn_count);
1286
Johan Hedberg2784eb42011-01-21 13:56:35 +02001287 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001288 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1289 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001290 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001291 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1292 continue;
1293 i++;
1294 }
1295
1296 /* Recalculate length in case of filtered SCO connections, etc */
1297 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001298
Szymon Janc4e51eae2011-02-25 19:05:48 +01001299 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001300
1301unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001302 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001303 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001304 hci_dev_put(hdev);
1305 return err;
1306}
1307
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001308static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1309 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1310{
1311 struct pending_cmd *cmd;
1312 int err;
1313
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001314 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001315 sizeof(*cp));
1316 if (!cmd)
1317 return -ENOMEM;
1318
1319 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1320 &cp->bdaddr);
1321 if (err < 0)
1322 mgmt_pending_remove(cmd);
1323
1324 return err;
1325}
1326
Szymon Janc4e51eae2011-02-25 19:05:48 +01001327static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1328 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001329{
1330 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001331 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001332 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001333 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001334 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001335 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001336 int err;
1337
1338 BT_DBG("");
1339
1340 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001341
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001342 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001343 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1344 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001345
Szymon Janc4e51eae2011-02-25 19:05:48 +01001346 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001347 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001348 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1349 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001350
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001351 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001352
1353 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001354 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1355 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001356 goto failed;
1357 }
1358
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001359 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1360 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001361 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1362 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001363 goto failed;
1364 }
1365
1366 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1367 bacpy(&ncp.bdaddr, &cp->bdaddr);
1368
1369 BT_ERR("PIN code is not 16 bytes long");
1370
1371 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1372 if (err >= 0)
1373 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001374 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001375
1376 goto failed;
1377 }
1378
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001379 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001380 if (!cmd) {
1381 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001382 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001383 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001384
1385 bacpy(&reply.bdaddr, &cp->bdaddr);
1386 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001387 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001388
1389 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1390 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001391 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001392
1393failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001394 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001395 hci_dev_put(hdev);
1396
1397 return err;
1398}
1399
Szymon Janc4e51eae2011-02-25 19:05:48 +01001400static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1401 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001402{
1403 struct hci_dev *hdev;
1404 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001405 int err;
1406
1407 BT_DBG("");
1408
1409 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001410
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001411 if (len != sizeof(*cp))
1412 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001413 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001414
Szymon Janc4e51eae2011-02-25 19:05:48 +01001415 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001416 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001417 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001418 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001419
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001420 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001421
1422 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001423 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001424 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001425 goto failed;
1426 }
1427
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001428 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001429
1430failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001431 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001432 hci_dev_put(hdev);
1433
1434 return err;
1435}
1436
Szymon Janc4e51eae2011-02-25 19:05:48 +01001437static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1438 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001439{
1440 struct hci_dev *hdev;
1441 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001442
1443 BT_DBG("");
1444
1445 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001446
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001447 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001448 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1449 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001450
Szymon Janc4e51eae2011-02-25 19:05:48 +01001451 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001452 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001453 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1454 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001455
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001456 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001457
1458 hdev->io_capability = cp->io_capability;
1459
1460 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001461 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001462
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001463 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001464 hci_dev_put(hdev);
1465
Szymon Janc4e51eae2011-02-25 19:05:48 +01001466 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001467}
1468
Johan Hedberge9a416b2011-02-19 12:05:56 -03001469static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1470{
1471 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001472 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001473
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001474 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001475 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1476 continue;
1477
Johan Hedberge9a416b2011-02-19 12:05:56 -03001478 if (cmd->user_data != conn)
1479 continue;
1480
1481 return cmd;
1482 }
1483
1484 return NULL;
1485}
1486
1487static void pairing_complete(struct pending_cmd *cmd, u8 status)
1488{
1489 struct mgmt_rp_pair_device rp;
1490 struct hci_conn *conn = cmd->user_data;
1491
Johan Hedbergba4e5642011-11-11 00:07:34 +02001492 bacpy(&rp.addr.bdaddr, &conn->dst);
1493 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001494 rp.status = status;
1495
Szymon Janc4e51eae2011-02-25 19:05:48 +01001496 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001497
1498 /* So we don't get further callbacks for this connection */
1499 conn->connect_cfm_cb = NULL;
1500 conn->security_cfm_cb = NULL;
1501 conn->disconn_cfm_cb = NULL;
1502
1503 hci_conn_put(conn);
1504
Johan Hedberga664b5b2011-02-19 12:06:02 -03001505 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001506}
1507
1508static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1509{
1510 struct pending_cmd *cmd;
1511
1512 BT_DBG("status %u", status);
1513
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001514 cmd = find_pairing(conn);
1515 if (!cmd)
1516 BT_DBG("Unable to find a pending command");
1517 else
1518 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001519}
1520
Szymon Janc4e51eae2011-02-25 19:05:48 +01001521static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001522{
1523 struct hci_dev *hdev;
1524 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001525 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001526 struct pending_cmd *cmd;
1527 u8 sec_level, auth_type;
1528 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001529 int err;
1530
1531 BT_DBG("");
1532
1533 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001534
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001535 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001536 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1537 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001538
Szymon Janc4e51eae2011-02-25 19:05:48 +01001539 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001540 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001541 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1542 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001543
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001544 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001545
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001546 sec_level = BT_SECURITY_MEDIUM;
1547 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001548 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001549 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001550 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001551
Johan Hedbergba4e5642011-11-11 00:07:34 +02001552 if (cp->addr.type == MGMT_ADDR_BREDR)
1553 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001554 auth_type);
1555 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001556 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001557 auth_type);
1558
Johan Hedberg1425acb2011-11-11 00:07:35 +02001559 memset(&rp, 0, sizeof(rp));
1560 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1561 rp.addr.type = cp->addr.type;
1562
Ville Tervo30e76272011-02-22 16:10:53 -03001563 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001564 rp.status = -PTR_ERR(conn);
1565 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1566 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001567 goto unlock;
1568 }
1569
1570 if (conn->connect_cfm_cb) {
1571 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001572 rp.status = EBUSY;
1573 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1574 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001575 goto unlock;
1576 }
1577
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001578 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001579 if (!cmd) {
1580 err = -ENOMEM;
1581 hci_conn_put(conn);
1582 goto unlock;
1583 }
1584
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001585 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001586 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001587 conn->connect_cfm_cb = pairing_complete_cb;
1588
Johan Hedberge9a416b2011-02-19 12:05:56 -03001589 conn->security_cfm_cb = pairing_complete_cb;
1590 conn->disconn_cfm_cb = pairing_complete_cb;
1591 conn->io_capability = cp->io_cap;
1592 cmd->user_data = conn;
1593
1594 if (conn->state == BT_CONNECTED &&
1595 hci_conn_security(conn, sec_level, auth_type))
1596 pairing_complete(cmd, 0);
1597
1598 err = 0;
1599
1600unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001601 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001602 hci_dev_put(hdev);
1603
1604 return err;
1605}
1606
Brian Gix0df4c182011-11-16 13:53:13 -08001607static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1608 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001609{
Johan Hedberga5c29682011-02-19 12:05:57 -03001610 struct pending_cmd *cmd;
1611 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001612 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001613 int err;
1614
Szymon Janc4e51eae2011-02-25 19:05:48 +01001615 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001616 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001617 return cmd_status(sk, index, mgmt_op,
1618 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001619
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001620 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001621
Johan Hedberga5c29682011-02-19 12:05:57 -03001622 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001623 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1624 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001625 }
1626
Brian Gix47c15e22011-11-16 13:53:14 -08001627 /*
1628 * Check for an existing ACL link, if present pair via
1629 * HCI commands.
1630 *
1631 * If no ACL link is present, check for an LE link and if
1632 * present, pair via the SMP engine.
1633 *
1634 * If neither ACL nor LE links are present, fail with error.
1635 */
1636 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1637 if (!conn) {
1638 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1639 if (!conn) {
1640 err = cmd_status(sk, index, mgmt_op,
1641 MGMT_STATUS_NOT_CONNECTED);
1642 goto done;
1643 }
1644
1645 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001646 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001647
Brian Gix5fe57d92011-12-21 16:12:13 -08001648 if (!err)
1649 err = cmd_status(sk, index, mgmt_op,
1650 MGMT_STATUS_SUCCESS);
1651 else
1652 err = cmd_status(sk, index, mgmt_op,
1653 MGMT_STATUS_FAILED);
1654
Brian Gix47c15e22011-11-16 13:53:14 -08001655 goto done;
1656 }
1657
Brian Gix0df4c182011-11-16 13:53:13 -08001658 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001659 if (!cmd) {
1660 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001661 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001662 }
1663
Brian Gix0df4c182011-11-16 13:53:13 -08001664 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001665 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1666 struct hci_cp_user_passkey_reply cp;
1667
1668 bacpy(&cp.bdaddr, bdaddr);
1669 cp.passkey = passkey;
1670 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1671 } else
1672 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1673
Johan Hedberga664b5b2011-02-19 12:06:02 -03001674 if (err < 0)
1675 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001676
Brian Gix0df4c182011-11-16 13:53:13 -08001677done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001678 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001679 hci_dev_put(hdev);
1680
1681 return err;
1682}
1683
Brian Gix0df4c182011-11-16 13:53:13 -08001684static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1685{
1686 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1687
1688 BT_DBG("");
1689
1690 if (len != sizeof(*cp))
1691 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1692 MGMT_STATUS_INVALID_PARAMS);
1693
1694 return user_pairing_resp(sk, index, &cp->bdaddr,
1695 MGMT_OP_USER_CONFIRM_REPLY,
1696 HCI_OP_USER_CONFIRM_REPLY, 0);
1697}
1698
1699static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1700 u16 len)
1701{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001702 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001703
1704 BT_DBG("");
1705
1706 if (len != sizeof(*cp))
1707 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1708 MGMT_STATUS_INVALID_PARAMS);
1709
1710 return user_pairing_resp(sk, index, &cp->bdaddr,
1711 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1712 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1713}
1714
Brian Gix604086b2011-11-23 08:28:33 -08001715static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1716{
1717 struct mgmt_cp_user_passkey_reply *cp = (void *) data;
1718
1719 BT_DBG("");
1720
1721 if (len != sizeof(*cp))
1722 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1723 EINVAL);
1724
1725 return user_pairing_resp(sk, index, &cp->bdaddr,
1726 MGMT_OP_USER_PASSKEY_REPLY,
1727 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1728}
1729
1730static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1731 u16 len)
1732{
1733 struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data;
1734
1735 BT_DBG("");
1736
1737 if (len != sizeof(*cp))
1738 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1739 EINVAL);
1740
1741 return user_pairing_resp(sk, index, &cp->bdaddr,
1742 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1743 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1744}
1745
Johan Hedbergb312b1612011-03-16 14:29:37 +02001746static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1747 u16 len)
1748{
1749 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1750 struct hci_cp_write_local_name hci_cp;
1751 struct hci_dev *hdev;
1752 struct pending_cmd *cmd;
1753 int err;
1754
1755 BT_DBG("");
1756
1757 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001758 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1759 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001760
1761 hdev = hci_dev_get(index);
1762 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001763 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1764 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001765
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001766 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001767
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001768 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001769 if (!cmd) {
1770 err = -ENOMEM;
1771 goto failed;
1772 }
1773
1774 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1775 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1776 &hci_cp);
1777 if (err < 0)
1778 mgmt_pending_remove(cmd);
1779
1780failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001781 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001782 hci_dev_put(hdev);
1783
1784 return err;
1785}
1786
Szymon Jancc35938b2011-03-22 13:12:21 +01001787static int read_local_oob_data(struct sock *sk, u16 index)
1788{
1789 struct hci_dev *hdev;
1790 struct pending_cmd *cmd;
1791 int err;
1792
1793 BT_DBG("hci%u", index);
1794
1795 hdev = hci_dev_get(index);
1796 if (!hdev)
1797 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001798 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001799
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001800 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001801
1802 if (!test_bit(HCI_UP, &hdev->flags)) {
1803 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001804 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001805 goto unlock;
1806 }
1807
1808 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1809 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001810 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001811 goto unlock;
1812 }
1813
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001814 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001815 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1816 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001817 goto unlock;
1818 }
1819
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001820 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001821 if (!cmd) {
1822 err = -ENOMEM;
1823 goto unlock;
1824 }
1825
1826 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1827 if (err < 0)
1828 mgmt_pending_remove(cmd);
1829
1830unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001831 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001832 hci_dev_put(hdev);
1833
1834 return err;
1835}
1836
Szymon Janc2763eda2011-03-22 13:12:22 +01001837static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1838 u16 len)
1839{
1840 struct hci_dev *hdev;
1841 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1842 int err;
1843
1844 BT_DBG("hci%u ", index);
1845
1846 if (len != sizeof(*cp))
1847 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001848 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001849
1850 hdev = hci_dev_get(index);
1851 if (!hdev)
1852 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001853 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001854
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001855 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001856
1857 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1858 cp->randomizer);
1859 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001860 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1861 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001862 else
1863 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1864 0);
1865
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001866 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001867 hci_dev_put(hdev);
1868
1869 return err;
1870}
1871
1872static int remove_remote_oob_data(struct sock *sk, u16 index,
1873 unsigned char *data, u16 len)
1874{
1875 struct hci_dev *hdev;
1876 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1877 int err;
1878
1879 BT_DBG("hci%u ", index);
1880
1881 if (len != sizeof(*cp))
1882 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001883 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001884
1885 hdev = hci_dev_get(index);
1886 if (!hdev)
1887 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001888 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001889
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001890 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001891
1892 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1893 if (err < 0)
1894 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001895 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001896 else
1897 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1898 NULL, 0);
1899
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001900 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001901 hci_dev_put(hdev);
1902
1903 return err;
1904}
1905
Johan Hedberg450dfda2011-11-12 11:58:22 +02001906static int start_discovery(struct sock *sk, u16 index,
1907 unsigned char *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001908{
Johan Hedberg450dfda2011-11-12 11:58:22 +02001909 struct mgmt_cp_start_discovery *cp = (void *) data;
Johan Hedberg14a53662011-04-27 10:29:56 -04001910 struct pending_cmd *cmd;
1911 struct hci_dev *hdev;
1912 int err;
1913
1914 BT_DBG("hci%u", index);
1915
Johan Hedberg450dfda2011-11-12 11:58:22 +02001916 if (len != sizeof(*cp))
1917 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1918 MGMT_STATUS_INVALID_PARAMS);
1919
Johan Hedberg14a53662011-04-27 10:29:56 -04001920 hdev = hci_dev_get(index);
1921 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001922 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1923 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001924
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001925 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001926
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001927 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001928 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1929 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001930 goto failed;
1931 }
1932
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001933 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001934 if (!cmd) {
1935 err = -ENOMEM;
1936 goto failed;
1937 }
1938
Andre Guedes2519a1f2011-11-07 11:45:24 -03001939 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001940 if (err < 0)
1941 mgmt_pending_remove(cmd);
1942
1943failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001944 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001945 hci_dev_put(hdev);
1946
1947 return err;
1948}
1949
1950static int stop_discovery(struct sock *sk, u16 index)
1951{
1952 struct hci_dev *hdev;
1953 struct pending_cmd *cmd;
1954 int err;
1955
1956 BT_DBG("hci%u", index);
1957
1958 hdev = hci_dev_get(index);
1959 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001960 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1961 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001962
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001963 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001964
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001965 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001966 if (!cmd) {
1967 err = -ENOMEM;
1968 goto failed;
1969 }
1970
Andre Guedes023d50492011-11-04 14:16:52 -03001971 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001972 if (err < 0)
1973 mgmt_pending_remove(cmd);
1974
1975failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001976 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001977 hci_dev_put(hdev);
1978
1979 return err;
1980}
1981
Antti Julku7fbec222011-06-15 12:01:15 +03001982static int block_device(struct sock *sk, u16 index, unsigned char *data,
1983 u16 len)
1984{
1985 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001986 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001987 int err;
1988
1989 BT_DBG("hci%u", index);
1990
Antti Julku7fbec222011-06-15 12:01:15 +03001991 if (len != sizeof(*cp))
1992 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001993 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001994
1995 hdev = hci_dev_get(index);
1996 if (!hdev)
1997 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001998 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001999
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002000 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002001
Antti Julku7fbec222011-06-15 12:01:15 +03002002 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03002003 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002004 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2005 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002006 else
2007 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2008 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002009
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002010 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002011 hci_dev_put(hdev);
2012
2013 return err;
2014}
2015
2016static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
2017 u16 len)
2018{
2019 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03002020 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03002021 int err;
2022
2023 BT_DBG("hci%u", index);
2024
Antti Julku7fbec222011-06-15 12:01:15 +03002025 if (len != sizeof(*cp))
2026 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002027 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002028
2029 hdev = hci_dev_get(index);
2030 if (!hdev)
2031 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002032 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002033
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002034 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002035
Antti Julku7fbec222011-06-15 12:01:15 +03002036 err = hci_blacklist_del(hdev, &cp->bdaddr);
2037
2038 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002039 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2040 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002041 else
2042 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2043 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002044
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002045 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002046 hci_dev_put(hdev);
2047
2048 return err;
2049}
2050
Antti Julkuf6422ec2011-06-22 13:11:56 +03002051static int set_fast_connectable(struct sock *sk, u16 index,
2052 unsigned char *data, u16 len)
2053{
2054 struct hci_dev *hdev;
Johan Hedbergf7c6869c2011-12-15 00:47:36 +02002055 struct mgmt_mode *cp = (void *) data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002056 struct hci_cp_write_page_scan_activity acp;
2057 u8 type;
2058 int err;
2059
2060 BT_DBG("hci%u", index);
2061
2062 if (len != sizeof(*cp))
2063 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002064 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002065
2066 hdev = hci_dev_get(index);
2067 if (!hdev)
2068 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002069 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002070
2071 hci_dev_lock(hdev);
2072
Johan Hedbergf7c6869c2011-12-15 00:47:36 +02002073 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002074 type = PAGE_SCAN_TYPE_INTERLACED;
2075 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2076 } else {
2077 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2078 acp.interval = 0x0800; /* default 1.28 sec page scan */
2079 }
2080
2081 acp.window = 0x0012; /* default 11.25 msec page scan window */
2082
2083 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2084 sizeof(acp), &acp);
2085 if (err < 0) {
2086 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002087 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002088 goto done;
2089 }
2090
2091 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2092 if (err < 0) {
2093 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002094 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002095 goto done;
2096 }
2097
2098 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2099 NULL, 0);
2100done:
2101 hci_dev_unlock(hdev);
2102 hci_dev_put(hdev);
2103
2104 return err;
2105}
2106
Johan Hedberg03811012010-12-08 00:21:06 +02002107int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2108{
2109 unsigned char *buf;
2110 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002111 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002112 int err;
2113
2114 BT_DBG("got %zu bytes", msglen);
2115
2116 if (msglen < sizeof(*hdr))
2117 return -EINVAL;
2118
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002119 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002120 if (!buf)
2121 return -ENOMEM;
2122
2123 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2124 err = -EFAULT;
2125 goto done;
2126 }
2127
2128 hdr = (struct mgmt_hdr *) buf;
2129 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002130 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002131 len = get_unaligned_le16(&hdr->len);
2132
2133 if (len != msglen - sizeof(*hdr)) {
2134 err = -EINVAL;
2135 goto done;
2136 }
2137
2138 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002139 case MGMT_OP_READ_VERSION:
2140 err = read_version(sk);
2141 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002142 case MGMT_OP_READ_INDEX_LIST:
2143 err = read_index_list(sk);
2144 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002145 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002146 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002147 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002148 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002149 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002150 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002151 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002152 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002153 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002154 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002155 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002156 break;
Johan Hedbergf7c6869c2011-12-15 00:47:36 +02002157 case MGMT_OP_SET_FAST_CONNECTABLE:
2158 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
2159 len);
2160 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002161 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002162 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002163 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002164 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002165 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002166 break;
2167 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002168 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002169 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002170 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002171 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002172 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002173 case MGMT_OP_LOAD_LINK_KEYS:
2174 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002175 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002176 case MGMT_OP_REMOVE_KEYS:
2177 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002178 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002179 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002180 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002181 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002182 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002183 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002184 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002185 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002186 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002187 break;
2188 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002189 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002190 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002191 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002192 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002193 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002194 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002195 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002196 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002197 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002198 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002199 break;
2200 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002201 err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr),
2202 len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002203 break;
Brian Gix604086b2011-11-23 08:28:33 -08002204 case MGMT_OP_USER_PASSKEY_REPLY:
2205 err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len);
2206 break;
2207 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
2208 err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr),
2209 len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002210 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002211 case MGMT_OP_SET_LOCAL_NAME:
2212 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2213 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002214 case MGMT_OP_READ_LOCAL_OOB_DATA:
2215 err = read_local_oob_data(sk, index);
2216 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002217 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2218 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2219 break;
2220 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2221 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2222 len);
2223 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002224 case MGMT_OP_START_DISCOVERY:
Johan Hedberg450dfda2011-11-12 11:58:22 +02002225 err = start_discovery(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002226 break;
2227 case MGMT_OP_STOP_DISCOVERY:
2228 err = stop_discovery(sk, index);
2229 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002230 case MGMT_OP_BLOCK_DEVICE:
2231 err = block_device(sk, index, buf + sizeof(*hdr), len);
2232 break;
2233 case MGMT_OP_UNBLOCK_DEVICE:
2234 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
2235 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002236 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002237 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002238 err = cmd_status(sk, index, opcode,
2239 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002240 break;
2241 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002242
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002243 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002244 goto done;
2245
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002246 err = msglen;
2247
2248done:
2249 kfree(buf);
2250 return err;
2251}
2252
Johan Hedbergb24752f2011-11-03 14:40:33 +02002253static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2254{
2255 u8 *status = data;
2256
2257 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2258 mgmt_pending_remove(cmd);
2259}
2260
Johan Hedberg744cf192011-11-08 20:40:14 +02002261int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002262{
Johan Hedberg744cf192011-11-08 20:40:14 +02002263 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002264}
2265
Johan Hedberg744cf192011-11-08 20:40:14 +02002266int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002267{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002268 u8 status = ENODEV;
2269
Johan Hedberg744cf192011-11-08 20:40:14 +02002270 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002271
Johan Hedberg744cf192011-11-08 20:40:14 +02002272 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002273}
2274
2275struct cmd_lookup {
2276 u8 val;
2277 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002278 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002279};
2280
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002281static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002282{
Johan Hedberg03811012010-12-08 00:21:06 +02002283 struct cmd_lookup *match = data;
2284
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002285 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002286
2287 list_del(&cmd->list);
2288
2289 if (match->sk == NULL) {
2290 match->sk = cmd->sk;
2291 sock_hold(match->sk);
2292 }
2293
2294 mgmt_pending_free(cmd);
2295}
2296
Johan Hedberg744cf192011-11-08 20:40:14 +02002297int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002298{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002299 struct cmd_lookup match = { powered, NULL, hdev };
2300 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002301 int ret;
2302
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002303 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002304
Johan Hedbergb24752f2011-11-03 14:40:33 +02002305 if (!powered) {
2306 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002307 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002308 }
2309
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002310 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002311
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002312 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2313 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002314
2315 if (match.sk)
2316 sock_put(match.sk);
2317
2318 return ret;
2319}
2320
Johan Hedberg744cf192011-11-08 20:40:14 +02002321int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002322{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002323 struct cmd_lookup match = { discoverable, NULL, hdev };
2324 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002325 int ret;
2326
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002327 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002328
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002329 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002330
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002331 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002332 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002333 if (match.sk)
2334 sock_put(match.sk);
2335
2336 return ret;
2337}
2338
Johan Hedberg744cf192011-11-08 20:40:14 +02002339int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002340{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002341 __le32 ev;
2342 struct cmd_lookup match = { connectable, NULL, hdev };
Johan Hedberg03811012010-12-08 00:21:06 +02002343 int ret;
2344
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002345 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2346 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002347
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002348 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002349
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002350 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002351
2352 if (match.sk)
2353 sock_put(match.sk);
2354
2355 return ret;
2356}
2357
Johan Hedberg744cf192011-11-08 20:40:14 +02002358int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002359{
Johan Hedbergca69b792011-11-11 18:10:00 +02002360 u8 mgmt_err = mgmt_status(status);
2361
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002362 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002363 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002364 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002365
2366 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002367 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002368 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002369
2370 return 0;
2371}
2372
Johan Hedberg744cf192011-11-08 20:40:14 +02002373int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2374 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002375{
Johan Hedberg86742e12011-11-07 23:13:38 +02002376 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002377
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002378 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002379
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002380 ev.store_hint = persistent;
2381 bacpy(&ev.key.bdaddr, &key->bdaddr);
2382 ev.key.type = key->type;
2383 memcpy(ev.key.val, key->val, 16);
2384 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002385
Johan Hedberg744cf192011-11-08 20:40:14 +02002386 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002387}
Johan Hedbergf7520542011-01-20 12:34:39 +02002388
Johan Hedberg48264f02011-11-09 13:58:58 +02002389int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2390 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002391{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002392 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002393
Johan Hedbergf7520542011-01-20 12:34:39 +02002394 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002395 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002396
Johan Hedberg744cf192011-11-08 20:40:14 +02002397 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002398}
2399
Johan Hedberg8962ee72011-01-20 12:40:27 +02002400static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2401{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002402 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002403 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002404 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002405
Johan Hedberga38528f2011-01-22 06:46:43 +02002406 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002407 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002408
Szymon Janc4e51eae2011-02-25 19:05:48 +01002409 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002410
2411 *sk = cmd->sk;
2412 sock_hold(*sk);
2413
Johan Hedberga664b5b2011-02-19 12:06:02 -03002414 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002415}
2416
Johan Hedberga8a1d192011-11-10 15:54:38 +02002417static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2418{
2419 u8 *status = data;
2420 struct mgmt_cp_remove_keys *cp = cmd->param;
2421 struct mgmt_rp_remove_keys rp;
2422
2423 memset(&rp, 0, sizeof(rp));
2424 bacpy(&rp.bdaddr, &cp->bdaddr);
2425 if (status != NULL)
2426 rp.status = *status;
2427
2428 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2429 sizeof(rp));
2430
2431 mgmt_pending_remove(cmd);
2432}
2433
Johan Hedberg48264f02011-11-09 13:58:58 +02002434int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2435 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002436{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002437 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002438 struct sock *sk = NULL;
2439 int err;
2440
Johan Hedberg744cf192011-11-08 20:40:14 +02002441 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002442
Johan Hedbergf7520542011-01-20 12:34:39 +02002443 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002444 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002445
Johan Hedberg744cf192011-11-08 20:40:14 +02002446 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002447
2448 if (sk)
2449 sock_put(sk);
2450
Johan Hedberga8a1d192011-11-10 15:54:38 +02002451 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2452
Johan Hedberg8962ee72011-01-20 12:40:27 +02002453 return err;
2454}
2455
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002456int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002457{
2458 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002459 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002460 int err;
2461
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002462 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002463 if (!cmd)
2464 return -ENOENT;
2465
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002466 if (bdaddr) {
2467 struct mgmt_rp_disconnect rp;
2468
2469 bacpy(&rp.bdaddr, bdaddr);
2470 rp.status = status;
2471
2472 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2473 &rp, sizeof(rp));
2474 } else
2475 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002476 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002477
Johan Hedberga664b5b2011-02-19 12:06:02 -03002478 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002479
2480 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002481}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002482
Johan Hedberg48264f02011-11-09 13:58:58 +02002483int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2484 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002485{
2486 struct mgmt_ev_connect_failed ev;
2487
Johan Hedberg4c659c32011-11-07 23:13:39 +02002488 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002489 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002490 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002491
Johan Hedberg744cf192011-11-08 20:40:14 +02002492 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002493}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002494
Johan Hedberg744cf192011-11-08 20:40:14 +02002495int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002496{
2497 struct mgmt_ev_pin_code_request ev;
2498
Johan Hedberg980e1a52011-01-22 06:10:07 +02002499 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002500 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002501
Johan Hedberg744cf192011-11-08 20:40:14 +02002502 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002503 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002504}
2505
Johan Hedberg744cf192011-11-08 20:40:14 +02002506int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2507 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002508{
2509 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002510 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002511 int err;
2512
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002513 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002514 if (!cmd)
2515 return -ENOENT;
2516
Johan Hedbergac56fb12011-02-19 12:05:59 -03002517 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002518 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002519
Johan Hedberg744cf192011-11-08 20:40:14 +02002520 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002521 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002522
Johan Hedberga664b5b2011-02-19 12:06:02 -03002523 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002524
2525 return err;
2526}
2527
Johan Hedberg744cf192011-11-08 20:40:14 +02002528int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2529 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002530{
2531 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002532 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002533 int err;
2534
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002535 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002536 if (!cmd)
2537 return -ENOENT;
2538
Johan Hedbergac56fb12011-02-19 12:05:59 -03002539 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002540 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002541
Johan Hedberg744cf192011-11-08 20:40:14 +02002542 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002543 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002544
Johan Hedberga664b5b2011-02-19 12:06:02 -03002545 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002546
2547 return err;
2548}
Johan Hedberga5c29682011-02-19 12:05:57 -03002549
Johan Hedberg744cf192011-11-08 20:40:14 +02002550int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2551 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002552{
2553 struct mgmt_ev_user_confirm_request ev;
2554
Johan Hedberg744cf192011-11-08 20:40:14 +02002555 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002556
Johan Hedberga5c29682011-02-19 12:05:57 -03002557 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002558 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002559 put_unaligned_le32(value, &ev.value);
2560
Johan Hedberg744cf192011-11-08 20:40:14 +02002561 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002562 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002563}
2564
Brian Gix604086b2011-11-23 08:28:33 -08002565int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2566{
2567 struct mgmt_ev_user_passkey_request ev;
2568
2569 BT_DBG("%s", hdev->name);
2570
2571 bacpy(&ev.bdaddr, bdaddr);
2572
2573 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2574 NULL);
2575}
2576
Brian Gix0df4c182011-11-16 13:53:13 -08002577static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002578 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002579{
2580 struct pending_cmd *cmd;
2581 struct mgmt_rp_user_confirm_reply rp;
2582 int err;
2583
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002584 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002585 if (!cmd)
2586 return -ENOENT;
2587
Johan Hedberga5c29682011-02-19 12:05:57 -03002588 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002589 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002590 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002591
Johan Hedberga664b5b2011-02-19 12:06:02 -03002592 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002593
2594 return err;
2595}
2596
Johan Hedberg744cf192011-11-08 20:40:14 +02002597int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2598 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002599{
Brian Gix0df4c182011-11-16 13:53:13 -08002600 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002601 MGMT_OP_USER_CONFIRM_REPLY);
2602}
2603
Johan Hedberg744cf192011-11-08 20:40:14 +02002604int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2605 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002606{
Brian Gix0df4c182011-11-16 13:53:13 -08002607 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002608 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2609}
Johan Hedberg2a611692011-02-19 12:06:00 -03002610
Brian Gix604086b2011-11-23 08:28:33 -08002611int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2612 u8 status)
2613{
2614 return user_pairing_resp_complete(hdev, bdaddr, status,
2615 MGMT_OP_USER_PASSKEY_REPLY);
2616}
2617
2618int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2619 bdaddr_t *bdaddr, u8 status)
2620{
2621 return user_pairing_resp_complete(hdev, bdaddr, status,
2622 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2623}
2624
Johan Hedberg744cf192011-11-08 20:40:14 +02002625int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002626{
2627 struct mgmt_ev_auth_failed ev;
2628
Johan Hedberg2a611692011-02-19 12:06:00 -03002629 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002630 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002631
Johan Hedberg744cf192011-11-08 20:40:14 +02002632 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002633}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002634
Johan Hedberg744cf192011-11-08 20:40:14 +02002635int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002636{
2637 struct pending_cmd *cmd;
2638 struct mgmt_cp_set_local_name ev;
2639 int err;
2640
2641 memset(&ev, 0, sizeof(ev));
2642 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2643
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002644 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002645 if (!cmd)
2646 goto send_event;
2647
2648 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002649 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002650 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002651 goto failed;
2652 }
2653
Johan Hedberg744cf192011-11-08 20:40:14 +02002654 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002655
Johan Hedberg744cf192011-11-08 20:40:14 +02002656 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002657 sizeof(ev));
2658 if (err < 0)
2659 goto failed;
2660
2661send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002662 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002663 cmd ? cmd->sk : NULL);
2664
2665failed:
2666 if (cmd)
2667 mgmt_pending_remove(cmd);
2668 return err;
2669}
Szymon Jancc35938b2011-03-22 13:12:21 +01002670
Johan Hedberg744cf192011-11-08 20:40:14 +02002671int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2672 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002673{
2674 struct pending_cmd *cmd;
2675 int err;
2676
Johan Hedberg744cf192011-11-08 20:40:14 +02002677 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002678
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002679 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002680 if (!cmd)
2681 return -ENOENT;
2682
2683 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002684 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002685 MGMT_OP_READ_LOCAL_OOB_DATA,
2686 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002687 } else {
2688 struct mgmt_rp_read_local_oob_data rp;
2689
2690 memcpy(rp.hash, hash, sizeof(rp.hash));
2691 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2692
Johan Hedberg744cf192011-11-08 20:40:14 +02002693 err = cmd_complete(cmd->sk, hdev->id,
2694 MGMT_OP_READ_LOCAL_OOB_DATA,
2695 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002696 }
2697
2698 mgmt_pending_remove(cmd);
2699
2700 return err;
2701}
Johan Hedberge17acd42011-03-30 23:57:16 +03002702
Johan Hedberg48264f02011-11-09 13:58:58 +02002703int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2704 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002705{
2706 struct mgmt_ev_device_found ev;
2707
2708 memset(&ev, 0, sizeof(ev));
2709
Johan Hedberg4c659c32011-11-07 23:13:39 +02002710 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002711 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002712 ev.rssi = rssi;
2713
2714 if (eir)
2715 memcpy(ev.eir, eir, sizeof(ev.eir));
2716
Andre Guedesf8523592011-09-09 18:56:26 -03002717 if (dev_class)
2718 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2719
Johan Hedberg744cf192011-11-08 20:40:14 +02002720 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002721}
Johan Hedberga88a9652011-03-30 13:18:12 +03002722
Johan Hedberg744cf192011-11-08 20:40:14 +02002723int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002724{
2725 struct mgmt_ev_remote_name ev;
2726
2727 memset(&ev, 0, sizeof(ev));
2728
2729 bacpy(&ev.bdaddr, bdaddr);
2730 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2731
Johan Hedberg744cf192011-11-08 20:40:14 +02002732 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002733}
Johan Hedberg314b2382011-04-27 10:29:57 -04002734
Andre Guedes7a135102011-11-09 17:14:25 -03002735int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002736{
2737 struct pending_cmd *cmd;
2738 int err;
2739
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002740 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002741 if (!cmd)
2742 return -ENOENT;
2743
Johan Hedbergca69b792011-11-11 18:10:00 +02002744 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002745 mgmt_pending_remove(cmd);
2746
2747 return err;
2748}
2749
Andre Guedese6d465c2011-11-09 17:14:26 -03002750int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2751{
2752 struct pending_cmd *cmd;
2753 int err;
2754
2755 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2756 if (!cmd)
2757 return -ENOENT;
2758
Andre Guedese75a8b0c2012-01-02 16:50:53 -03002759 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02002760 mgmt_pending_remove(cmd);
2761
2762 return err;
2763}
Johan Hedberg314b2382011-04-27 10:29:57 -04002764
Johan Hedberg744cf192011-11-08 20:40:14 +02002765int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002766{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002767 struct pending_cmd *cmd;
2768
2769 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002770 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002771 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002772 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002773
2774 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002775 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002776 mgmt_pending_remove(cmd);
2777 }
2778
Johan Hedberg744cf192011-11-08 20:40:14 +02002779 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002780 sizeof(discovering), NULL);
2781}
Antti Julku5e762442011-08-25 16:48:02 +03002782
Johan Hedberg744cf192011-11-08 20:40:14 +02002783int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002784{
2785 struct pending_cmd *cmd;
2786 struct mgmt_ev_device_blocked ev;
2787
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002788 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002789
2790 bacpy(&ev.bdaddr, bdaddr);
2791
Johan Hedberg744cf192011-11-08 20:40:14 +02002792 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2793 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002794}
2795
Johan Hedberg744cf192011-11-08 20:40:14 +02002796int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002797{
2798 struct pending_cmd *cmd;
2799 struct mgmt_ev_device_unblocked ev;
2800
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002801 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002802
2803 bacpy(&ev.bdaddr, bdaddr);
2804
Johan Hedberg744cf192011-11-08 20:40:14 +02002805 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2806 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002807}