blob: 8413f55cc13ca07a3e23514e67eba3bc90c783f4 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Johan Hedbergca69b792011-11-11 18:10:00 +020025#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020027#include <asm/unaligned.h>
28
29#include <net/bluetooth/bluetooth.h>
30#include <net/bluetooth/hci_core.h>
31#include <net/bluetooth/mgmt.h>
32
Johan Hedberg02d98122010-12-13 21:07:04 +020033#define MGMT_VERSION 0
34#define MGMT_REVISION 1
35
Andre Guedes2519a1f2011-11-07 11:45:24 -030036#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
37
Johan Hedberg7d785252011-12-15 00:47:39 +020038#define SERVICE_CACHE_TIMEOUT (5 * 1000)
39
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020040struct pending_cmd {
41 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020042 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020043 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010044 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030046 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020047};
48
Johan Hedbergca69b792011-11-11 18:10:00 +020049/* HCI to MGMT error code conversion table */
50static u8 mgmt_status_table[] = {
51 MGMT_STATUS_SUCCESS,
52 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
53 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
54 MGMT_STATUS_FAILED, /* Hardware Failure */
55 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
56 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
57 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
58 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
59 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
60 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
61 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
62 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
63 MGMT_STATUS_BUSY, /* Command Disallowed */
64 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
65 MGMT_STATUS_REJECTED, /* Rejected Security */
66 MGMT_STATUS_REJECTED, /* Rejected Personal */
67 MGMT_STATUS_TIMEOUT, /* Host Timeout */
68 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
69 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
70 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
71 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
72 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
73 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
74 MGMT_STATUS_BUSY, /* Repeated Attempts */
75 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
76 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
77 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
78 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
79 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
80 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
81 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
82 MGMT_STATUS_FAILED, /* Unspecified Error */
83 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
84 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
85 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
86 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
87 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
88 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
89 MGMT_STATUS_FAILED, /* Unit Link Key Used */
90 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
91 MGMT_STATUS_TIMEOUT, /* Instant Passed */
92 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
93 MGMT_STATUS_FAILED, /* Transaction Collision */
94 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
95 MGMT_STATUS_REJECTED, /* QoS Rejected */
96 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
97 MGMT_STATUS_REJECTED, /* Insufficient Security */
98 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
99 MGMT_STATUS_BUSY, /* Role Switch Pending */
100 MGMT_STATUS_FAILED, /* Slot Violation */
101 MGMT_STATUS_FAILED, /* Role Switch Failed */
102 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
103 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
104 MGMT_STATUS_BUSY, /* Host Busy Pairing */
105 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
106 MGMT_STATUS_BUSY, /* Controller Busy */
107 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
108 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
109 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
110 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
111 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
112};
113
114static u8 mgmt_status(u8 hci_status)
115{
116 if (hci_status < ARRAY_SIZE(mgmt_status_table))
117 return mgmt_status_table[hci_status];
118
119 return MGMT_STATUS_FAILED;
120}
121
Szymon Janc4e51eae2011-02-25 19:05:48 +0100122static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200123{
124 struct sk_buff *skb;
125 struct mgmt_hdr *hdr;
126 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300127 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200128
Szymon Janc34eb5252011-02-28 14:10:08 +0100129 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200130
131 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
132 if (!skb)
133 return -ENOMEM;
134
135 hdr = (void *) skb_put(skb, sizeof(*hdr));
136
137 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100138 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200139 hdr->len = cpu_to_le16(sizeof(*ev));
140
141 ev = (void *) skb_put(skb, sizeof(*ev));
142 ev->status = status;
143 put_unaligned_le16(cmd, &ev->opcode);
144
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300145 err = sock_queue_rcv_skb(sk, skb);
146 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200147 kfree_skb(skb);
148
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300149 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200150}
151
Szymon Janc4e51eae2011-02-25 19:05:48 +0100152static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
153 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200154{
155 struct sk_buff *skb;
156 struct mgmt_hdr *hdr;
157 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300158 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200159
160 BT_DBG("sock %p", sk);
161
Johan Hedberga38528f2011-01-22 06:46:43 +0200162 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200163 if (!skb)
164 return -ENOMEM;
165
166 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200167
Johan Hedberg02d98122010-12-13 21:07:04 +0200168 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100169 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200170 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200171
Johan Hedberga38528f2011-01-22 06:46:43 +0200172 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
173 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100174
175 if (rp)
176 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200177
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300178 err = sock_queue_rcv_skb(sk, skb);
179 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200180 kfree_skb(skb);
181
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300182 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200183}
184
Johan Hedberga38528f2011-01-22 06:46:43 +0200185static int read_version(struct sock *sk)
186{
187 struct mgmt_rp_read_version rp;
188
189 BT_DBG("sock %p", sk);
190
191 rp.version = MGMT_VERSION;
192 put_unaligned_le16(MGMT_REVISION, &rp.revision);
193
Szymon Janc4e51eae2011-02-25 19:05:48 +0100194 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
195 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200196}
197
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200198static int read_index_list(struct sock *sk)
199{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200200 struct mgmt_rp_read_index_list *rp;
201 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200202 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200204 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200205 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200206
207 BT_DBG("sock %p", sk);
208
209 read_lock(&hci_dev_list_lock);
210
211 count = 0;
212 list_for_each(p, &hci_dev_list) {
213 count++;
214 }
215
Johan Hedberga38528f2011-01-22 06:46:43 +0200216 rp_len = sizeof(*rp) + (2 * count);
217 rp = kmalloc(rp_len, GFP_ATOMIC);
218 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100219 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200220 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100221 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200222
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200223 put_unaligned_le16(count, &rp->num_controllers);
224
225 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200226 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberg32435532011-11-07 22:16:04 +0200227 if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200228 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200229
230 if (test_bit(HCI_SETUP, &d->flags))
231 continue;
232
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200233 put_unaligned_le16(d->id, &rp->index[i++]);
234 BT_DBG("Added hci%u", d->id);
235 }
236
237 read_unlock(&hci_dev_list_lock);
238
Szymon Janc4e51eae2011-02-25 19:05:48 +0100239 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
240 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200241
Johan Hedberga38528f2011-01-22 06:46:43 +0200242 kfree(rp);
243
244 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200245}
246
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200247static u32 get_supported_settings(struct hci_dev *hdev)
248{
249 u32 settings = 0;
250
251 settings |= MGMT_SETTING_POWERED;
252 settings |= MGMT_SETTING_CONNECTABLE;
253 settings |= MGMT_SETTING_FAST_CONNECTABLE;
254 settings |= MGMT_SETTING_DISCOVERABLE;
255 settings |= MGMT_SETTING_PAIRABLE;
256
257 if (hdev->features[6] & LMP_SIMPLE_PAIR)
258 settings |= MGMT_SETTING_SSP;
259
260 if (!(hdev->features[4] & LMP_NO_BREDR)) {
261 settings |= MGMT_SETTING_BREDR;
262 settings |= MGMT_SETTING_LINK_SECURITY;
263 }
264
265 if (hdev->features[4] & LMP_LE)
266 settings |= MGMT_SETTING_LE;
267
268 return settings;
269}
270
271static u32 get_current_settings(struct hci_dev *hdev)
272{
273 u32 settings = 0;
274
275 if (test_bit(HCI_UP, &hdev->flags))
276 settings |= MGMT_SETTING_POWERED;
277 else
278 return settings;
279
280 if (test_bit(HCI_PSCAN, &hdev->flags))
281 settings |= MGMT_SETTING_CONNECTABLE;
282
283 if (test_bit(HCI_ISCAN, &hdev->flags))
284 settings |= MGMT_SETTING_DISCOVERABLE;
285
286 if (test_bit(HCI_PAIRABLE, &hdev->flags))
287 settings |= MGMT_SETTING_PAIRABLE;
288
289 if (!(hdev->features[4] & LMP_NO_BREDR))
290 settings |= MGMT_SETTING_BREDR;
291
292 if (hdev->extfeatures[0] & LMP_HOST_LE)
293 settings |= MGMT_SETTING_LE;
294
295 if (test_bit(HCI_AUTH, &hdev->flags))
296 settings |= MGMT_SETTING_LINK_SECURITY;
297
298 if (hdev->ssp_mode > 0)
299 settings |= MGMT_SETTING_SSP;
300
301 return settings;
302}
303
Johan Hedbergef580372011-12-15 00:47:38 +0200304#define EIR_FLAGS 0x01 /* flags */
305#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
306#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
307#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
308#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
309#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
310#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
311#define EIR_NAME_SHORT 0x08 /* shortened local name */
312#define EIR_NAME_COMPLETE 0x09 /* complete local name */
313#define EIR_TX_POWER 0x0A /* transmit power level */
314#define EIR_DEVICE_ID 0x10 /* device ID */
315
316#define PNP_INFO_SVCLASS_ID 0x1200
317
318static u8 bluetooth_base_uuid[] = {
319 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
320 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321};
322
323static u16 get_uuid16(u8 *uuid128)
324{
325 u32 val;
326 int i;
327
328 for (i = 0; i < 12; i++) {
329 if (bluetooth_base_uuid[i] != uuid128[i])
330 return 0;
331 }
332
333 memcpy(&val, &uuid128[12], 4);
334
335 val = le32_to_cpu(val);
336 if (val > 0xffff)
337 return 0;
338
339 return (u16) val;
340}
341
342static void create_eir(struct hci_dev *hdev, u8 *data)
343{
344 u8 *ptr = data;
345 u16 eir_len = 0;
346 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
347 int i, truncated = 0;
348 struct bt_uuid *uuid;
349 size_t name_len;
350
351 name_len = strlen(hdev->dev_name);
352
353 if (name_len > 0) {
354 /* EIR Data type */
355 if (name_len > 48) {
356 name_len = 48;
357 ptr[1] = EIR_NAME_SHORT;
358 } else
359 ptr[1] = EIR_NAME_COMPLETE;
360
361 /* EIR Data length */
362 ptr[0] = name_len + 1;
363
364 memcpy(ptr + 2, hdev->dev_name, name_len);
365
366 eir_len += (name_len + 2);
367 ptr += (name_len + 2);
368 }
369
370 memset(uuid16_list, 0, sizeof(uuid16_list));
371
372 /* Group all UUID16 types */
373 list_for_each_entry(uuid, &hdev->uuids, list) {
374 u16 uuid16;
375
376 uuid16 = get_uuid16(uuid->uuid);
377 if (uuid16 == 0)
378 return;
379
380 if (uuid16 < 0x1100)
381 continue;
382
383 if (uuid16 == PNP_INFO_SVCLASS_ID)
384 continue;
385
386 /* Stop if not enough space to put next UUID */
387 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
388 truncated = 1;
389 break;
390 }
391
392 /* Check for duplicates */
393 for (i = 0; uuid16_list[i] != 0; i++)
394 if (uuid16_list[i] == uuid16)
395 break;
396
397 if (uuid16_list[i] == 0) {
398 uuid16_list[i] = uuid16;
399 eir_len += sizeof(u16);
400 }
401 }
402
403 if (uuid16_list[0] != 0) {
404 u8 *length = ptr;
405
406 /* EIR Data type */
407 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
408
409 ptr += 2;
410 eir_len += 2;
411
412 for (i = 0; uuid16_list[i] != 0; i++) {
413 *ptr++ = (uuid16_list[i] & 0x00ff);
414 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
415 }
416
417 /* EIR Data length */
418 *length = (i * sizeof(u16)) + 1;
419 }
420}
421
422static int update_eir(struct hci_dev *hdev)
423{
424 struct hci_cp_write_eir cp;
425
426 if (!(hdev->features[6] & LMP_EXT_INQ))
427 return 0;
428
429 if (hdev->ssp_mode == 0)
430 return 0;
431
432 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
433 return 0;
434
435 memset(&cp, 0, sizeof(cp));
436
437 create_eir(hdev, cp.data);
438
439 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
440 return 0;
441
442 memcpy(hdev->eir, cp.data, sizeof(cp.data));
443
444 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
445}
446
447static u8 get_service_classes(struct hci_dev *hdev)
448{
449 struct bt_uuid *uuid;
450 u8 val = 0;
451
452 list_for_each_entry(uuid, &hdev->uuids, list)
453 val |= uuid->svc_hint;
454
455 return val;
456}
457
458static int update_class(struct hci_dev *hdev)
459{
460 u8 cod[3];
461
462 BT_DBG("%s", hdev->name);
463
464 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
465 return 0;
466
467 cod[0] = hdev->minor_class;
468 cod[1] = hdev->major_class;
469 cod[2] = get_service_classes(hdev);
470
471 if (memcmp(cod, hdev->dev_class, 3) == 0)
472 return 0;
473
474 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
475}
476
Johan Hedberg7d785252011-12-15 00:47:39 +0200477static void service_cache_off(struct work_struct *work)
478{
479 struct hci_dev *hdev = container_of(work, struct hci_dev,
480 service_cache.work);
481
482 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags))
483 return;
484
485 hci_dev_lock(hdev);
486
487 update_eir(hdev);
488 update_class(hdev);
489
490 hci_dev_unlock(hdev);
491}
492
493static void mgmt_init_hdev(struct hci_dev *hdev)
494{
495 if (!test_and_set_bit(HCI_MGMT, &hdev->flags))
496 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
497
498 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->flags))
499 schedule_delayed_work(&hdev->service_cache,
500 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
501}
502
Szymon Janc4e51eae2011-02-25 19:05:48 +0100503static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200504{
Johan Hedberga38528f2011-01-22 06:46:43 +0200505 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200506 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200507
Szymon Janc4e51eae2011-02-25 19:05:48 +0100508 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200509
Szymon Janc4e51eae2011-02-25 19:05:48 +0100510 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200511 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200512 return cmd_status(sk, index, MGMT_OP_READ_INFO,
513 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200514
Johan Hedberg32435532011-11-07 22:16:04 +0200515 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
516 cancel_delayed_work_sync(&hdev->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200517
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300518 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200519
Johan Hedberg7d785252011-12-15 00:47:39 +0200520 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
521 mgmt_init_hdev(hdev);
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200522
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200523 memset(&rp, 0, sizeof(rp));
524
Johan Hedberga38528f2011-01-22 06:46:43 +0200525 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200526
527 rp.version = hdev->hci_ver;
528
Johan Hedberga38528f2011-01-22 06:46:43 +0200529 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200530
531 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
532 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
533
534 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200535
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200536 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
537
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300538 hci_dev_unlock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200539 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200540
Szymon Janc4e51eae2011-02-25 19:05:48 +0100541 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200542}
543
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200544static void mgmt_pending_free(struct pending_cmd *cmd)
545{
546 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100547 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200548 kfree(cmd);
549}
550
Johan Hedberg366a0332011-02-19 12:05:55 -0300551static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200552 struct hci_dev *hdev,
553 void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200554{
555 struct pending_cmd *cmd;
556
557 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
558 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300559 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200560
561 cmd->opcode = opcode;
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200562 cmd->index = hdev->id;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200563
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100564 cmd->param = kmalloc(len, GFP_ATOMIC);
565 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200566 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300567 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200568 }
569
Szymon Janc8fce6352011-03-22 13:12:20 +0100570 if (data)
571 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200572
573 cmd->sk = sk;
574 sock_hold(sk);
575
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200576 list_add(&cmd->list, &hdev->mgmt_pending);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200577
Johan Hedberg366a0332011-02-19 12:05:55 -0300578 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200579}
580
Johan Hedberg744cf192011-11-08 20:40:14 +0200581static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200582 void (*cb)(struct pending_cmd *cmd, void *data),
583 void *data)
584{
585 struct list_head *p, *n;
586
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200587 list_for_each_safe(p, n, &hdev->mgmt_pending) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200588 struct pending_cmd *cmd;
589
590 cmd = list_entry(p, struct pending_cmd, list);
591
Johan Hedbergb24752f2011-11-03 14:40:33 +0200592 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200593 continue;
594
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200595 cb(cmd, data);
596 }
597}
598
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200599static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200600{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200601 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200602
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200603 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberg2aeabcb2011-11-09 13:58:57 +0200604 if (cmd->opcode == opcode)
605 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200606 }
607
608 return NULL;
609}
610
Johan Hedberga664b5b2011-02-19 12:06:02 -0300611static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200612{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200613 list_del(&cmd->list);
614 mgmt_pending_free(cmd);
615}
616
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200617static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200618{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200619 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200620
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200621 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200622}
623
Szymon Janc4e51eae2011-02-25 19:05:48 +0100624static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200625{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200626 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200627 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300628 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300629 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200630
631 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200632
Szymon Janc4e51eae2011-02-25 19:05:48 +0100633 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200634
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100635 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200636 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
637 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100638
Szymon Janc4e51eae2011-02-25 19:05:48 +0100639 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200640 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200641 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
642 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200643
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300644 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200645
646 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200647 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200648 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200649 goto failed;
650 }
651
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200652 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200653 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
654 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200655 goto failed;
656 }
657
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200658 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300659 if (!cmd) {
660 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200661 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300662 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200663
Johan Hedberg72a734e2010-12-30 00:38:22 +0200664 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200665 schedule_work(&hdev->power_on);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200666 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200667 schedule_work(&hdev->power_off.work);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200668
Johan Hedberg366a0332011-02-19 12:05:55 -0300669 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200670
671failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300672 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200673 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300674 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200675}
676
Szymon Janc4e51eae2011-02-25 19:05:48 +0100677static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
678 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200679{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200680 struct mgmt_cp_set_discoverable *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200681 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300682 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200683 u8 scan;
684 int err;
685
686 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200687
Szymon Janc4e51eae2011-02-25 19:05:48 +0100688 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200689
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100690 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200691 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
692 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100693
Szymon Janc4e51eae2011-02-25 19:05:48 +0100694 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200695 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200696 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
697 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200698
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300699 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200700
701 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200702 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
703 MGMT_STATUS_NOT_POWERED);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200704 goto failed;
705 }
706
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200707 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
708 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200709 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
710 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200711 goto failed;
712 }
713
Johan Hedberg72a734e2010-12-30 00:38:22 +0200714 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200715 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200716 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200717 goto failed;
718 }
719
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200720 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300721 if (!cmd) {
722 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200723 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300724 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200725
726 scan = SCAN_PAGE;
727
Johan Hedberg72a734e2010-12-30 00:38:22 +0200728 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200729 scan |= SCAN_INQUIRY;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200730 else
Johan Hedberge0f93092011-11-09 01:44:22 +0200731 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200732
733 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
734 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300735 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200736
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200737 if (cp->val)
738 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
739
Johan Hedberg73f22f62010-12-29 16:00:25 +0200740failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300741 hci_dev_unlock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200742 hci_dev_put(hdev);
743
744 return err;
745}
746
Szymon Janc4e51eae2011-02-25 19:05:48 +0100747static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
748 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200749{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200750 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200751 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300752 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200753 u8 scan;
754 int err;
755
756 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200757
Szymon Janc4e51eae2011-02-25 19:05:48 +0100758 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200759
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100760 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200761 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
762 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100763
Szymon Janc4e51eae2011-02-25 19:05:48 +0100764 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200765 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200766 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
767 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200768
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300769 hci_dev_lock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200770
771 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200772 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
773 MGMT_STATUS_NOT_POWERED);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200774 goto failed;
775 }
776
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200777 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
778 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200779 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
780 MGMT_STATUS_BUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200781 goto failed;
782 }
783
Johan Hedberg72a734e2010-12-30 00:38:22 +0200784 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200785 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200786 goto failed;
787 }
788
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200789 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300790 if (!cmd) {
791 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200792 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300793 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200794
Johan Hedberg72a734e2010-12-30 00:38:22 +0200795 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200796 scan = SCAN_PAGE;
797 else
798 scan = 0;
799
800 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
801 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300802 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200803
804failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300805 hci_dev_unlock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200806 hci_dev_put(hdev);
807
808 return err;
809}
810
Johan Hedberg744cf192011-11-08 20:40:14 +0200811static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
812 u16 data_len, struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200813{
814 struct sk_buff *skb;
815 struct mgmt_hdr *hdr;
816
817 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
818 if (!skb)
819 return -ENOMEM;
820
821 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
822
823 hdr = (void *) skb_put(skb, sizeof(*hdr));
824 hdr->opcode = cpu_to_le16(event);
Johan Hedberg744cf192011-11-08 20:40:14 +0200825 if (hdev)
826 hdr->index = cpu_to_le16(hdev->id);
827 else
828 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergc542a062011-01-26 13:11:03 +0200829 hdr->len = cpu_to_le16(data_len);
830
Szymon Janc4e51eae2011-02-25 19:05:48 +0100831 if (data)
832 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200833
834 hci_send_to_sock(NULL, skb, skip_sk);
835 kfree_skb(skb);
836
837 return 0;
838}
839
Szymon Janc4e51eae2011-02-25 19:05:48 +0100840static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
841 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200842{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200843 struct mgmt_mode *cp;
Johan Hedbergc542a062011-01-26 13:11:03 +0200844 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200845 __le32 ev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200846 int err;
847
848 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200849
Szymon Janc4e51eae2011-02-25 19:05:48 +0100850 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200851
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100852 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200853 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
854 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100855
Szymon Janc4e51eae2011-02-25 19:05:48 +0100856 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200857 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200858 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
859 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergc542a062011-01-26 13:11:03 +0200860
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300861 hci_dev_lock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200862
863 if (cp->val)
864 set_bit(HCI_PAIRABLE, &hdev->flags);
865 else
866 clear_bit(HCI_PAIRABLE, &hdev->flags);
867
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200868 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200869 if (err < 0)
870 goto failed;
871
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200872 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergc542a062011-01-26 13:11:03 +0200873
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200874 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200875
876failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300877 hci_dev_unlock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200878 hci_dev_put(hdev);
879
880 return err;
881}
882
Szymon Janc4e51eae2011-02-25 19:05:48 +0100883static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200884{
885 struct mgmt_cp_add_uuid *cp;
886 struct hci_dev *hdev;
887 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200888 int err;
889
890 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200891
Szymon Janc4e51eae2011-02-25 19:05:48 +0100892 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200893
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100894 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200895 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
896 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100897
Szymon Janc4e51eae2011-02-25 19:05:48 +0100898 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200899 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200900 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
901 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200902
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300903 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200904
905 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
906 if (!uuid) {
907 err = -ENOMEM;
908 goto failed;
909 }
910
911 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200912 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200913
914 list_add(&uuid->list, &hdev->uuids);
915
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200916 err = update_class(hdev);
917 if (err < 0)
918 goto failed;
919
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300920 err = update_eir(hdev);
921 if (err < 0)
922 goto failed;
923
Szymon Janc4e51eae2011-02-25 19:05:48 +0100924 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200925
926failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300927 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200928 hci_dev_put(hdev);
929
930 return err;
931}
932
Szymon Janc4e51eae2011-02-25 19:05:48 +0100933static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200934{
935 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100936 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200937 struct hci_dev *hdev;
938 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 +0200939 int err, found;
940
941 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200942
Szymon Janc4e51eae2011-02-25 19:05:48 +0100943 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200944
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100945 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200946 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
947 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100948
Szymon Janc4e51eae2011-02-25 19:05:48 +0100949 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200950 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200951 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
952 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200953
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300954 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200955
956 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
957 err = hci_uuids_clear(hdev);
958 goto unlock;
959 }
960
961 found = 0;
962
963 list_for_each_safe(p, n, &hdev->uuids) {
964 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
965
966 if (memcmp(match->uuid, cp->uuid, 16) != 0)
967 continue;
968
969 list_del(&match->list);
970 found++;
971 }
972
973 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200974 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
975 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200976 goto unlock;
977 }
978
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200979 err = update_class(hdev);
980 if (err < 0)
981 goto unlock;
982
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300983 err = update_eir(hdev);
984 if (err < 0)
985 goto unlock;
986
Szymon Janc4e51eae2011-02-25 19:05:48 +0100987 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200988
989unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300990 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200991 hci_dev_put(hdev);
992
993 return err;
994}
995
Szymon Janc4e51eae2011-02-25 19:05:48 +0100996static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
997 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200998{
999 struct hci_dev *hdev;
1000 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001001 int err;
1002
1003 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001004
Szymon Janc4e51eae2011-02-25 19:05:48 +01001005 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001006
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001007 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001008 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1009 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001010
Szymon Janc4e51eae2011-02-25 19:05:48 +01001011 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001012 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001013 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1014 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001015
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001016 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001017
1018 hdev->major_class = cp->major;
1019 hdev->minor_class = cp->minor;
1020
Johan Hedberg7d785252011-12-15 00:47:39 +02001021 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags)) {
1022 hci_dev_unlock(hdev);
1023 cancel_delayed_work_sync(&hdev->service_cache);
1024 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001025 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001026 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001027
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001028 err = update_class(hdev);
1029
1030 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001031 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001032
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001033 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001034 hci_dev_put(hdev);
1035
1036 return err;
1037}
1038
Johan Hedberg86742e12011-11-07 23:13:38 +02001039static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
1040 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001041{
1042 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001043 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001044 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001045 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001046
1047 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001048
1049 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001050 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1051 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001052
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001053 key_count = get_unaligned_le16(&cp->key_count);
1054
Johan Hedberg86742e12011-11-07 23:13:38 +02001055 expected_len = sizeof(*cp) + key_count *
1056 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001057 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001058 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001059 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001060 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1061 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001062 }
1063
Szymon Janc4e51eae2011-02-25 19:05:48 +01001064 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001065 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001066 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1067 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001068
Szymon Janc4e51eae2011-02-25 19:05:48 +01001069 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001070 key_count);
1071
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001072 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001073
1074 hci_link_keys_clear(hdev);
1075
1076 set_bit(HCI_LINK_KEYS, &hdev->flags);
1077
1078 if (cp->debug_keys)
1079 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1080 else
1081 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1082
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001083 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001084 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001085
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001086 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001087 key->pin_len);
1088 }
1089
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001090 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1091
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001092 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001093 hci_dev_put(hdev);
1094
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001095 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001096}
1097
Johan Hedberg86742e12011-11-07 23:13:38 +02001098static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
1099 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001100{
1101 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001102 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001103 struct mgmt_rp_remove_keys rp;
1104 struct hci_cp_disconnect dc;
1105 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001106 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001107 int err;
1108
1109 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001110
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001111 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001112 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1113 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001114
Szymon Janc4e51eae2011-02-25 19:05:48 +01001115 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001116 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001117 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1118 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001119
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001120 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001121
Johan Hedberga8a1d192011-11-10 15:54:38 +02001122 memset(&rp, 0, sizeof(rp));
1123 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001124 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001125
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001126 err = hci_remove_link_key(hdev, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001127 if (err < 0) {
1128 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001129 goto unlock;
Johan Hedbergca69b792011-11-11 18:10:00 +02001130 }
Johan Hedberga8a1d192011-11-10 15:54:38 +02001131
1132 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1133 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1134 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001135 goto unlock;
1136 }
1137
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001138 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001139 if (!conn) {
1140 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1141 sizeof(rp));
1142 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001143 }
1144
Johan Hedberga8a1d192011-11-10 15:54:38 +02001145 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1146 if (!cmd) {
1147 err = -ENOMEM;
1148 goto unlock;
1149 }
1150
1151 put_unaligned_le16(conn->handle, &dc.handle);
1152 dc.reason = 0x13; /* Remote User Terminated Connection */
1153 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1154 if (err < 0)
1155 mgmt_pending_remove(cmd);
1156
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001157unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001158 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001159 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1160 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001161 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001162 hci_dev_put(hdev);
1163
1164 return err;
1165}
1166
Szymon Janc4e51eae2011-02-25 19:05:48 +01001167static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001168{
1169 struct hci_dev *hdev;
1170 struct mgmt_cp_disconnect *cp;
1171 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001172 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001173 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001174 int err;
1175
1176 BT_DBG("");
1177
1178 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001179
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001180 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001181 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1182 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001183
Szymon Janc4e51eae2011-02-25 19:05:48 +01001184 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001185 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001186 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1187 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001188
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001189 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001190
1191 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001192 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1193 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001194 goto failed;
1195 }
1196
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001197 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001198 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1199 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001200 goto failed;
1201 }
1202
1203 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001204 if (!conn)
1205 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1206
Johan Hedberg8962ee72011-01-20 12:40:27 +02001207 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001208 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1209 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001210 goto failed;
1211 }
1212
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001213 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001214 if (!cmd) {
1215 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001216 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001217 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001218
1219 put_unaligned_le16(conn->handle, &dc.handle);
1220 dc.reason = 0x13; /* Remote User Terminated Connection */
1221
1222 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1223 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001224 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001225
1226failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001227 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001228 hci_dev_put(hdev);
1229
1230 return err;
1231}
1232
Johan Hedberg48264f02011-11-09 13:58:58 +02001233static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001234{
1235 switch (link_type) {
1236 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001237 switch (addr_type) {
1238 case ADDR_LE_DEV_PUBLIC:
1239 return MGMT_ADDR_LE_PUBLIC;
1240 case ADDR_LE_DEV_RANDOM:
1241 return MGMT_ADDR_LE_RANDOM;
1242 default:
1243 return MGMT_ADDR_INVALID;
1244 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001245 case ACL_LINK:
1246 return MGMT_ADDR_BREDR;
1247 default:
1248 return MGMT_ADDR_INVALID;
1249 }
1250}
1251
Szymon Janc8ce62842011-03-01 16:55:32 +01001252static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001253{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001254 struct mgmt_rp_get_connections *rp;
1255 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001256 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001257 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001258 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001259 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001260 int i, err;
1261
1262 BT_DBG("");
1263
Szymon Janc4e51eae2011-02-25 19:05:48 +01001264 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001265 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001266 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1267 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001268
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001269 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001270
1271 count = 0;
1272 list_for_each(p, &hdev->conn_hash.list) {
1273 count++;
1274 }
1275
Johan Hedberg4c659c32011-11-07 23:13:39 +02001276 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001277 rp = kmalloc(rp_len, GFP_ATOMIC);
1278 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001279 err = -ENOMEM;
1280 goto unlock;
1281 }
1282
Johan Hedberg2784eb42011-01-21 13:56:35 +02001283 put_unaligned_le16(count, &rp->conn_count);
1284
Johan Hedberg2784eb42011-01-21 13:56:35 +02001285 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001286 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1287 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001288 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001289 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1290 continue;
1291 i++;
1292 }
1293
1294 /* Recalculate length in case of filtered SCO connections, etc */
1295 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001296
Szymon Janc4e51eae2011-02-25 19:05:48 +01001297 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001298
1299unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001300 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001301 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001302 hci_dev_put(hdev);
1303 return err;
1304}
1305
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001306static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1307 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1308{
1309 struct pending_cmd *cmd;
1310 int err;
1311
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001312 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001313 sizeof(*cp));
1314 if (!cmd)
1315 return -ENOMEM;
1316
1317 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1318 &cp->bdaddr);
1319 if (err < 0)
1320 mgmt_pending_remove(cmd);
1321
1322 return err;
1323}
1324
Szymon Janc4e51eae2011-02-25 19:05:48 +01001325static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1326 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001327{
1328 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001329 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001330 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001331 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001332 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001333 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001334 int err;
1335
1336 BT_DBG("");
1337
1338 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001339
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001340 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001341 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1342 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001343
Szymon Janc4e51eae2011-02-25 19:05:48 +01001344 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001345 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001346 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1347 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001348
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001349 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001350
1351 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001352 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1353 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001354 goto failed;
1355 }
1356
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001357 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1358 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001359 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1360 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001361 goto failed;
1362 }
1363
1364 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1365 bacpy(&ncp.bdaddr, &cp->bdaddr);
1366
1367 BT_ERR("PIN code is not 16 bytes long");
1368
1369 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1370 if (err >= 0)
1371 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001372 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001373
1374 goto failed;
1375 }
1376
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001377 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001378 if (!cmd) {
1379 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001380 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001381 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001382
1383 bacpy(&reply.bdaddr, &cp->bdaddr);
1384 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001385 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001386
1387 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1388 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001389 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001390
1391failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001392 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001393 hci_dev_put(hdev);
1394
1395 return err;
1396}
1397
Szymon Janc4e51eae2011-02-25 19:05:48 +01001398static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1399 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001400{
1401 struct hci_dev *hdev;
1402 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001403 int err;
1404
1405 BT_DBG("");
1406
1407 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001408
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001409 if (len != sizeof(*cp))
1410 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001411 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001412
Szymon Janc4e51eae2011-02-25 19:05:48 +01001413 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001414 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001415 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001416 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001417
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001418 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001419
1420 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001421 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001422 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001423 goto failed;
1424 }
1425
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001426 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001427
1428failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001429 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001430 hci_dev_put(hdev);
1431
1432 return err;
1433}
1434
Szymon Janc4e51eae2011-02-25 19:05:48 +01001435static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1436 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001437{
1438 struct hci_dev *hdev;
1439 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001440
1441 BT_DBG("");
1442
1443 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001444
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001445 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001446 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1447 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001448
Szymon Janc4e51eae2011-02-25 19:05:48 +01001449 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001450 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001451 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1452 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001453
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001454 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001455
1456 hdev->io_capability = cp->io_capability;
1457
1458 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001459 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001460
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001461 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001462 hci_dev_put(hdev);
1463
Szymon Janc4e51eae2011-02-25 19:05:48 +01001464 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001465}
1466
Johan Hedberge9a416b2011-02-19 12:05:56 -03001467static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1468{
1469 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001470 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001471
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001472 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001473 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1474 continue;
1475
Johan Hedberge9a416b2011-02-19 12:05:56 -03001476 if (cmd->user_data != conn)
1477 continue;
1478
1479 return cmd;
1480 }
1481
1482 return NULL;
1483}
1484
1485static void pairing_complete(struct pending_cmd *cmd, u8 status)
1486{
1487 struct mgmt_rp_pair_device rp;
1488 struct hci_conn *conn = cmd->user_data;
1489
Johan Hedbergba4e5642011-11-11 00:07:34 +02001490 bacpy(&rp.addr.bdaddr, &conn->dst);
1491 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001492 rp.status = status;
1493
Szymon Janc4e51eae2011-02-25 19:05:48 +01001494 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001495
1496 /* So we don't get further callbacks for this connection */
1497 conn->connect_cfm_cb = NULL;
1498 conn->security_cfm_cb = NULL;
1499 conn->disconn_cfm_cb = NULL;
1500
1501 hci_conn_put(conn);
1502
Johan Hedberga664b5b2011-02-19 12:06:02 -03001503 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001504}
1505
1506static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1507{
1508 struct pending_cmd *cmd;
1509
1510 BT_DBG("status %u", status);
1511
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001512 cmd = find_pairing(conn);
1513 if (!cmd)
1514 BT_DBG("Unable to find a pending command");
1515 else
1516 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001517}
1518
Szymon Janc4e51eae2011-02-25 19:05:48 +01001519static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001520{
1521 struct hci_dev *hdev;
1522 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001523 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001524 struct pending_cmd *cmd;
1525 u8 sec_level, auth_type;
1526 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001527 int err;
1528
1529 BT_DBG("");
1530
1531 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001532
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001533 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001534 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1535 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001536
Szymon Janc4e51eae2011-02-25 19:05:48 +01001537 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001538 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001539 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1540 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001541
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001542 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001543
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001544 sec_level = BT_SECURITY_MEDIUM;
1545 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001546 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001547 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001548 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001549
Johan Hedbergba4e5642011-11-11 00:07:34 +02001550 if (cp->addr.type == MGMT_ADDR_BREDR)
1551 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001552 auth_type);
1553 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001554 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001555 auth_type);
1556
Johan Hedberg1425acb2011-11-11 00:07:35 +02001557 memset(&rp, 0, sizeof(rp));
1558 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1559 rp.addr.type = cp->addr.type;
1560
Ville Tervo30e76272011-02-22 16:10:53 -03001561 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001562 rp.status = -PTR_ERR(conn);
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
1568 if (conn->connect_cfm_cb) {
1569 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001570 rp.status = EBUSY;
1571 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1572 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001573 goto unlock;
1574 }
1575
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001576 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001577 if (!cmd) {
1578 err = -ENOMEM;
1579 hci_conn_put(conn);
1580 goto unlock;
1581 }
1582
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001583 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001584 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001585 conn->connect_cfm_cb = pairing_complete_cb;
1586
Johan Hedberge9a416b2011-02-19 12:05:56 -03001587 conn->security_cfm_cb = pairing_complete_cb;
1588 conn->disconn_cfm_cb = pairing_complete_cb;
1589 conn->io_capability = cp->io_cap;
1590 cmd->user_data = conn;
1591
1592 if (conn->state == BT_CONNECTED &&
1593 hci_conn_security(conn, sec_level, auth_type))
1594 pairing_complete(cmd, 0);
1595
1596 err = 0;
1597
1598unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001599 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001600 hci_dev_put(hdev);
1601
1602 return err;
1603}
1604
Brian Gix0df4c182011-11-16 13:53:13 -08001605static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1606 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001607{
Johan Hedberga5c29682011-02-19 12:05:57 -03001608 struct pending_cmd *cmd;
1609 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001610 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001611 int err;
1612
Szymon Janc4e51eae2011-02-25 19:05:48 +01001613 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001614 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001615 return cmd_status(sk, index, mgmt_op,
1616 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001617
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001618 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001619
Johan Hedberga5c29682011-02-19 12:05:57 -03001620 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001621 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1622 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001623 }
1624
Brian Gix47c15e22011-11-16 13:53:14 -08001625 /*
1626 * Check for an existing ACL link, if present pair via
1627 * HCI commands.
1628 *
1629 * If no ACL link is present, check for an LE link and if
1630 * present, pair via the SMP engine.
1631 *
1632 * If neither ACL nor LE links are present, fail with error.
1633 */
1634 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1635 if (!conn) {
1636 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1637 if (!conn) {
1638 err = cmd_status(sk, index, mgmt_op,
1639 MGMT_STATUS_NOT_CONNECTED);
1640 goto done;
1641 }
1642
1643 /* Continue with pairing via SMP */
1644
1645 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_SUCCESS);
1646 goto done;
1647 }
1648
Brian Gix0df4c182011-11-16 13:53:13 -08001649 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001650 if (!cmd) {
1651 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001652 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001653 }
1654
Brian Gix0df4c182011-11-16 13:53:13 -08001655 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001656 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1657 struct hci_cp_user_passkey_reply cp;
1658
1659 bacpy(&cp.bdaddr, bdaddr);
1660 cp.passkey = passkey;
1661 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1662 } else
1663 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1664
Johan Hedberga664b5b2011-02-19 12:06:02 -03001665 if (err < 0)
1666 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001667
Brian Gix0df4c182011-11-16 13:53:13 -08001668done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001669 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001670 hci_dev_put(hdev);
1671
1672 return err;
1673}
1674
Brian Gix0df4c182011-11-16 13:53:13 -08001675static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1676{
1677 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1678
1679 BT_DBG("");
1680
1681 if (len != sizeof(*cp))
1682 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1683 MGMT_STATUS_INVALID_PARAMS);
1684
1685 return user_pairing_resp(sk, index, &cp->bdaddr,
1686 MGMT_OP_USER_CONFIRM_REPLY,
1687 HCI_OP_USER_CONFIRM_REPLY, 0);
1688}
1689
1690static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1691 u16 len)
1692{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001693 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001694
1695 BT_DBG("");
1696
1697 if (len != sizeof(*cp))
1698 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1699 MGMT_STATUS_INVALID_PARAMS);
1700
1701 return user_pairing_resp(sk, index, &cp->bdaddr,
1702 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1703 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1704}
1705
Brian Gix604086b2011-11-23 08:28:33 -08001706static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1707{
1708 struct mgmt_cp_user_passkey_reply *cp = (void *) data;
1709
1710 BT_DBG("");
1711
1712 if (len != sizeof(*cp))
1713 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1714 EINVAL);
1715
1716 return user_pairing_resp(sk, index, &cp->bdaddr,
1717 MGMT_OP_USER_PASSKEY_REPLY,
1718 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1719}
1720
1721static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1722 u16 len)
1723{
1724 struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data;
1725
1726 BT_DBG("");
1727
1728 if (len != sizeof(*cp))
1729 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1730 EINVAL);
1731
1732 return user_pairing_resp(sk, index, &cp->bdaddr,
1733 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1734 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1735}
1736
Johan Hedbergb312b1612011-03-16 14:29:37 +02001737static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1738 u16 len)
1739{
1740 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1741 struct hci_cp_write_local_name hci_cp;
1742 struct hci_dev *hdev;
1743 struct pending_cmd *cmd;
1744 int err;
1745
1746 BT_DBG("");
1747
1748 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001749 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1750 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001751
1752 hdev = hci_dev_get(index);
1753 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001754 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1755 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001756
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001757 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001758
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001759 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001760 if (!cmd) {
1761 err = -ENOMEM;
1762 goto failed;
1763 }
1764
1765 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1766 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1767 &hci_cp);
1768 if (err < 0)
1769 mgmt_pending_remove(cmd);
1770
1771failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001772 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001773 hci_dev_put(hdev);
1774
1775 return err;
1776}
1777
Szymon Jancc35938b2011-03-22 13:12:21 +01001778static int read_local_oob_data(struct sock *sk, u16 index)
1779{
1780 struct hci_dev *hdev;
1781 struct pending_cmd *cmd;
1782 int err;
1783
1784 BT_DBG("hci%u", index);
1785
1786 hdev = hci_dev_get(index);
1787 if (!hdev)
1788 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001789 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001790
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001791 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001792
1793 if (!test_bit(HCI_UP, &hdev->flags)) {
1794 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001795 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001796 goto unlock;
1797 }
1798
1799 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1800 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001801 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001802 goto unlock;
1803 }
1804
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001805 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001806 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1807 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001808 goto unlock;
1809 }
1810
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001811 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001812 if (!cmd) {
1813 err = -ENOMEM;
1814 goto unlock;
1815 }
1816
1817 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1818 if (err < 0)
1819 mgmt_pending_remove(cmd);
1820
1821unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001822 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001823 hci_dev_put(hdev);
1824
1825 return err;
1826}
1827
Szymon Janc2763eda2011-03-22 13:12:22 +01001828static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1829 u16 len)
1830{
1831 struct hci_dev *hdev;
1832 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1833 int err;
1834
1835 BT_DBG("hci%u ", index);
1836
1837 if (len != sizeof(*cp))
1838 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001839 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001840
1841 hdev = hci_dev_get(index);
1842 if (!hdev)
1843 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001844 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001845
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001846 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001847
1848 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1849 cp->randomizer);
1850 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001851 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1852 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001853 else
1854 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1855 0);
1856
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001857 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001858 hci_dev_put(hdev);
1859
1860 return err;
1861}
1862
1863static int remove_remote_oob_data(struct sock *sk, u16 index,
1864 unsigned char *data, u16 len)
1865{
1866 struct hci_dev *hdev;
1867 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1868 int err;
1869
1870 BT_DBG("hci%u ", index);
1871
1872 if (len != sizeof(*cp))
1873 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001874 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001875
1876 hdev = hci_dev_get(index);
1877 if (!hdev)
1878 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001879 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001880
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001881 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001882
1883 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1884 if (err < 0)
1885 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001886 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001887 else
1888 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1889 NULL, 0);
1890
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001891 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001892 hci_dev_put(hdev);
1893
1894 return err;
1895}
1896
Johan Hedberg450dfda2011-11-12 11:58:22 +02001897static int start_discovery(struct sock *sk, u16 index,
1898 unsigned char *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001899{
Johan Hedberg450dfda2011-11-12 11:58:22 +02001900 struct mgmt_cp_start_discovery *cp = (void *) data;
Johan Hedberg14a53662011-04-27 10:29:56 -04001901 struct pending_cmd *cmd;
1902 struct hci_dev *hdev;
1903 int err;
1904
1905 BT_DBG("hci%u", index);
1906
Johan Hedberg450dfda2011-11-12 11:58:22 +02001907 if (len != sizeof(*cp))
1908 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1909 MGMT_STATUS_INVALID_PARAMS);
1910
Johan Hedberg14a53662011-04-27 10:29:56 -04001911 hdev = hci_dev_get(index);
1912 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001913 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1914 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001915
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001916 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001917
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001918 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001919 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1920 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001921 goto failed;
1922 }
1923
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001924 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001925 if (!cmd) {
1926 err = -ENOMEM;
1927 goto failed;
1928 }
1929
Andre Guedes2519a1f2011-11-07 11:45:24 -03001930 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001931 if (err < 0)
1932 mgmt_pending_remove(cmd);
1933
1934failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001935 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001936 hci_dev_put(hdev);
1937
1938 return err;
1939}
1940
1941static int stop_discovery(struct sock *sk, u16 index)
1942{
1943 struct hci_dev *hdev;
1944 struct pending_cmd *cmd;
1945 int err;
1946
1947 BT_DBG("hci%u", index);
1948
1949 hdev = hci_dev_get(index);
1950 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001951 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1952 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001953
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001954 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001955
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001956 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001957 if (!cmd) {
1958 err = -ENOMEM;
1959 goto failed;
1960 }
1961
Andre Guedes023d50492011-11-04 14:16:52 -03001962 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001963 if (err < 0)
1964 mgmt_pending_remove(cmd);
1965
1966failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001967 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001968 hci_dev_put(hdev);
1969
1970 return err;
1971}
1972
Antti Julku7fbec222011-06-15 12:01:15 +03001973static int block_device(struct sock *sk, u16 index, unsigned char *data,
1974 u16 len)
1975{
1976 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001977 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001978 int err;
1979
1980 BT_DBG("hci%u", index);
1981
Antti Julku7fbec222011-06-15 12:01:15 +03001982 if (len != sizeof(*cp))
1983 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001984 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001985
1986 hdev = hci_dev_get(index);
1987 if (!hdev)
1988 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001989 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001990
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001991 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03001992
Antti Julku7fbec222011-06-15 12:01:15 +03001993 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001994 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001995 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1996 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03001997 else
1998 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1999 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002000
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002001 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002002 hci_dev_put(hdev);
2003
2004 return err;
2005}
2006
2007static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
2008 u16 len)
2009{
2010 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03002011 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03002012 int err;
2013
2014 BT_DBG("hci%u", index);
2015
Antti Julku7fbec222011-06-15 12:01:15 +03002016 if (len != sizeof(*cp))
2017 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002018 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002019
2020 hdev = hci_dev_get(index);
2021 if (!hdev)
2022 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002023 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002024
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002025 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002026
Antti Julku7fbec222011-06-15 12:01:15 +03002027 err = hci_blacklist_del(hdev, &cp->bdaddr);
2028
2029 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002030 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2031 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002032 else
2033 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2034 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002035
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002036 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002037 hci_dev_put(hdev);
2038
2039 return err;
2040}
2041
Antti Julkuf6422ec2011-06-22 13:11:56 +03002042static int set_fast_connectable(struct sock *sk, u16 index,
2043 unsigned char *data, u16 len)
2044{
2045 struct hci_dev *hdev;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002046 struct mgmt_mode *cp = (void *) data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002047 struct hci_cp_write_page_scan_activity acp;
2048 u8 type;
2049 int err;
2050
2051 BT_DBG("hci%u", index);
2052
2053 if (len != sizeof(*cp))
2054 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002055 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002056
2057 hdev = hci_dev_get(index);
2058 if (!hdev)
2059 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002060 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002061
2062 hci_dev_lock(hdev);
2063
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002064 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002065 type = PAGE_SCAN_TYPE_INTERLACED;
2066 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2067 } else {
2068 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2069 acp.interval = 0x0800; /* default 1.28 sec page scan */
2070 }
2071
2072 acp.window = 0x0012; /* default 11.25 msec page scan window */
2073
2074 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2075 sizeof(acp), &acp);
2076 if (err < 0) {
2077 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002078 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002079 goto done;
2080 }
2081
2082 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2083 if (err < 0) {
2084 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002085 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002086 goto done;
2087 }
2088
2089 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2090 NULL, 0);
2091done:
2092 hci_dev_unlock(hdev);
2093 hci_dev_put(hdev);
2094
2095 return err;
2096}
2097
Johan Hedberg03811012010-12-08 00:21:06 +02002098int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2099{
2100 unsigned char *buf;
2101 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002102 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002103 int err;
2104
2105 BT_DBG("got %zu bytes", msglen);
2106
2107 if (msglen < sizeof(*hdr))
2108 return -EINVAL;
2109
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002110 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002111 if (!buf)
2112 return -ENOMEM;
2113
2114 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2115 err = -EFAULT;
2116 goto done;
2117 }
2118
2119 hdr = (struct mgmt_hdr *) buf;
2120 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002121 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002122 len = get_unaligned_le16(&hdr->len);
2123
2124 if (len != msglen - sizeof(*hdr)) {
2125 err = -EINVAL;
2126 goto done;
2127 }
2128
2129 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002130 case MGMT_OP_READ_VERSION:
2131 err = read_version(sk);
2132 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002133 case MGMT_OP_READ_INDEX_LIST:
2134 err = read_index_list(sk);
2135 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002136 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002137 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002138 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002139 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002140 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002141 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002142 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002143 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002144 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002145 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002146 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002147 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002148 case MGMT_OP_SET_FAST_CONNECTABLE:
2149 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
2150 len);
2151 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002152 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002153 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002154 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002155 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002156 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002157 break;
2158 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002159 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002160 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002161 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002162 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002163 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002164 case MGMT_OP_LOAD_LINK_KEYS:
2165 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002166 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002167 case MGMT_OP_REMOVE_KEYS:
2168 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002169 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002170 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002171 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002172 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002173 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002174 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002175 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002176 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002177 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002178 break;
2179 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002180 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002181 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002182 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002183 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002184 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002185 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002186 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002187 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002188 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002189 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002190 break;
2191 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002192 err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr),
2193 len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002194 break;
Brian Gix604086b2011-11-23 08:28:33 -08002195 case MGMT_OP_USER_PASSKEY_REPLY:
2196 err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len);
2197 break;
2198 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
2199 err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr),
2200 len);
2201 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002202 case MGMT_OP_SET_LOCAL_NAME:
2203 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2204 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002205 case MGMT_OP_READ_LOCAL_OOB_DATA:
2206 err = read_local_oob_data(sk, index);
2207 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002208 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2209 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2210 break;
2211 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2212 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2213 len);
2214 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002215 case MGMT_OP_START_DISCOVERY:
Johan Hedberg450dfda2011-11-12 11:58:22 +02002216 err = start_discovery(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002217 break;
2218 case MGMT_OP_STOP_DISCOVERY:
2219 err = stop_discovery(sk, index);
2220 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002221 case MGMT_OP_BLOCK_DEVICE:
2222 err = block_device(sk, index, buf + sizeof(*hdr), len);
2223 break;
2224 case MGMT_OP_UNBLOCK_DEVICE:
2225 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
2226 break;
Johan Hedberg03811012010-12-08 00:21:06 +02002227 default:
2228 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002229 err = cmd_status(sk, index, opcode,
2230 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg03811012010-12-08 00:21:06 +02002231 break;
2232 }
2233
Johan Hedberge41d8b42010-12-13 21:07:03 +02002234 if (err < 0)
2235 goto done;
2236
Johan Hedberg03811012010-12-08 00:21:06 +02002237 err = msglen;
2238
2239done:
2240 kfree(buf);
2241 return err;
2242}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002243
Johan Hedbergb24752f2011-11-03 14:40:33 +02002244static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2245{
2246 u8 *status = data;
2247
2248 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2249 mgmt_pending_remove(cmd);
2250}
2251
Johan Hedberg744cf192011-11-08 20:40:14 +02002252int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002253{
Johan Hedberg744cf192011-11-08 20:40:14 +02002254 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002255}
2256
Johan Hedberg744cf192011-11-08 20:40:14 +02002257int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002258{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002259 u8 status = ENODEV;
2260
Johan Hedberg744cf192011-11-08 20:40:14 +02002261 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002262
Johan Hedberg744cf192011-11-08 20:40:14 +02002263 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002264}
2265
Johan Hedberg73f22f62010-12-29 16:00:25 +02002266struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002267 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002268 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002269 struct hci_dev *hdev;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002270};
2271
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002272static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002273{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002274 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002275
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002276 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002277
2278 list_del(&cmd->list);
2279
2280 if (match->sk == NULL) {
2281 match->sk = cmd->sk;
2282 sock_hold(match->sk);
2283 }
2284
2285 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002286}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002287
Johan Hedberg744cf192011-11-08 20:40:14 +02002288int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002289{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002290 struct cmd_lookup match = { powered, NULL, hdev };
2291 __le32 ev;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002292 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002293
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002294 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002295
Johan Hedbergb24752f2011-11-03 14:40:33 +02002296 if (!powered) {
2297 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002298 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002299 }
2300
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002301 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002302
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002303 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2304 match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002305
2306 if (match.sk)
2307 sock_put(match.sk);
2308
2309 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002310}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002311
Johan Hedberg744cf192011-11-08 20:40:14 +02002312int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002313{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002314 struct cmd_lookup match = { discoverable, NULL, hdev };
2315 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002316 int ret;
2317
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002318 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002319
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002320 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg73f22f62010-12-29 16:00:25 +02002321
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002322 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002323 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002324 if (match.sk)
2325 sock_put(match.sk);
2326
2327 return ret;
2328}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002329
Johan Hedberg744cf192011-11-08 20:40:14 +02002330int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002331{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002332 __le32 ev;
2333 struct cmd_lookup match = { connectable, NULL, hdev };
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002334 int ret;
2335
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002336 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2337 &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002338
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002339 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002340
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002341 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002342
2343 if (match.sk)
2344 sock_put(match.sk);
2345
2346 return ret;
2347}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002348
Johan Hedberg744cf192011-11-08 20:40:14 +02002349int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002350{
Johan Hedbergca69b792011-11-11 18:10:00 +02002351 u8 mgmt_err = mgmt_status(status);
2352
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002353 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002354 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002355 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002356
2357 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002358 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002359 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002360
2361 return 0;
2362}
2363
Johan Hedberg744cf192011-11-08 20:40:14 +02002364int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2365 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002366{
Johan Hedberg86742e12011-11-07 23:13:38 +02002367 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002368
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002369 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002370
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002371 ev.store_hint = persistent;
2372 bacpy(&ev.key.bdaddr, &key->bdaddr);
2373 ev.key.type = key->type;
2374 memcpy(ev.key.val, key->val, 16);
2375 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002376
Johan Hedberg744cf192011-11-08 20:40:14 +02002377 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002378}
Johan Hedbergf7520542011-01-20 12:34:39 +02002379
Johan Hedberg48264f02011-11-09 13:58:58 +02002380int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2381 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002382{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002383 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002384
Johan Hedbergf7520542011-01-20 12:34:39 +02002385 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002386 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002387
Johan Hedberg744cf192011-11-08 20:40:14 +02002388 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002389}
2390
Johan Hedberg8962ee72011-01-20 12:40:27 +02002391static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2392{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002393 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002394 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002395 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002396
Johan Hedberga38528f2011-01-22 06:46:43 +02002397 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002398 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002399
Szymon Janc4e51eae2011-02-25 19:05:48 +01002400 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002401
2402 *sk = cmd->sk;
2403 sock_hold(*sk);
2404
Johan Hedberga664b5b2011-02-19 12:06:02 -03002405 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002406}
2407
Johan Hedberga8a1d192011-11-10 15:54:38 +02002408static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2409{
2410 u8 *status = data;
2411 struct mgmt_cp_remove_keys *cp = cmd->param;
2412 struct mgmt_rp_remove_keys rp;
2413
2414 memset(&rp, 0, sizeof(rp));
2415 bacpy(&rp.bdaddr, &cp->bdaddr);
2416 if (status != NULL)
2417 rp.status = *status;
2418
2419 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2420 sizeof(rp));
2421
2422 mgmt_pending_remove(cmd);
2423}
2424
Johan Hedberg48264f02011-11-09 13:58:58 +02002425int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2426 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002427{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002428 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002429 struct sock *sk = NULL;
2430 int err;
2431
Johan Hedberg744cf192011-11-08 20:40:14 +02002432 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002433
Johan Hedbergf7520542011-01-20 12:34:39 +02002434 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002435 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002436
Johan Hedberg744cf192011-11-08 20:40:14 +02002437 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002438
2439 if (sk)
2440 sock_put(sk);
2441
Johan Hedberga8a1d192011-11-10 15:54:38 +02002442 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2443
Johan Hedberg8962ee72011-01-20 12:40:27 +02002444 return err;
2445}
2446
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002447int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002448{
2449 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002450 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002451 int err;
2452
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002453 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002454 if (!cmd)
2455 return -ENOENT;
2456
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002457 if (bdaddr) {
2458 struct mgmt_rp_disconnect rp;
2459
2460 bacpy(&rp.bdaddr, bdaddr);
2461 rp.status = status;
2462
2463 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2464 &rp, sizeof(rp));
2465 } else
2466 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002467 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002468
Johan Hedberga664b5b2011-02-19 12:06:02 -03002469 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002470
2471 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002472}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002473
Johan Hedberg48264f02011-11-09 13:58:58 +02002474int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2475 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002476{
2477 struct mgmt_ev_connect_failed ev;
2478
Johan Hedberg4c659c32011-11-07 23:13:39 +02002479 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002480 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002481 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002482
Johan Hedberg744cf192011-11-08 20:40:14 +02002483 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002484}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002485
Johan Hedberg744cf192011-11-08 20:40:14 +02002486int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002487{
2488 struct mgmt_ev_pin_code_request ev;
2489
Johan Hedberg980e1a52011-01-22 06:10:07 +02002490 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002491 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002492
Johan Hedberg744cf192011-11-08 20:40:14 +02002493 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002494 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002495}
2496
Johan Hedberg744cf192011-11-08 20:40:14 +02002497int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2498 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002499{
2500 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002501 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002502 int err;
2503
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002504 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002505 if (!cmd)
2506 return -ENOENT;
2507
Johan Hedbergac56fb12011-02-19 12:05:59 -03002508 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002509 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002510
Johan Hedberg744cf192011-11-08 20:40:14 +02002511 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002512 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002513
Johan Hedberga664b5b2011-02-19 12:06:02 -03002514 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002515
2516 return err;
2517}
2518
Johan Hedberg744cf192011-11-08 20:40:14 +02002519int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2520 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002521{
2522 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002523 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002524 int err;
2525
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002526 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002527 if (!cmd)
2528 return -ENOENT;
2529
Johan Hedbergac56fb12011-02-19 12:05:59 -03002530 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002531 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002532
Johan Hedberg744cf192011-11-08 20:40:14 +02002533 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002534 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002535
Johan Hedberga664b5b2011-02-19 12:06:02 -03002536 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002537
2538 return err;
2539}
Johan Hedberga5c29682011-02-19 12:05:57 -03002540
Johan Hedberg744cf192011-11-08 20:40:14 +02002541int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2542 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002543{
2544 struct mgmt_ev_user_confirm_request ev;
2545
Johan Hedberg744cf192011-11-08 20:40:14 +02002546 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002547
Johan Hedberga5c29682011-02-19 12:05:57 -03002548 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002549 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002550 put_unaligned_le32(value, &ev.value);
2551
Johan Hedberg744cf192011-11-08 20:40:14 +02002552 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002553 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002554}
2555
Brian Gix604086b2011-11-23 08:28:33 -08002556int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2557{
2558 struct mgmt_ev_user_passkey_request ev;
2559
2560 BT_DBG("%s", hdev->name);
2561
2562 bacpy(&ev.bdaddr, bdaddr);
2563
2564 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2565 NULL);
2566}
2567
Brian Gix0df4c182011-11-16 13:53:13 -08002568static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002569 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002570{
2571 struct pending_cmd *cmd;
2572 struct mgmt_rp_user_confirm_reply rp;
2573 int err;
2574
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002575 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002576 if (!cmd)
2577 return -ENOENT;
2578
Johan Hedberga5c29682011-02-19 12:05:57 -03002579 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002580 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002581 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002582
Johan Hedberga664b5b2011-02-19 12:06:02 -03002583 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002584
2585 return err;
2586}
2587
Johan Hedberg744cf192011-11-08 20:40:14 +02002588int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2589 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002590{
Brian Gix0df4c182011-11-16 13:53:13 -08002591 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002592 MGMT_OP_USER_CONFIRM_REPLY);
2593}
2594
Johan Hedberg744cf192011-11-08 20:40:14 +02002595int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2596 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002597{
Brian Gix0df4c182011-11-16 13:53:13 -08002598 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002599 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2600}
Johan Hedberg2a611692011-02-19 12:06:00 -03002601
Brian Gix604086b2011-11-23 08:28:33 -08002602int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2603 u8 status)
2604{
2605 return user_pairing_resp_complete(hdev, bdaddr, status,
2606 MGMT_OP_USER_PASSKEY_REPLY);
2607}
2608
2609int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2610 bdaddr_t *bdaddr, u8 status)
2611{
2612 return user_pairing_resp_complete(hdev, bdaddr, status,
2613 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2614}
2615
Johan Hedberg744cf192011-11-08 20:40:14 +02002616int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002617{
2618 struct mgmt_ev_auth_failed ev;
2619
Johan Hedberg2a611692011-02-19 12:06:00 -03002620 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002621 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002622
Johan Hedberg744cf192011-11-08 20:40:14 +02002623 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002624}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002625
Johan Hedberg744cf192011-11-08 20:40:14 +02002626int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002627{
2628 struct pending_cmd *cmd;
2629 struct mgmt_cp_set_local_name ev;
2630 int err;
2631
2632 memset(&ev, 0, sizeof(ev));
2633 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2634
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002635 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002636 if (!cmd)
2637 goto send_event;
2638
2639 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002640 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002641 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002642 goto failed;
2643 }
2644
Johan Hedberg744cf192011-11-08 20:40:14 +02002645 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002646
Johan Hedberg744cf192011-11-08 20:40:14 +02002647 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002648 sizeof(ev));
2649 if (err < 0)
2650 goto failed;
2651
2652send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002653 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002654 cmd ? cmd->sk : NULL);
2655
2656failed:
2657 if (cmd)
2658 mgmt_pending_remove(cmd);
2659 return err;
2660}
Szymon Jancc35938b2011-03-22 13:12:21 +01002661
Johan Hedberg744cf192011-11-08 20:40:14 +02002662int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2663 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002664{
2665 struct pending_cmd *cmd;
2666 int err;
2667
Johan Hedberg744cf192011-11-08 20:40:14 +02002668 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002669
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002670 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002671 if (!cmd)
2672 return -ENOENT;
2673
2674 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002675 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002676 MGMT_OP_READ_LOCAL_OOB_DATA,
2677 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002678 } else {
2679 struct mgmt_rp_read_local_oob_data rp;
2680
2681 memcpy(rp.hash, hash, sizeof(rp.hash));
2682 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2683
Johan Hedberg744cf192011-11-08 20:40:14 +02002684 err = cmd_complete(cmd->sk, hdev->id,
2685 MGMT_OP_READ_LOCAL_OOB_DATA,
2686 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002687 }
2688
2689 mgmt_pending_remove(cmd);
2690
2691 return err;
2692}
Johan Hedberge17acd42011-03-30 23:57:16 +03002693
Johan Hedberg48264f02011-11-09 13:58:58 +02002694int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2695 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002696{
2697 struct mgmt_ev_device_found ev;
2698
2699 memset(&ev, 0, sizeof(ev));
2700
Johan Hedberg4c659c32011-11-07 23:13:39 +02002701 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002702 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002703 ev.rssi = rssi;
2704
2705 if (eir)
2706 memcpy(ev.eir, eir, sizeof(ev.eir));
2707
Andre Guedesf8523592011-09-09 18:56:26 -03002708 if (dev_class)
2709 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2710
Johan Hedberg744cf192011-11-08 20:40:14 +02002711 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002712}
Johan Hedberga88a9652011-03-30 13:18:12 +03002713
Johan Hedberg744cf192011-11-08 20:40:14 +02002714int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002715{
2716 struct mgmt_ev_remote_name ev;
2717
2718 memset(&ev, 0, sizeof(ev));
2719
2720 bacpy(&ev.bdaddr, bdaddr);
2721 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2722
Johan Hedberg744cf192011-11-08 20:40:14 +02002723 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002724}
Johan Hedberg314b2382011-04-27 10:29:57 -04002725
Andre Guedes7a135102011-11-09 17:14:25 -03002726int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002727{
2728 struct pending_cmd *cmd;
2729 int err;
2730
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002731 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002732 if (!cmd)
2733 return -ENOENT;
2734
Johan Hedbergca69b792011-11-11 18:10:00 +02002735 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002736 mgmt_pending_remove(cmd);
2737
2738 return err;
2739}
2740
Andre Guedese6d465c2011-11-09 17:14:26 -03002741int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2742{
2743 struct pending_cmd *cmd;
2744 int err;
2745
2746 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2747 if (!cmd)
2748 return -ENOENT;
2749
2750 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
2751 mgmt_pending_remove(cmd);
2752
2753 return err;
2754}
2755
Johan Hedberg744cf192011-11-08 20:40:14 +02002756int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002757{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002758 struct pending_cmd *cmd;
2759
2760 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002761 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002762 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002763 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002764
2765 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002766 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002767 mgmt_pending_remove(cmd);
2768 }
2769
Johan Hedberg744cf192011-11-08 20:40:14 +02002770 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002771 sizeof(discovering), NULL);
2772}
Antti Julku5e762442011-08-25 16:48:02 +03002773
Johan Hedberg744cf192011-11-08 20:40:14 +02002774int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002775{
2776 struct pending_cmd *cmd;
2777 struct mgmt_ev_device_blocked ev;
2778
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002779 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002780
2781 bacpy(&ev.bdaddr, bdaddr);
2782
Johan Hedberg744cf192011-11-08 20:40:14 +02002783 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2784 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002785}
2786
Johan Hedberg744cf192011-11-08 20:40:14 +02002787int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002788{
2789 struct pending_cmd *cmd;
2790 struct mgmt_ev_device_unblocked ev;
2791
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002792 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002793
2794 bacpy(&ev.bdaddr, bdaddr);
2795
Johan Hedberg744cf192011-11-08 20:40:14 +02002796 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2797 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002798}