blob: 00ab083749eb569c70e2f45e5b691c90e9c72a19 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Johan Hedbergca69b792011-11-11 18:10:00 +020025#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Johan Hedberg02d98122010-12-13 21:07:04 +020035#define MGMT_VERSION 0
36#define MGMT_REVISION 1
37
Andre Guedes2519a1f2011-11-07 11:45:24 -030038#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
39
Johan Hedberg7d785252011-12-15 00:47:39 +020040#define SERVICE_CACHE_TIMEOUT (5 * 1000)
41
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042struct pending_cmd {
43 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020044 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010046 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020047 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030048 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020049};
50
Johan Hedbergca69b792011-11-11 18:10:00 +020051/* HCI to MGMT error code conversion table */
52static u8 mgmt_status_table[] = {
53 MGMT_STATUS_SUCCESS,
54 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
55 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
56 MGMT_STATUS_FAILED, /* Hardware Failure */
57 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
58 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
59 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
60 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
61 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
62 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
63 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
64 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
65 MGMT_STATUS_BUSY, /* Command Disallowed */
66 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
67 MGMT_STATUS_REJECTED, /* Rejected Security */
68 MGMT_STATUS_REJECTED, /* Rejected Personal */
69 MGMT_STATUS_TIMEOUT, /* Host Timeout */
70 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
71 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
72 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
73 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
74 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
75 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
76 MGMT_STATUS_BUSY, /* Repeated Attempts */
77 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
78 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
79 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
80 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
81 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
82 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
83 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
84 MGMT_STATUS_FAILED, /* Unspecified Error */
85 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
86 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
87 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
88 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
89 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
90 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
91 MGMT_STATUS_FAILED, /* Unit Link Key Used */
92 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
93 MGMT_STATUS_TIMEOUT, /* Instant Passed */
94 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
95 MGMT_STATUS_FAILED, /* Transaction Collision */
96 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
97 MGMT_STATUS_REJECTED, /* QoS Rejected */
98 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
99 MGMT_STATUS_REJECTED, /* Insufficient Security */
100 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
101 MGMT_STATUS_BUSY, /* Role Switch Pending */
102 MGMT_STATUS_FAILED, /* Slot Violation */
103 MGMT_STATUS_FAILED, /* Role Switch Failed */
104 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
105 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
106 MGMT_STATUS_BUSY, /* Host Busy Pairing */
107 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
108 MGMT_STATUS_BUSY, /* Controller Busy */
109 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
110 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
111 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
112 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
113 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
114};
115
116static u8 mgmt_status(u8 hci_status)
117{
118 if (hci_status < ARRAY_SIZE(mgmt_status_table))
119 return mgmt_status_table[hci_status];
120
121 return MGMT_STATUS_FAILED;
122}
123
Szymon Janc4e51eae2011-02-25 19:05:48 +0100124static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200125{
126 struct sk_buff *skb;
127 struct mgmt_hdr *hdr;
128 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300129 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200130
Szymon Janc34eb5252011-02-28 14:10:08 +0100131 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200132
133 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
134 if (!skb)
135 return -ENOMEM;
136
137 hdr = (void *) skb_put(skb, sizeof(*hdr));
138
139 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100140 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200141 hdr->len = cpu_to_le16(sizeof(*ev));
142
143 ev = (void *) skb_put(skb, sizeof(*ev));
144 ev->status = status;
145 put_unaligned_le16(cmd, &ev->opcode);
146
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300147 err = sock_queue_rcv_skb(sk, skb);
148 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200149 kfree_skb(skb);
150
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300151 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200152}
153
Szymon Janc4e51eae2011-02-25 19:05:48 +0100154static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
155 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200156{
157 struct sk_buff *skb;
158 struct mgmt_hdr *hdr;
159 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300160 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200161
162 BT_DBG("sock %p", sk);
163
Johan Hedberga38528f2011-01-22 06:46:43 +0200164 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200165 if (!skb)
166 return -ENOMEM;
167
168 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200169
Johan Hedberg02d98122010-12-13 21:07:04 +0200170 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100171 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200172 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200173
Johan Hedberga38528f2011-01-22 06:46:43 +0200174 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
175 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100176
177 if (rp)
178 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200179
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300180 err = sock_queue_rcv_skb(sk, skb);
181 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200182 kfree_skb(skb);
183
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300184 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200185}
186
Johan Hedberga38528f2011-01-22 06:46:43 +0200187static int read_version(struct sock *sk)
188{
189 struct mgmt_rp_read_version rp;
190
191 BT_DBG("sock %p", sk);
192
193 rp.version = MGMT_VERSION;
194 put_unaligned_le16(MGMT_REVISION, &rp.revision);
195
Szymon Janc4e51eae2011-02-25 19:05:48 +0100196 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
197 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200198}
199
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200200static int read_index_list(struct sock *sk)
201{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200202 struct mgmt_rp_read_index_list *rp;
203 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200204 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200205 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200206 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200207 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200208
209 BT_DBG("sock %p", sk);
210
211 read_lock(&hci_dev_list_lock);
212
213 count = 0;
214 list_for_each(p, &hci_dev_list) {
215 count++;
216 }
217
Johan Hedberga38528f2011-01-22 06:46:43 +0200218 rp_len = sizeof(*rp) + (2 * count);
219 rp = kmalloc(rp_len, GFP_ATOMIC);
220 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100221 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200222 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100223 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200224
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200225 put_unaligned_le16(count, &rp->num_controllers);
226
227 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200228 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200229 if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200230 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200231
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200232 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200233 continue;
234
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200235 put_unaligned_le16(d->id, &rp->index[i++]);
236 BT_DBG("Added hci%u", d->id);
237 }
238
239 read_unlock(&hci_dev_list_lock);
240
Szymon Janc4e51eae2011-02-25 19:05:48 +0100241 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
242 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200243
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 kfree(rp);
245
246 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200247}
248
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200249static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200250{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200251 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200252
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200253 settings |= MGMT_SETTING_POWERED;
254 settings |= MGMT_SETTING_CONNECTABLE;
255 settings |= MGMT_SETTING_FAST_CONNECTABLE;
256 settings |= MGMT_SETTING_DISCOVERABLE;
257 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200258
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200259 if (hdev->features[6] & LMP_SIMPLE_PAIR)
260 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200261
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200262 if (!(hdev->features[4] & LMP_NO_BREDR)) {
263 settings |= MGMT_SETTING_BREDR;
264 settings |= MGMT_SETTING_LINK_SECURITY;
265 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200266
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200267 if (hdev->features[4] & LMP_LE)
268 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200269
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200270 return settings;
271}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200272
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200273static u32 get_current_settings(struct hci_dev *hdev)
274{
275 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200276
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200277 if (test_bit(HCI_UP, &hdev->flags))
278 settings |= MGMT_SETTING_POWERED;
279 else
280 return settings;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200281
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200282 if (test_bit(HCI_PSCAN, &hdev->flags))
283 settings |= MGMT_SETTING_CONNECTABLE;
284
285 if (test_bit(HCI_ISCAN, &hdev->flags))
286 settings |= MGMT_SETTING_DISCOVERABLE;
287
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200288 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200289 settings |= MGMT_SETTING_PAIRABLE;
290
291 if (!(hdev->features[4] & LMP_NO_BREDR))
292 settings |= MGMT_SETTING_BREDR;
293
Andre Guedes59e29402011-12-30 10:34:03 -0300294 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200295 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200296
297 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200298 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200299
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200300 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200301 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200302
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200303 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200304}
305
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300306#define PNP_INFO_SVCLASS_ID 0x1200
307
308static u8 bluetooth_base_uuid[] = {
309 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
310 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311};
312
313static u16 get_uuid16(u8 *uuid128)
314{
315 u32 val;
316 int i;
317
318 for (i = 0; i < 12; i++) {
319 if (bluetooth_base_uuid[i] != uuid128[i])
320 return 0;
321 }
322
323 memcpy(&val, &uuid128[12], 4);
324
325 val = le32_to_cpu(val);
326 if (val > 0xffff)
327 return 0;
328
329 return (u16) val;
330}
331
332static void create_eir(struct hci_dev *hdev, u8 *data)
333{
334 u8 *ptr = data;
335 u16 eir_len = 0;
336 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
337 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200338 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300339 size_t name_len;
340
341 name_len = strlen(hdev->dev_name);
342
343 if (name_len > 0) {
344 /* EIR Data type */
345 if (name_len > 48) {
346 name_len = 48;
347 ptr[1] = EIR_NAME_SHORT;
348 } else
349 ptr[1] = EIR_NAME_COMPLETE;
350
351 /* EIR Data length */
352 ptr[0] = name_len + 1;
353
354 memcpy(ptr + 2, hdev->dev_name, name_len);
355
356 eir_len += (name_len + 2);
357 ptr += (name_len + 2);
358 }
359
360 memset(uuid16_list, 0, sizeof(uuid16_list));
361
362 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200363 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300364 u16 uuid16;
365
366 uuid16 = get_uuid16(uuid->uuid);
367 if (uuid16 == 0)
368 return;
369
370 if (uuid16 < 0x1100)
371 continue;
372
373 if (uuid16 == PNP_INFO_SVCLASS_ID)
374 continue;
375
376 /* Stop if not enough space to put next UUID */
377 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
378 truncated = 1;
379 break;
380 }
381
382 /* Check for duplicates */
383 for (i = 0; uuid16_list[i] != 0; i++)
384 if (uuid16_list[i] == uuid16)
385 break;
386
387 if (uuid16_list[i] == 0) {
388 uuid16_list[i] = uuid16;
389 eir_len += sizeof(u16);
390 }
391 }
392
393 if (uuid16_list[0] != 0) {
394 u8 *length = ptr;
395
396 /* EIR Data type */
397 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
398
399 ptr += 2;
400 eir_len += 2;
401
402 for (i = 0; uuid16_list[i] != 0; i++) {
403 *ptr++ = (uuid16_list[i] & 0x00ff);
404 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
405 }
406
407 /* EIR Data length */
408 *length = (i * sizeof(u16)) + 1;
409 }
410}
411
412static int update_eir(struct hci_dev *hdev)
413{
414 struct hci_cp_write_eir cp;
415
416 if (!(hdev->features[6] & LMP_EXT_INQ))
417 return 0;
418
Johan Hedberg84bde9d6c2012-01-25 14:21:06 +0200419 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300420 return 0;
421
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200422 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300423 return 0;
424
425 memset(&cp, 0, sizeof(cp));
426
427 create_eir(hdev, cp.data);
428
429 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
430 return 0;
431
432 memcpy(hdev->eir, cp.data, sizeof(cp.data));
433
434 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
435}
436
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200437static u8 get_service_classes(struct hci_dev *hdev)
438{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300439 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200440 u8 val = 0;
441
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300442 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200443 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200444
445 return val;
446}
447
448static int update_class(struct hci_dev *hdev)
449{
450 u8 cod[3];
451
452 BT_DBG("%s", hdev->name);
453
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200454 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200455 return 0;
456
457 cod[0] = hdev->minor_class;
458 cod[1] = hdev->major_class;
459 cod[2] = get_service_classes(hdev);
460
461 if (memcmp(cod, hdev->dev_class, 3) == 0)
462 return 0;
463
464 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
465}
466
Johan Hedberg7d785252011-12-15 00:47:39 +0200467static void service_cache_off(struct work_struct *work)
468{
469 struct hci_dev *hdev = container_of(work, struct hci_dev,
470 service_cache.work);
471
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200472 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200473 return;
474
475 hci_dev_lock(hdev);
476
477 update_eir(hdev);
478 update_class(hdev);
479
480 hci_dev_unlock(hdev);
481}
482
483static void mgmt_init_hdev(struct hci_dev *hdev)
484{
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200485 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200486 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
487
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200488 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200489 schedule_delayed_work(&hdev->service_cache,
490 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
491}
492
Johan Hedberg03811012010-12-08 00:21:06 +0200493static int read_controller_info(struct sock *sk, u16 index)
494{
495 struct mgmt_rp_read_info rp;
496 struct hci_dev *hdev;
497
498 BT_DBG("sock %p hci%u", sk, index);
499
500 hdev = hci_dev_get(index);
501 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200502 return cmd_status(sk, index, MGMT_OP_READ_INFO,
503 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200504
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200505 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
Johan Hedberg03811012010-12-08 00:21:06 +0200506 cancel_delayed_work_sync(&hdev->power_off);
507
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300508 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200509
Johan Hedberg7d785252011-12-15 00:47:39 +0200510 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
511 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200512
513 memset(&rp, 0, sizeof(rp));
514
Johan Hedberg03811012010-12-08 00:21:06 +0200515 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200516
517 rp.version = hdev->hci_ver;
518
Johan Hedberg03811012010-12-08 00:21:06 +0200519 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200520
521 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
522 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
523
524 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200525
526 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
527
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300528 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200529 hci_dev_put(hdev);
530
531 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
532}
533
534static void mgmt_pending_free(struct pending_cmd *cmd)
535{
536 sock_put(cmd->sk);
537 kfree(cmd->param);
538 kfree(cmd);
539}
540
541static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
542 struct hci_dev *hdev,
543 void *data, u16 len)
544{
545 struct pending_cmd *cmd;
546
547 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
548 if (!cmd)
549 return NULL;
550
551 cmd->opcode = opcode;
552 cmd->index = hdev->id;
553
554 cmd->param = kmalloc(len, GFP_ATOMIC);
555 if (!cmd->param) {
556 kfree(cmd);
557 return NULL;
558 }
559
560 if (data)
561 memcpy(cmd->param, data, len);
562
563 cmd->sk = sk;
564 sock_hold(sk);
565
566 list_add(&cmd->list, &hdev->mgmt_pending);
567
568 return cmd;
569}
570
571static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
572 void (*cb)(struct pending_cmd *cmd, void *data),
573 void *data)
574{
575 struct list_head *p, *n;
576
577 list_for_each_safe(p, n, &hdev->mgmt_pending) {
578 struct pending_cmd *cmd;
579
580 cmd = list_entry(p, struct pending_cmd, list);
581
582 if (opcode > 0 && cmd->opcode != opcode)
583 continue;
584
585 cb(cmd, data);
586 }
587}
588
589static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
590{
591 struct pending_cmd *cmd;
592
593 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
594 if (cmd->opcode == opcode)
595 return cmd;
596 }
597
598 return NULL;
599}
600
601static void mgmt_pending_remove(struct pending_cmd *cmd)
602{
603 list_del(&cmd->list);
604 mgmt_pending_free(cmd);
605}
606
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200607static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200608{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200609 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200610
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200611 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200612}
613
Johan Hedberg03811012010-12-08 00:21:06 +0200614static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
615{
616 struct mgmt_mode *cp;
617 struct hci_dev *hdev;
618 struct pending_cmd *cmd;
619 int err, up;
620
621 cp = (void *) data;
622
623 BT_DBG("request for hci%u", index);
624
625 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200626 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
627 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200628
629 hdev = hci_dev_get(index);
630 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200631 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
632 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200633
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300634 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200635
636 up = test_bit(HCI_UP, &hdev->flags);
637 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200638 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200639 goto failed;
640 }
641
642 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200643 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
644 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200645 goto failed;
646 }
647
648 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
649 if (!cmd) {
650 err = -ENOMEM;
651 goto failed;
652 }
653
654 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200655 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200656 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200657 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200658
659 err = 0;
660
661failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300662 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200663 hci_dev_put(hdev);
664 return err;
665}
666
667static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
668 u16 len)
669{
670 struct mgmt_cp_set_discoverable *cp;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200671 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200672 struct pending_cmd *cmd;
673 u8 scan;
674 int err;
675
676 cp = (void *) data;
677
678 BT_DBG("request for hci%u", index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200679
680 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200681 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
682 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200683
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200684 hdev = hci_dev_get(index);
685 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200686 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
687 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200688
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300689 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200690
691 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200692 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
693 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200694 goto failed;
695 }
696
697 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
698 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200699 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
700 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200701 goto failed;
702 }
703
704 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
705 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200706 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200707 goto failed;
708 }
709
710 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
711 if (!cmd) {
712 err = -ENOMEM;
713 goto failed;
714 }
715
716 scan = SCAN_PAGE;
717
718 if (cp->val)
719 scan |= SCAN_INQUIRY;
720 else
721 cancel_delayed_work(&hdev->discov_off);
722
723 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
724 if (err < 0)
725 mgmt_pending_remove(cmd);
726
Johan Hedberg03811012010-12-08 00:21:06 +0200727 if (cp->val)
728 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
729
Johan Hedberge41d8b42010-12-13 21:07:03 +0200730failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300731 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200732 hci_dev_put(hdev);
733
734 return err;
735}
736
737static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
738 u16 len)
739{
740 struct mgmt_mode *cp;
741 struct hci_dev *hdev;
742 struct pending_cmd *cmd;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200743 u8 scan;
744 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200745
746 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200747
748 BT_DBG("request for hci%u", index);
749
750 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200751 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
752 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200753
754 hdev = hci_dev_get(index);
755 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200756 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
757 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200758
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300759 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200760
761 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200762 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
763 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200764 goto failed;
765 }
766
767 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
768 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200769 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
770 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200771 goto failed;
772 }
773
774 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200775 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200776 goto failed;
777 }
778
779 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
780 if (!cmd) {
781 err = -ENOMEM;
782 goto failed;
783 }
784
785 if (cp->val)
786 scan = SCAN_PAGE;
787 else
788 scan = 0;
789
790 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
791 if (err < 0)
792 mgmt_pending_remove(cmd);
793
794failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300795 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200796 hci_dev_put(hdev);
797
798 return err;
799}
800
801static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
802 u16 data_len, struct sock *skip_sk)
803{
804 struct sk_buff *skb;
805 struct mgmt_hdr *hdr;
806
807 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
808 if (!skb)
809 return -ENOMEM;
810
811 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
812
813 hdr = (void *) skb_put(skb, sizeof(*hdr));
814 hdr->opcode = cpu_to_le16(event);
815 if (hdev)
816 hdr->index = cpu_to_le16(hdev->id);
817 else
818 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
819 hdr->len = cpu_to_le16(data_len);
820
821 if (data)
822 memcpy(skb_put(skb, data_len), data, data_len);
823
824 hci_send_to_sock(NULL, skb, skip_sk);
825 kfree_skb(skb);
826
827 return 0;
828}
829
Johan Hedberg73f22f62010-12-29 16:00:25 +0200830static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
831 u16 len)
832{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200833 struct mgmt_mode *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200834 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200835 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200836 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200837
838 cp = (void *) data;
Johan Hedberg72a734e2010-12-30 00:38:22 +0200839
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200840 BT_DBG("request for hci%u", index);
841
842 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200843 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
844 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200845
846 hdev = hci_dev_get(index);
847 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200848 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
849 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200850
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300851 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200852
853 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200854 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200855 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200856 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200857
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200858 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200859 if (err < 0)
860 goto failed;
861
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200862 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200863
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200864 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200865
866failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300867 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200868 hci_dev_put(hdev);
869
870 return err;
871}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200872
Szymon Janc4e51eae2011-02-25 19:05:48 +0100873static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200874{
875 struct mgmt_cp_add_uuid *cp;
876 struct hci_dev *hdev;
877 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200878 int err;
879
880 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200881
Szymon Janc4e51eae2011-02-25 19:05:48 +0100882 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200883
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100884 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200885 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
886 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100887
Szymon Janc4e51eae2011-02-25 19:05:48 +0100888 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200889 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200890 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
891 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200892
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300893 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200894
895 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
896 if (!uuid) {
897 err = -ENOMEM;
898 goto failed;
899 }
900
901 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200902 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200903
904 list_add(&uuid->list, &hdev->uuids);
905
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200906 err = update_class(hdev);
907 if (err < 0)
908 goto failed;
909
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300910 err = update_eir(hdev);
911 if (err < 0)
912 goto failed;
913
Szymon Janc4e51eae2011-02-25 19:05:48 +0100914 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200915
916failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300917 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200918 hci_dev_put(hdev);
919
920 return err;
921}
922
Szymon Janc4e51eae2011-02-25 19:05:48 +0100923static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200924{
925 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100926 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200927 struct hci_dev *hdev;
928 u8 bt_uuid_any[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200929 int err, found;
930
931 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200932
Szymon Janc4e51eae2011-02-25 19:05:48 +0100933 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200934
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100935 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200936 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
937 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100938
Szymon Janc4e51eae2011-02-25 19:05:48 +0100939 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200940 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200941 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
942 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200943
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300944 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200945
946 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
947 err = hci_uuids_clear(hdev);
948 goto unlock;
949 }
950
951 found = 0;
952
953 list_for_each_safe(p, n, &hdev->uuids) {
954 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
955
956 if (memcmp(match->uuid, cp->uuid, 16) != 0)
957 continue;
958
959 list_del(&match->list);
960 found++;
961 }
962
963 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200964 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
965 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200966 goto unlock;
967 }
968
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200969 err = update_class(hdev);
970 if (err < 0)
971 goto unlock;
972
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300973 err = update_eir(hdev);
974 if (err < 0)
975 goto unlock;
976
Szymon Janc4e51eae2011-02-25 19:05:48 +0100977 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200978
979unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300980 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200981 hci_dev_put(hdev);
982
983 return err;
984}
985
Szymon Janc4e51eae2011-02-25 19:05:48 +0100986static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
987 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200988{
989 struct hci_dev *hdev;
990 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200991 int err;
992
993 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200994
Szymon Janc4e51eae2011-02-25 19:05:48 +0100995 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200996
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100997 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200998 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
999 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001000
Szymon Janc4e51eae2011-02-25 19:05:48 +01001001 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001002 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001003 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1004 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001005
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001006 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001007
1008 hdev->major_class = cp->major;
1009 hdev->minor_class = cp->minor;
1010
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001011 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001012 hci_dev_unlock(hdev);
1013 cancel_delayed_work_sync(&hdev->service_cache);
1014 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001015 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001016 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001017
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001018 err = update_class(hdev);
1019
1020 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001021 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001022
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001023 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001024 hci_dev_put(hdev);
1025
1026 return err;
1027}
1028
Johan Hedberg86742e12011-11-07 23:13:38 +02001029static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
1030 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001031{
1032 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001033 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001034 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001035 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001036
1037 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001038
1039 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001040 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1041 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001042
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001043 key_count = get_unaligned_le16(&cp->key_count);
1044
Johan Hedberg86742e12011-11-07 23:13:38 +02001045 expected_len = sizeof(*cp) + key_count *
1046 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001047 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001048 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001049 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001050 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1051 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001052 }
1053
Szymon Janc4e51eae2011-02-25 19:05:48 +01001054 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001055 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001056 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1057 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001058
Szymon Janc4e51eae2011-02-25 19:05:48 +01001059 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001060 key_count);
1061
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001062 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001063
1064 hci_link_keys_clear(hdev);
1065
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001066 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001067
1068 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001069 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001070 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001071 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001072
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001073 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001074 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001075
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001076 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001077 key->pin_len);
1078 }
1079
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001080 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1081
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001082 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001083 hci_dev_put(hdev);
1084
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001085 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001086}
1087
Johan Hedberg86742e12011-11-07 23:13:38 +02001088static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
1089 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001090{
1091 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001092 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001093 struct mgmt_rp_remove_keys rp;
1094 struct hci_cp_disconnect dc;
1095 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001096 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001097 int err;
1098
1099 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001100
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001101 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001102 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1103 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001104
Szymon Janc4e51eae2011-02-25 19:05:48 +01001105 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001106 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001107 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1108 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001109
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001110 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001111
Johan Hedberga8a1d192011-11-10 15:54:38 +02001112 memset(&rp, 0, sizeof(rp));
1113 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001114 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001115
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001116 err = hci_remove_link_key(hdev, &cp->bdaddr);
1117 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001118 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001119 goto unlock;
1120 }
1121
Johan Hedberga8a1d192011-11-10 15:54:38 +02001122 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1123 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1124 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001125 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001126 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001127
1128 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001129 if (!conn) {
1130 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1131 sizeof(rp));
1132 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001133 }
1134
Johan Hedberga8a1d192011-11-10 15:54:38 +02001135 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1136 if (!cmd) {
1137 err = -ENOMEM;
1138 goto unlock;
1139 }
1140
1141 put_unaligned_le16(conn->handle, &dc.handle);
1142 dc.reason = 0x13; /* Remote User Terminated Connection */
1143 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1144 if (err < 0)
1145 mgmt_pending_remove(cmd);
1146
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001147unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001148 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001149 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1150 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001151 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001152 hci_dev_put(hdev);
1153
1154 return err;
1155}
1156
Szymon Janc4e51eae2011-02-25 19:05:48 +01001157static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001158{
1159 struct hci_dev *hdev;
1160 struct mgmt_cp_disconnect *cp;
1161 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001162 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001163 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001164 int err;
1165
1166 BT_DBG("");
1167
1168 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001169
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001170 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001171 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1172 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001173
Szymon Janc4e51eae2011-02-25 19:05:48 +01001174 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001175 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001176 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1177 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001178
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001179 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001180
1181 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001182 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1183 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001184 goto failed;
1185 }
1186
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001187 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001188 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1189 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001190 goto failed;
1191 }
1192
1193 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001194 if (!conn)
1195 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1196
Johan Hedberg8962ee72011-01-20 12:40:27 +02001197 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001198 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1199 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001200 goto failed;
1201 }
1202
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001203 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001204 if (!cmd) {
1205 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001206 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001207 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001208
1209 put_unaligned_le16(conn->handle, &dc.handle);
1210 dc.reason = 0x13; /* Remote User Terminated Connection */
1211
1212 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1213 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001214 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001215
1216failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001217 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001218 hci_dev_put(hdev);
1219
1220 return err;
1221}
1222
Johan Hedberg48264f02011-11-09 13:58:58 +02001223static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001224{
1225 switch (link_type) {
1226 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001227 switch (addr_type) {
1228 case ADDR_LE_DEV_PUBLIC:
1229 return MGMT_ADDR_LE_PUBLIC;
1230 case ADDR_LE_DEV_RANDOM:
1231 return MGMT_ADDR_LE_RANDOM;
1232 default:
1233 return MGMT_ADDR_INVALID;
1234 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001235 case ACL_LINK:
1236 return MGMT_ADDR_BREDR;
1237 default:
1238 return MGMT_ADDR_INVALID;
1239 }
1240}
1241
Szymon Janc8ce62842011-03-01 16:55:32 +01001242static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001243{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001244 struct mgmt_rp_get_connections *rp;
1245 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001246 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001247 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001248 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001249 int i, err;
1250
1251 BT_DBG("");
1252
Szymon Janc4e51eae2011-02-25 19:05:48 +01001253 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001254 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001255 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1256 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001257
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001258 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001259
1260 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001261 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1262 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1263 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001264 }
1265
Johan Hedberg4c659c32011-11-07 23:13:39 +02001266 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001267 rp = kmalloc(rp_len, GFP_ATOMIC);
1268 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001269 err = -ENOMEM;
1270 goto unlock;
1271 }
1272
Johan Hedberg2784eb42011-01-21 13:56:35 +02001273 put_unaligned_le16(count, &rp->conn_count);
1274
Johan Hedberg2784eb42011-01-21 13:56:35 +02001275 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001276 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001277 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1278 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001279 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001280 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001281 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1282 continue;
1283 i++;
1284 }
1285
1286 /* Recalculate length in case of filtered SCO connections, etc */
1287 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001288
Szymon Janc4e51eae2011-02-25 19:05:48 +01001289 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001290
1291unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001292 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001293 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001294 hci_dev_put(hdev);
1295 return err;
1296}
1297
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001298static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1299 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1300{
1301 struct pending_cmd *cmd;
1302 int err;
1303
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001304 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001305 sizeof(*cp));
1306 if (!cmd)
1307 return -ENOMEM;
1308
1309 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1310 &cp->bdaddr);
1311 if (err < 0)
1312 mgmt_pending_remove(cmd);
1313
1314 return err;
1315}
1316
Szymon Janc4e51eae2011-02-25 19:05:48 +01001317static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1318 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001319{
1320 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001321 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001322 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001323 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001324 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001325 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001326 int err;
1327
1328 BT_DBG("");
1329
1330 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001331
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001332 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001333 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1334 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001335
Szymon Janc4e51eae2011-02-25 19:05:48 +01001336 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001337 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001338 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1339 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001340
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001341 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001342
1343 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001344 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1345 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001346 goto failed;
1347 }
1348
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001349 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1350 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001351 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1352 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001353 goto failed;
1354 }
1355
1356 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1357 bacpy(&ncp.bdaddr, &cp->bdaddr);
1358
1359 BT_ERR("PIN code is not 16 bytes long");
1360
1361 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1362 if (err >= 0)
1363 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001364 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001365
1366 goto failed;
1367 }
1368
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001369 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001370 if (!cmd) {
1371 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001372 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001373 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001374
1375 bacpy(&reply.bdaddr, &cp->bdaddr);
1376 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001377 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001378
1379 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1380 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001381 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001382
1383failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001384 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001385 hci_dev_put(hdev);
1386
1387 return err;
1388}
1389
Szymon Janc4e51eae2011-02-25 19:05:48 +01001390static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1391 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001392{
1393 struct hci_dev *hdev;
1394 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001395 int err;
1396
1397 BT_DBG("");
1398
1399 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001400
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001401 if (len != sizeof(*cp))
1402 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001403 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001404
Szymon Janc4e51eae2011-02-25 19:05:48 +01001405 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001406 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001407 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001408 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001409
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001410 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001411
1412 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001413 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001414 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001415 goto failed;
1416 }
1417
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001418 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001419
1420failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001421 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001422 hci_dev_put(hdev);
1423
1424 return err;
1425}
1426
Szymon Janc4e51eae2011-02-25 19:05:48 +01001427static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1428 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001429{
1430 struct hci_dev *hdev;
1431 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001432
1433 BT_DBG("");
1434
1435 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001436
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001437 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001438 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1439 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001440
Szymon Janc4e51eae2011-02-25 19:05:48 +01001441 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001442 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001443 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1444 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001445
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001446 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001447
1448 hdev->io_capability = cp->io_capability;
1449
1450 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001451 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001452
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001453 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001454 hci_dev_put(hdev);
1455
Szymon Janc4e51eae2011-02-25 19:05:48 +01001456 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001457}
1458
Johan Hedberge9a416b2011-02-19 12:05:56 -03001459static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1460{
1461 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001462 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001463
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001464 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001465 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1466 continue;
1467
Johan Hedberge9a416b2011-02-19 12:05:56 -03001468 if (cmd->user_data != conn)
1469 continue;
1470
1471 return cmd;
1472 }
1473
1474 return NULL;
1475}
1476
1477static void pairing_complete(struct pending_cmd *cmd, u8 status)
1478{
1479 struct mgmt_rp_pair_device rp;
1480 struct hci_conn *conn = cmd->user_data;
1481
Johan Hedbergba4e5642011-11-11 00:07:34 +02001482 bacpy(&rp.addr.bdaddr, &conn->dst);
1483 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001484 rp.status = status;
1485
Szymon Janc4e51eae2011-02-25 19:05:48 +01001486 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001487
1488 /* So we don't get further callbacks for this connection */
1489 conn->connect_cfm_cb = NULL;
1490 conn->security_cfm_cb = NULL;
1491 conn->disconn_cfm_cb = NULL;
1492
1493 hci_conn_put(conn);
1494
Johan Hedberga664b5b2011-02-19 12:06:02 -03001495 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001496}
1497
1498static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1499{
1500 struct pending_cmd *cmd;
1501
1502 BT_DBG("status %u", status);
1503
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001504 cmd = find_pairing(conn);
1505 if (!cmd)
1506 BT_DBG("Unable to find a pending command");
1507 else
1508 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001509}
1510
Szymon Janc4e51eae2011-02-25 19:05:48 +01001511static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001512{
1513 struct hci_dev *hdev;
1514 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001515 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001516 struct pending_cmd *cmd;
1517 u8 sec_level, auth_type;
1518 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001519 int err;
1520
1521 BT_DBG("");
1522
1523 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001524
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001525 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001526 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1527 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001528
Szymon Janc4e51eae2011-02-25 19:05:48 +01001529 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001530 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001531 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1532 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001533
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001534 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001535
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001536 sec_level = BT_SECURITY_MEDIUM;
1537 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001538 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001539 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001540 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001541
Johan Hedbergba4e5642011-11-11 00:07:34 +02001542 if (cp->addr.type == MGMT_ADDR_BREDR)
1543 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001544 auth_type);
1545 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001546 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001547 auth_type);
1548
Johan Hedberg1425acb2011-11-11 00:07:35 +02001549 memset(&rp, 0, sizeof(rp));
1550 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1551 rp.addr.type = cp->addr.type;
1552
Ville Tervo30e76272011-02-22 16:10:53 -03001553 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001554 rp.status = -PTR_ERR(conn);
1555 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1556 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001557 goto unlock;
1558 }
1559
1560 if (conn->connect_cfm_cb) {
1561 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001562 rp.status = EBUSY;
1563 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1564 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001565 goto unlock;
1566 }
1567
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001568 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001569 if (!cmd) {
1570 err = -ENOMEM;
1571 hci_conn_put(conn);
1572 goto unlock;
1573 }
1574
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001575 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001576 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001577 conn->connect_cfm_cb = pairing_complete_cb;
1578
Johan Hedberge9a416b2011-02-19 12:05:56 -03001579 conn->security_cfm_cb = pairing_complete_cb;
1580 conn->disconn_cfm_cb = pairing_complete_cb;
1581 conn->io_capability = cp->io_cap;
1582 cmd->user_data = conn;
1583
1584 if (conn->state == BT_CONNECTED &&
1585 hci_conn_security(conn, sec_level, auth_type))
1586 pairing_complete(cmd, 0);
1587
1588 err = 0;
1589
1590unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001591 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001592 hci_dev_put(hdev);
1593
1594 return err;
1595}
1596
Johan Hedberg28424702012-02-02 04:02:29 +02001597static int cancel_pair_device(struct sock *sk, u16 index,
1598 unsigned char *data, u16 len)
1599{
1600 struct mgmt_addr_info *addr = (void *) data;
1601 struct hci_dev *hdev;
1602 struct pending_cmd *cmd;
1603 struct hci_conn *conn;
1604 int err;
1605
1606 BT_DBG("");
1607
1608 if (len != sizeof(*addr))
1609 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1610 MGMT_STATUS_INVALID_PARAMS);
1611
1612 hdev = hci_dev_get(index);
1613 if (!hdev)
1614 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1615 MGMT_STATUS_INVALID_PARAMS);
1616
1617 hci_dev_lock(hdev);
1618
1619 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1620 if (!cmd) {
1621 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1622 MGMT_STATUS_INVALID_PARAMS);
1623 goto unlock;
1624 }
1625
1626 conn = cmd->user_data;
1627
1628 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1629 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1630 MGMT_STATUS_INVALID_PARAMS);
1631 goto unlock;
1632 }
1633
1634 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1635
1636 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, addr,
1637 sizeof(*addr));
1638unlock:
1639 hci_dev_unlock(hdev);
1640 hci_dev_put(hdev);
1641
1642 return err;
1643}
1644
Brian Gix0df4c182011-11-16 13:53:13 -08001645static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1646 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001647{
Johan Hedberga5c29682011-02-19 12:05:57 -03001648 struct pending_cmd *cmd;
1649 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001650 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001651 int err;
1652
Szymon Janc4e51eae2011-02-25 19:05:48 +01001653 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001654 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001655 return cmd_status(sk, index, mgmt_op,
1656 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001657
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001658 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001659
Johan Hedberga5c29682011-02-19 12:05:57 -03001660 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001661 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1662 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001663 }
1664
Brian Gix47c15e22011-11-16 13:53:14 -08001665 /*
1666 * Check for an existing ACL link, if present pair via
1667 * HCI commands.
1668 *
1669 * If no ACL link is present, check for an LE link and if
1670 * present, pair via the SMP engine.
1671 *
1672 * If neither ACL nor LE links are present, fail with error.
1673 */
1674 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1675 if (!conn) {
1676 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1677 if (!conn) {
1678 err = cmd_status(sk, index, mgmt_op,
1679 MGMT_STATUS_NOT_CONNECTED);
1680 goto done;
1681 }
1682
1683 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001684 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001685
Brian Gix5fe57d92011-12-21 16:12:13 -08001686 if (!err)
1687 err = cmd_status(sk, index, mgmt_op,
1688 MGMT_STATUS_SUCCESS);
1689 else
1690 err = cmd_status(sk, index, mgmt_op,
1691 MGMT_STATUS_FAILED);
1692
Brian Gix47c15e22011-11-16 13:53:14 -08001693 goto done;
1694 }
1695
Brian Gix0df4c182011-11-16 13:53:13 -08001696 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001697 if (!cmd) {
1698 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001699 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001700 }
1701
Brian Gix0df4c182011-11-16 13:53:13 -08001702 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001703 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1704 struct hci_cp_user_passkey_reply cp;
1705
1706 bacpy(&cp.bdaddr, bdaddr);
1707 cp.passkey = passkey;
1708 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1709 } else
1710 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1711
Johan Hedberga664b5b2011-02-19 12:06:02 -03001712 if (err < 0)
1713 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001714
Brian Gix0df4c182011-11-16 13:53:13 -08001715done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001716 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001717 hci_dev_put(hdev);
1718
1719 return err;
1720}
1721
Brian Gix0df4c182011-11-16 13:53:13 -08001722static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1723{
1724 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1725
1726 BT_DBG("");
1727
1728 if (len != sizeof(*cp))
1729 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1730 MGMT_STATUS_INVALID_PARAMS);
1731
1732 return user_pairing_resp(sk, index, &cp->bdaddr,
1733 MGMT_OP_USER_CONFIRM_REPLY,
1734 HCI_OP_USER_CONFIRM_REPLY, 0);
1735}
1736
1737static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1738 u16 len)
1739{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001740 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001741
1742 BT_DBG("");
1743
1744 if (len != sizeof(*cp))
1745 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1746 MGMT_STATUS_INVALID_PARAMS);
1747
1748 return user_pairing_resp(sk, index, &cp->bdaddr,
1749 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1750 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1751}
1752
Brian Gix604086b2011-11-23 08:28:33 -08001753static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1754{
1755 struct mgmt_cp_user_passkey_reply *cp = (void *) data;
1756
1757 BT_DBG("");
1758
1759 if (len != sizeof(*cp))
1760 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1761 EINVAL);
1762
1763 return user_pairing_resp(sk, index, &cp->bdaddr,
1764 MGMT_OP_USER_PASSKEY_REPLY,
1765 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1766}
1767
1768static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1769 u16 len)
1770{
1771 struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data;
1772
1773 BT_DBG("");
1774
1775 if (len != sizeof(*cp))
1776 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1777 EINVAL);
1778
1779 return user_pairing_resp(sk, index, &cp->bdaddr,
1780 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1781 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1782}
1783
Johan Hedbergb312b1612011-03-16 14:29:37 +02001784static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1785 u16 len)
1786{
1787 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1788 struct hci_cp_write_local_name hci_cp;
1789 struct hci_dev *hdev;
1790 struct pending_cmd *cmd;
1791 int err;
1792
1793 BT_DBG("");
1794
1795 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001796 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1797 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001798
1799 hdev = hci_dev_get(index);
1800 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001801 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1802 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001803
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001804 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001805
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001806 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001807 if (!cmd) {
1808 err = -ENOMEM;
1809 goto failed;
1810 }
1811
1812 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1813 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1814 &hci_cp);
1815 if (err < 0)
1816 mgmt_pending_remove(cmd);
1817
1818failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001819 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001820 hci_dev_put(hdev);
1821
1822 return err;
1823}
1824
Szymon Jancc35938b2011-03-22 13:12:21 +01001825static int read_local_oob_data(struct sock *sk, u16 index)
1826{
1827 struct hci_dev *hdev;
1828 struct pending_cmd *cmd;
1829 int err;
1830
1831 BT_DBG("hci%u", index);
1832
1833 hdev = hci_dev_get(index);
1834 if (!hdev)
1835 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001836 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001837
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001838 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001839
1840 if (!test_bit(HCI_UP, &hdev->flags)) {
1841 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001842 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001843 goto unlock;
1844 }
1845
1846 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1847 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001848 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001849 goto unlock;
1850 }
1851
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001852 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001853 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1854 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001855 goto unlock;
1856 }
1857
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001858 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001859 if (!cmd) {
1860 err = -ENOMEM;
1861 goto unlock;
1862 }
1863
1864 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1865 if (err < 0)
1866 mgmt_pending_remove(cmd);
1867
1868unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001869 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001870 hci_dev_put(hdev);
1871
1872 return err;
1873}
1874
Szymon Janc2763eda2011-03-22 13:12:22 +01001875static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1876 u16 len)
1877{
1878 struct hci_dev *hdev;
1879 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1880 int err;
1881
1882 BT_DBG("hci%u ", index);
1883
1884 if (len != sizeof(*cp))
1885 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001886 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001887
1888 hdev = hci_dev_get(index);
1889 if (!hdev)
1890 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001891 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001892
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001893 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001894
1895 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1896 cp->randomizer);
1897 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001898 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1899 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001900 else
1901 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1902 0);
1903
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001904 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001905 hci_dev_put(hdev);
1906
1907 return err;
1908}
1909
1910static int remove_remote_oob_data(struct sock *sk, u16 index,
1911 unsigned char *data, u16 len)
1912{
1913 struct hci_dev *hdev;
1914 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1915 int err;
1916
1917 BT_DBG("hci%u ", index);
1918
1919 if (len != sizeof(*cp))
1920 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001921 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001922
1923 hdev = hci_dev_get(index);
1924 if (!hdev)
1925 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001926 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001927
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001928 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001929
1930 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1931 if (err < 0)
1932 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001933 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001934 else
1935 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1936 NULL, 0);
1937
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001938 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001939 hci_dev_put(hdev);
1940
1941 return err;
1942}
1943
Johan Hedberg450dfda2011-11-12 11:58:22 +02001944static int start_discovery(struct sock *sk, u16 index,
1945 unsigned char *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001946{
Johan Hedberg450dfda2011-11-12 11:58:22 +02001947 struct mgmt_cp_start_discovery *cp = (void *) data;
Johan Hedberg14a53662011-04-27 10:29:56 -04001948 struct pending_cmd *cmd;
1949 struct hci_dev *hdev;
1950 int err;
1951
1952 BT_DBG("hci%u", index);
1953
Johan Hedberg450dfda2011-11-12 11:58:22 +02001954 if (len != sizeof(*cp))
1955 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1956 MGMT_STATUS_INVALID_PARAMS);
1957
Johan Hedberg14a53662011-04-27 10:29:56 -04001958 hdev = hci_dev_get(index);
1959 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001960 return cmd_status(sk, index, MGMT_OP_START_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 Hedbergbd2d1332011-11-07 23:13:37 +02001965 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001966 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1967 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001968 goto failed;
1969 }
1970
Johan Hedbergff9ef572012-01-04 14:23:45 +02001971 if (hdev->discovery.state != DISCOVERY_STOPPED) {
1972 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1973 MGMT_STATUS_BUSY);
1974 goto failed;
1975 }
1976
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001977 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001978 if (!cmd) {
1979 err = -ENOMEM;
1980 goto failed;
1981 }
1982
Andre Guedes2519a1f2011-11-07 11:45:24 -03001983 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001984 if (err < 0)
1985 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02001986 else
1987 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04001988
1989failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001990 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001991 hci_dev_put(hdev);
1992
1993 return err;
1994}
1995
1996static int stop_discovery(struct sock *sk, u16 index)
1997{
1998 struct hci_dev *hdev;
1999 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002000 struct hci_cp_remote_name_req_cancel cp;
2001 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002002 int err;
2003
2004 BT_DBG("hci%u", index);
2005
2006 hdev = hci_dev_get(index);
2007 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002008 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2009 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002010
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002011 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002012
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002013 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002014 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2015 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002016 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002017 }
2018
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002019 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002020 if (!cmd) {
2021 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002022 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002023 }
2024
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002025 if (hdev->discovery.state == DISCOVERY_INQUIRY) {
2026 err = hci_cancel_inquiry(hdev);
2027 if (err < 0)
2028 mgmt_pending_remove(cmd);
2029 else
2030 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2031 goto unlock;
2032 }
2033
2034 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2035 if (!e) {
2036 mgmt_pending_remove(cmd);
2037 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, NULL, 0);
2038 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2039 goto unlock;
2040 }
2041
2042 bacpy(&cp.bdaddr, &e->data.bdaddr);
2043 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2044 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002045 if (err < 0)
2046 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002047 else
2048 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002049
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002050unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002051 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002052 hci_dev_put(hdev);
2053
2054 return err;
2055}
2056
Johan Hedberg561aafb2012-01-04 13:31:59 +02002057static int confirm_name(struct sock *sk, u16 index, unsigned char *data,
2058 u16 len)
2059{
2060 struct mgmt_cp_confirm_name *cp = (void *) data;
2061 struct inquiry_entry *e;
2062 struct hci_dev *hdev;
2063 int err;
2064
2065 BT_DBG("hci%u", index);
2066
2067 if (len != sizeof(*cp))
2068 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2069 MGMT_STATUS_INVALID_PARAMS);
2070
2071 hdev = hci_dev_get(index);
2072 if (!hdev)
2073 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2074 MGMT_STATUS_INVALID_PARAMS);
2075
2076 hci_dev_lock(hdev);
2077
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002078 if (!hci_discovery_active(hdev)) {
2079 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2080 MGMT_STATUS_FAILED);
2081 goto failed;
2082 }
2083
Johan Hedberg561aafb2012-01-04 13:31:59 +02002084 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->bdaddr);
2085 if (!e) {
2086 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2087 MGMT_STATUS_INVALID_PARAMS);
2088 goto failed;
2089 }
2090
2091 if (cp->name_known) {
2092 e->name_state = NAME_KNOWN;
2093 list_del(&e->list);
2094 } else {
2095 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002096 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002097 }
2098
2099 err = 0;
2100
2101failed:
2102 hci_dev_unlock(hdev);
2103
2104 return err;
2105}
2106
Antti Julku7fbec222011-06-15 12:01:15 +03002107static int block_device(struct sock *sk, u16 index, unsigned char *data,
2108 u16 len)
2109{
2110 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03002111 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03002112 int err;
2113
2114 BT_DBG("hci%u", index);
2115
Antti Julku7fbec222011-06-15 12:01:15 +03002116 if (len != sizeof(*cp))
2117 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002118 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002119
2120 hdev = hci_dev_get(index);
2121 if (!hdev)
2122 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002123 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002124
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002125 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002126
Antti Julku7fbec222011-06-15 12:01:15 +03002127 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03002128 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002129 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2130 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002131 else
2132 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2133 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002134
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002135 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002136 hci_dev_put(hdev);
2137
2138 return err;
2139}
2140
2141static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
2142 u16 len)
2143{
2144 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03002145 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03002146 int err;
2147
2148 BT_DBG("hci%u", index);
2149
Antti Julku7fbec222011-06-15 12:01:15 +03002150 if (len != sizeof(*cp))
2151 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002152 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002153
2154 hdev = hci_dev_get(index);
2155 if (!hdev)
2156 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002157 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002158
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002159 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002160
Antti Julku7fbec222011-06-15 12:01:15 +03002161 err = hci_blacklist_del(hdev, &cp->bdaddr);
2162
2163 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002164 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2165 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002166 else
2167 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2168 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002169
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002170 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002171 hci_dev_put(hdev);
2172
2173 return err;
2174}
2175
Antti Julkuf6422ec2011-06-22 13:11:56 +03002176static int set_fast_connectable(struct sock *sk, u16 index,
2177 unsigned char *data, u16 len)
2178{
2179 struct hci_dev *hdev;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002180 struct mgmt_mode *cp = (void *) data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002181 struct hci_cp_write_page_scan_activity acp;
2182 u8 type;
2183 int err;
2184
2185 BT_DBG("hci%u", index);
2186
2187 if (len != sizeof(*cp))
2188 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002189 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002190
2191 hdev = hci_dev_get(index);
2192 if (!hdev)
2193 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002194 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002195
2196 hci_dev_lock(hdev);
2197
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002198 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002199 type = PAGE_SCAN_TYPE_INTERLACED;
2200 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2201 } else {
2202 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2203 acp.interval = 0x0800; /* default 1.28 sec page scan */
2204 }
2205
2206 acp.window = 0x0012; /* default 11.25 msec page scan window */
2207
2208 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2209 sizeof(acp), &acp);
2210 if (err < 0) {
2211 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002212 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002213 goto done;
2214 }
2215
2216 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2217 if (err < 0) {
2218 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002219 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002220 goto done;
2221 }
2222
2223 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2224 NULL, 0);
2225done:
2226 hci_dev_unlock(hdev);
2227 hci_dev_put(hdev);
2228
2229 return err;
2230}
2231
Johan Hedberg03811012010-12-08 00:21:06 +02002232int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2233{
2234 unsigned char *buf;
2235 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002236 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002237 int err;
2238
2239 BT_DBG("got %zu bytes", msglen);
2240
2241 if (msglen < sizeof(*hdr))
2242 return -EINVAL;
2243
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002244 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002245 if (!buf)
2246 return -ENOMEM;
2247
2248 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2249 err = -EFAULT;
2250 goto done;
2251 }
2252
2253 hdr = (struct mgmt_hdr *) buf;
2254 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002255 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002256 len = get_unaligned_le16(&hdr->len);
2257
2258 if (len != msglen - sizeof(*hdr)) {
2259 err = -EINVAL;
2260 goto done;
2261 }
2262
2263 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002264 case MGMT_OP_READ_VERSION:
2265 err = read_version(sk);
2266 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002267 case MGMT_OP_READ_INDEX_LIST:
2268 err = read_index_list(sk);
2269 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002270 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002271 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002272 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002273 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002274 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002275 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002276 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002277 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002278 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002279 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002280 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002281 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002282 case MGMT_OP_SET_FAST_CONNECTABLE:
2283 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
2284 len);
2285 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002286 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002287 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002288 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002289 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002290 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002291 break;
2292 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002293 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002294 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002295 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002296 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002297 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002298 case MGMT_OP_LOAD_LINK_KEYS:
2299 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002300 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002301 case MGMT_OP_REMOVE_KEYS:
2302 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002303 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002304 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002305 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002306 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002307 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002308 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002309 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002310 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002311 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002312 break;
2313 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002314 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002315 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002316 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002317 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002318 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002319 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002320 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002321 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002322 case MGMT_OP_CANCEL_PAIR_DEVICE:
2323 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2324 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002325 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002326 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002327 break;
2328 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002329 err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr),
2330 len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002331 break;
Brian Gix604086b2011-11-23 08:28:33 -08002332 case MGMT_OP_USER_PASSKEY_REPLY:
2333 err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len);
2334 break;
2335 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
2336 err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr),
2337 len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002338 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002339 case MGMT_OP_SET_LOCAL_NAME:
2340 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2341 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002342 case MGMT_OP_READ_LOCAL_OOB_DATA:
2343 err = read_local_oob_data(sk, index);
2344 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002345 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2346 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2347 break;
2348 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2349 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2350 len);
2351 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002352 case MGMT_OP_START_DISCOVERY:
Johan Hedberg450dfda2011-11-12 11:58:22 +02002353 err = start_discovery(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002354 break;
2355 case MGMT_OP_STOP_DISCOVERY:
2356 err = stop_discovery(sk, index);
2357 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002358 case MGMT_OP_CONFIRM_NAME:
2359 err = confirm_name(sk, index, buf + sizeof(*hdr), len);
2360 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002361 case MGMT_OP_BLOCK_DEVICE:
2362 err = block_device(sk, index, buf + sizeof(*hdr), len);
2363 break;
2364 case MGMT_OP_UNBLOCK_DEVICE:
2365 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
2366 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002367 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002368 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002369 err = cmd_status(sk, index, opcode,
2370 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002371 break;
2372 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002373
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002374 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002375 goto done;
2376
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002377 err = msglen;
2378
2379done:
2380 kfree(buf);
2381 return err;
2382}
2383
Johan Hedbergb24752f2011-11-03 14:40:33 +02002384static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2385{
2386 u8 *status = data;
2387
2388 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2389 mgmt_pending_remove(cmd);
2390}
2391
Johan Hedberg744cf192011-11-08 20:40:14 +02002392int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002393{
Johan Hedberg744cf192011-11-08 20:40:14 +02002394 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002395}
2396
Johan Hedberg744cf192011-11-08 20:40:14 +02002397int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002398{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002399 u8 status = ENODEV;
2400
Johan Hedberg744cf192011-11-08 20:40:14 +02002401 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002402
Johan Hedberg744cf192011-11-08 20:40:14 +02002403 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002404}
2405
2406struct cmd_lookup {
2407 u8 val;
2408 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002409 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002410};
2411
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002412static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002413{
Johan Hedberg03811012010-12-08 00:21:06 +02002414 struct cmd_lookup *match = data;
2415
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002416 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002417
2418 list_del(&cmd->list);
2419
2420 if (match->sk == NULL) {
2421 match->sk = cmd->sk;
2422 sock_hold(match->sk);
2423 }
2424
2425 mgmt_pending_free(cmd);
2426}
2427
Johan Hedberg744cf192011-11-08 20:40:14 +02002428int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002429{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002430 struct cmd_lookup match = { powered, NULL, hdev };
2431 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002432 int ret;
2433
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002434 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002435
Johan Hedbergb24752f2011-11-03 14:40:33 +02002436 if (!powered) {
2437 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002438 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002439 }
2440
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002441 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002442
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002443 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2444 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002445
2446 if (match.sk)
2447 sock_put(match.sk);
2448
2449 return ret;
2450}
2451
Johan Hedberg744cf192011-11-08 20:40:14 +02002452int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002453{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002454 struct cmd_lookup match = { discoverable, NULL, hdev };
2455 __le32 ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002456 int ret;
2457
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002458 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002459
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002460 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002461
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002462 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002463 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002464 if (match.sk)
2465 sock_put(match.sk);
2466
2467 return ret;
2468}
2469
Johan Hedberg744cf192011-11-08 20:40:14 +02002470int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002471{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002472 __le32 ev;
2473 struct cmd_lookup match = { connectable, NULL, hdev };
Johan Hedberg03811012010-12-08 00:21:06 +02002474 int ret;
2475
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002476 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2477 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002478
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002479 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002480
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002481 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002482
2483 if (match.sk)
2484 sock_put(match.sk);
2485
2486 return ret;
2487}
2488
Johan Hedberg744cf192011-11-08 20:40:14 +02002489int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002490{
Johan Hedbergca69b792011-11-11 18:10:00 +02002491 u8 mgmt_err = mgmt_status(status);
2492
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002493 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002494 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002495 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002496
2497 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002498 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002499 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002500
2501 return 0;
2502}
2503
Johan Hedberg744cf192011-11-08 20:40:14 +02002504int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2505 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002506{
Johan Hedberg86742e12011-11-07 23:13:38 +02002507 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002508
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002509 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002510
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002511 ev.store_hint = persistent;
2512 bacpy(&ev.key.bdaddr, &key->bdaddr);
2513 ev.key.type = key->type;
2514 memcpy(ev.key.val, key->val, 16);
2515 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002516
Johan Hedberg744cf192011-11-08 20:40:14 +02002517 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002518}
Johan Hedbergf7520542011-01-20 12:34:39 +02002519
Johan Hedbergafc747a2012-01-15 18:11:07 +02002520int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002521 u8 addr_type, u8 *name, u8 name_len,
2522 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002523{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002524 char buf[512];
2525 struct mgmt_ev_device_connected *ev = (void *) buf;
2526 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002527
Johan Hedbergb644ba32012-01-17 21:48:47 +02002528 bacpy(&ev->addr.bdaddr, bdaddr);
2529 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002530
Johan Hedbergb644ba32012-01-17 21:48:47 +02002531 if (name_len > 0)
2532 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2533 name, name_len);
2534
2535 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2536 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2537 EIR_CLASS_OF_DEV, dev_class, 3);
2538
2539 put_unaligned_le16(eir_len, &ev->eir_len);
2540
2541 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2542 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002543}
2544
Johan Hedberg8962ee72011-01-20 12:40:27 +02002545static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2546{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002547 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002548 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002549 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002550
Johan Hedberga38528f2011-01-22 06:46:43 +02002551 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002552 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002553
Szymon Janc4e51eae2011-02-25 19:05:48 +01002554 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002555
2556 *sk = cmd->sk;
2557 sock_hold(*sk);
2558
Johan Hedberga664b5b2011-02-19 12:06:02 -03002559 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002560}
2561
Johan Hedberga8a1d192011-11-10 15:54:38 +02002562static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2563{
2564 u8 *status = data;
2565 struct mgmt_cp_remove_keys *cp = cmd->param;
2566 struct mgmt_rp_remove_keys rp;
2567
2568 memset(&rp, 0, sizeof(rp));
2569 bacpy(&rp.bdaddr, &cp->bdaddr);
2570 if (status != NULL)
2571 rp.status = *status;
2572
2573 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2574 sizeof(rp));
2575
2576 mgmt_pending_remove(cmd);
2577}
2578
Johan Hedbergafc747a2012-01-15 18:11:07 +02002579int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2580 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002581{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002582 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002583 struct sock *sk = NULL;
2584 int err;
2585
Johan Hedberg744cf192011-11-08 20:40:14 +02002586 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002587
Johan Hedbergf7520542011-01-20 12:34:39 +02002588 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002589 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002590
Johan Hedbergafc747a2012-01-15 18:11:07 +02002591 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2592 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002593
2594 if (sk)
2595 sock_put(sk);
2596
Johan Hedberga8a1d192011-11-10 15:54:38 +02002597 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2598
Johan Hedberg8962ee72011-01-20 12:40:27 +02002599 return err;
2600}
2601
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002602int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002603{
2604 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002605 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002606 int err;
2607
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002608 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002609 if (!cmd)
2610 return -ENOENT;
2611
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002612 if (bdaddr) {
2613 struct mgmt_rp_disconnect rp;
2614
2615 bacpy(&rp.bdaddr, bdaddr);
2616 rp.status = status;
2617
2618 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2619 &rp, sizeof(rp));
2620 } else
2621 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002622 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002623
Johan Hedberga664b5b2011-02-19 12:06:02 -03002624 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002625
2626 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002627}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002628
Johan Hedberg48264f02011-11-09 13:58:58 +02002629int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2630 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002631{
2632 struct mgmt_ev_connect_failed ev;
2633
Johan Hedberg4c659c32011-11-07 23:13:39 +02002634 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002635 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002636 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002637
Johan Hedberg744cf192011-11-08 20:40:14 +02002638 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002639}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002640
Johan Hedberg744cf192011-11-08 20:40:14 +02002641int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002642{
2643 struct mgmt_ev_pin_code_request ev;
2644
Johan Hedberg980e1a52011-01-22 06:10:07 +02002645 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002646 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002647
Johan Hedberg744cf192011-11-08 20:40:14 +02002648 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002649 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002650}
2651
Johan Hedberg744cf192011-11-08 20:40:14 +02002652int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2653 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002654{
2655 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002656 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002657 int err;
2658
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002659 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002660 if (!cmd)
2661 return -ENOENT;
2662
Johan Hedbergac56fb12011-02-19 12:05:59 -03002663 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002664 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002665
Johan Hedberg744cf192011-11-08 20:40:14 +02002666 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002667 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002668
Johan Hedberga664b5b2011-02-19 12:06:02 -03002669 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002670
2671 return err;
2672}
2673
Johan Hedberg744cf192011-11-08 20:40:14 +02002674int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2675 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002676{
2677 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002678 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002679 int err;
2680
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002681 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002682 if (!cmd)
2683 return -ENOENT;
2684
Johan Hedbergac56fb12011-02-19 12:05:59 -03002685 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002686 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002687
Johan Hedberg744cf192011-11-08 20:40:14 +02002688 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002689 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002690
Johan Hedberga664b5b2011-02-19 12:06:02 -03002691 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002692
2693 return err;
2694}
Johan Hedberga5c29682011-02-19 12:05:57 -03002695
Johan Hedberg744cf192011-11-08 20:40:14 +02002696int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2697 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002698{
2699 struct mgmt_ev_user_confirm_request ev;
2700
Johan Hedberg744cf192011-11-08 20:40:14 +02002701 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002702
Johan Hedberga5c29682011-02-19 12:05:57 -03002703 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002704 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002705 put_unaligned_le32(value, &ev.value);
2706
Johan Hedberg744cf192011-11-08 20:40:14 +02002707 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002708 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002709}
2710
Brian Gix604086b2011-11-23 08:28:33 -08002711int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2712{
2713 struct mgmt_ev_user_passkey_request ev;
2714
2715 BT_DBG("%s", hdev->name);
2716
2717 bacpy(&ev.bdaddr, bdaddr);
2718
2719 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2720 NULL);
2721}
2722
Brian Gix0df4c182011-11-16 13:53:13 -08002723static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002724 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002725{
2726 struct pending_cmd *cmd;
2727 struct mgmt_rp_user_confirm_reply rp;
2728 int err;
2729
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002730 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002731 if (!cmd)
2732 return -ENOENT;
2733
Johan Hedberga5c29682011-02-19 12:05:57 -03002734 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002735 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002736 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002737
Johan Hedberga664b5b2011-02-19 12:06:02 -03002738 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002739
2740 return err;
2741}
2742
Johan Hedberg744cf192011-11-08 20:40:14 +02002743int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2744 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002745{
Brian Gix0df4c182011-11-16 13:53:13 -08002746 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002747 MGMT_OP_USER_CONFIRM_REPLY);
2748}
2749
Johan Hedberg744cf192011-11-08 20:40:14 +02002750int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2751 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002752{
Brian Gix0df4c182011-11-16 13:53:13 -08002753 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002754 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2755}
Johan Hedberg2a611692011-02-19 12:06:00 -03002756
Brian Gix604086b2011-11-23 08:28:33 -08002757int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2758 u8 status)
2759{
2760 return user_pairing_resp_complete(hdev, bdaddr, status,
2761 MGMT_OP_USER_PASSKEY_REPLY);
2762}
2763
2764int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2765 bdaddr_t *bdaddr, u8 status)
2766{
2767 return user_pairing_resp_complete(hdev, bdaddr, status,
2768 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2769}
2770
Johan Hedberg744cf192011-11-08 20:40:14 +02002771int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002772{
2773 struct mgmt_ev_auth_failed ev;
2774
Johan Hedberg2a611692011-02-19 12:06:00 -03002775 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002776 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002777
Johan Hedberg744cf192011-11-08 20:40:14 +02002778 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002779}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002780
Johan Hedberg744cf192011-11-08 20:40:14 +02002781int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002782{
2783 struct pending_cmd *cmd;
2784 struct mgmt_cp_set_local_name ev;
2785 int err;
2786
2787 memset(&ev, 0, sizeof(ev));
2788 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2789
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002790 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002791 if (!cmd)
2792 goto send_event;
2793
2794 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002795 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002796 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002797 goto failed;
2798 }
2799
Johan Hedberg744cf192011-11-08 20:40:14 +02002800 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002801
Johan Hedberg744cf192011-11-08 20:40:14 +02002802 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002803 sizeof(ev));
2804 if (err < 0)
2805 goto failed;
2806
2807send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002808 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002809 cmd ? cmd->sk : NULL);
2810
2811failed:
2812 if (cmd)
2813 mgmt_pending_remove(cmd);
2814 return err;
2815}
Szymon Jancc35938b2011-03-22 13:12:21 +01002816
Johan Hedberg744cf192011-11-08 20:40:14 +02002817int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2818 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002819{
2820 struct pending_cmd *cmd;
2821 int err;
2822
Johan Hedberg744cf192011-11-08 20:40:14 +02002823 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002824
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002825 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002826 if (!cmd)
2827 return -ENOENT;
2828
2829 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002830 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002831 MGMT_OP_READ_LOCAL_OOB_DATA,
2832 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002833 } else {
2834 struct mgmt_rp_read_local_oob_data rp;
2835
2836 memcpy(rp.hash, hash, sizeof(rp.hash));
2837 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2838
Johan Hedberg744cf192011-11-08 20:40:14 +02002839 err = cmd_complete(cmd->sk, hdev->id,
2840 MGMT_OP_READ_LOCAL_OOB_DATA,
2841 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002842 }
2843
2844 mgmt_pending_remove(cmd);
2845
2846 return err;
2847}
Johan Hedberge17acd42011-03-30 23:57:16 +03002848
Johan Hedberg48264f02011-11-09 13:58:58 +02002849int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02002850 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02002851 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03002852{
Johan Hedberge319d2e2012-01-15 19:51:59 +02002853 char buf[512];
2854 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02002855 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03002856
Johan Hedberg1dc06092012-01-15 21:01:23 +02002857 /* Leave 5 bytes for a potential CoD field */
2858 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03002859 return -EINVAL;
2860
Johan Hedberg1dc06092012-01-15 21:01:23 +02002861 memset(buf, 0, sizeof(buf));
2862
Johan Hedberge319d2e2012-01-15 19:51:59 +02002863 bacpy(&ev->addr.bdaddr, bdaddr);
2864 ev->addr.type = link_to_mgmt(link_type, addr_type);
2865 ev->rssi = rssi;
2866 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03002867
Johan Hedberg1dc06092012-01-15 21:01:23 +02002868 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02002869 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03002870
Johan Hedberg1dc06092012-01-15 21:01:23 +02002871 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
2872 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
2873 dev_class, 3);
2874
2875 put_unaligned_le16(eir_len, &ev->eir_len);
2876
2877 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03002878
Johan Hedberge319d2e2012-01-15 19:51:59 +02002879 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002880}
Johan Hedberga88a9652011-03-30 13:18:12 +03002881
Johan Hedbergb644ba32012-01-17 21:48:47 +02002882int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2883 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03002884{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002885 struct mgmt_ev_device_found *ev;
2886 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
2887 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03002888
Johan Hedbergb644ba32012-01-17 21:48:47 +02002889 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03002890
Johan Hedbergb644ba32012-01-17 21:48:47 +02002891 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03002892
Johan Hedbergb644ba32012-01-17 21:48:47 +02002893 bacpy(&ev->addr.bdaddr, bdaddr);
2894 ev->addr.type = link_to_mgmt(link_type, addr_type);
2895 ev->rssi = rssi;
2896
2897 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
2898 name_len);
2899
2900 put_unaligned_le16(eir_len, &ev->eir_len);
2901
2902 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002903}
Johan Hedberg314b2382011-04-27 10:29:57 -04002904
Andre Guedes7a135102011-11-09 17:14:25 -03002905int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002906{
2907 struct pending_cmd *cmd;
2908 int err;
2909
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002910 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002911 if (!cmd)
2912 return -ENOENT;
2913
Johan Hedbergca69b792011-11-11 18:10:00 +02002914 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002915 mgmt_pending_remove(cmd);
2916
2917 return err;
2918}
2919
Andre Guedese6d465c2011-11-09 17:14:26 -03002920int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2921{
2922 struct pending_cmd *cmd;
2923 int err;
2924
2925 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2926 if (!cmd)
2927 return -ENOENT;
2928
Andre Guedese75a8b0c2012-01-02 16:50:53 -03002929 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02002930 mgmt_pending_remove(cmd);
2931
2932 return err;
2933}
Johan Hedberg314b2382011-04-27 10:29:57 -04002934
Johan Hedberg744cf192011-11-08 20:40:14 +02002935int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002936{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002937 struct pending_cmd *cmd;
2938
2939 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002940 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002941 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002942 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002943
2944 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002945 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002946 mgmt_pending_remove(cmd);
2947 }
2948
Johan Hedberg744cf192011-11-08 20:40:14 +02002949 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002950 sizeof(discovering), NULL);
2951}
Antti Julku5e762442011-08-25 16:48:02 +03002952
Johan Hedberg744cf192011-11-08 20:40:14 +02002953int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002954{
2955 struct pending_cmd *cmd;
2956 struct mgmt_ev_device_blocked ev;
2957
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002958 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002959
2960 bacpy(&ev.bdaddr, bdaddr);
2961
Johan Hedberg744cf192011-11-08 20:40:14 +02002962 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2963 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002964}
2965
Johan Hedberg744cf192011-11-08 20:40:14 +02002966int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002967{
2968 struct pending_cmd *cmd;
2969 struct mgmt_ev_device_unblocked ev;
2970
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002971 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002972
2973 bacpy(&ev.bdaddr, bdaddr);
2974
Johan Hedberg744cf192011-11-08 20:40:14 +02002975 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2976 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002977}