blob: cb3af4e4f9593b5139834531840d6aa8a4cb3fc0 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Johan Hedbergca69b792011-11-11 18:10:00 +020025#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020027#include <asm/unaligned.h>
28
29#include <net/bluetooth/bluetooth.h>
30#include <net/bluetooth/hci_core.h>
31#include <net/bluetooth/mgmt.h>
32
Johan Hedberg02d98122010-12-13 21:07:04 +020033#define MGMT_VERSION 0
34#define MGMT_REVISION 1
35
Andre Guedes2519a1f2011-11-07 11:45:24 -030036#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
37
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020038struct pending_cmd {
39 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020040 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020041 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010042 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020043 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030044 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045};
46
Johan Hedbergca69b792011-11-11 18:10:00 +020047/* HCI to MGMT error code conversion table */
48static u8 mgmt_status_table[] = {
49 MGMT_STATUS_SUCCESS,
50 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
51 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
52 MGMT_STATUS_FAILED, /* Hardware Failure */
53 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
54 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
55 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
56 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
57 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
58 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
59 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
60 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
61 MGMT_STATUS_BUSY, /* Command Disallowed */
62 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
63 MGMT_STATUS_REJECTED, /* Rejected Security */
64 MGMT_STATUS_REJECTED, /* Rejected Personal */
65 MGMT_STATUS_TIMEOUT, /* Host Timeout */
66 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
67 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
68 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
69 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
70 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
71 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
72 MGMT_STATUS_BUSY, /* Repeated Attempts */
73 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
74 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
75 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
76 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
77 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
78 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
79 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
80 MGMT_STATUS_FAILED, /* Unspecified Error */
81 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
82 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
83 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
84 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
85 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
86 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
87 MGMT_STATUS_FAILED, /* Unit Link Key Used */
88 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
89 MGMT_STATUS_TIMEOUT, /* Instant Passed */
90 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
91 MGMT_STATUS_FAILED, /* Transaction Collision */
92 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
93 MGMT_STATUS_REJECTED, /* QoS Rejected */
94 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
95 MGMT_STATUS_REJECTED, /* Insufficient Security */
96 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
97 MGMT_STATUS_BUSY, /* Role Switch Pending */
98 MGMT_STATUS_FAILED, /* Slot Violation */
99 MGMT_STATUS_FAILED, /* Role Switch Failed */
100 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
101 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
102 MGMT_STATUS_BUSY, /* Host Busy Pairing */
103 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
104 MGMT_STATUS_BUSY, /* Controller Busy */
105 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
106 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
107 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
108 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
109 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
110};
111
112static u8 mgmt_status(u8 hci_status)
113{
114 if (hci_status < ARRAY_SIZE(mgmt_status_table))
115 return mgmt_status_table[hci_status];
116
117 return MGMT_STATUS_FAILED;
118}
119
Szymon Janc4e51eae2011-02-25 19:05:48 +0100120static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200121{
122 struct sk_buff *skb;
123 struct mgmt_hdr *hdr;
124 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300125 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200126
Szymon Janc34eb5252011-02-28 14:10:08 +0100127 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200128
129 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
130 if (!skb)
131 return -ENOMEM;
132
133 hdr = (void *) skb_put(skb, sizeof(*hdr));
134
135 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100136 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200137 hdr->len = cpu_to_le16(sizeof(*ev));
138
139 ev = (void *) skb_put(skb, sizeof(*ev));
140 ev->status = status;
141 put_unaligned_le16(cmd, &ev->opcode);
142
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300143 err = sock_queue_rcv_skb(sk, skb);
144 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200145 kfree_skb(skb);
146
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300147 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200148}
149
Szymon Janc4e51eae2011-02-25 19:05:48 +0100150static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
151 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200152{
153 struct sk_buff *skb;
154 struct mgmt_hdr *hdr;
155 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300156 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200157
158 BT_DBG("sock %p", sk);
159
Johan Hedberga38528f2011-01-22 06:46:43 +0200160 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200161 if (!skb)
162 return -ENOMEM;
163
164 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200165
Johan Hedberg02d98122010-12-13 21:07:04 +0200166 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100167 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200168 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200169
Johan Hedberga38528f2011-01-22 06:46:43 +0200170 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
171 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100172
173 if (rp)
174 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200175
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300176 err = sock_queue_rcv_skb(sk, skb);
177 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200178 kfree_skb(skb);
179
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300180 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200181}
182
Johan Hedberga38528f2011-01-22 06:46:43 +0200183static int read_version(struct sock *sk)
184{
185 struct mgmt_rp_read_version rp;
186
187 BT_DBG("sock %p", sk);
188
189 rp.version = MGMT_VERSION;
190 put_unaligned_le16(MGMT_REVISION, &rp.revision);
191
Szymon Janc4e51eae2011-02-25 19:05:48 +0100192 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
193 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200194}
195
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200196static int read_index_list(struct sock *sk)
197{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200198 struct mgmt_rp_read_index_list *rp;
199 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200200 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200202 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200204
205 BT_DBG("sock %p", sk);
206
207 read_lock(&hci_dev_list_lock);
208
209 count = 0;
210 list_for_each(p, &hci_dev_list) {
211 count++;
212 }
213
Johan Hedberga38528f2011-01-22 06:46:43 +0200214 rp_len = sizeof(*rp) + (2 * count);
215 rp = kmalloc(rp_len, GFP_ATOMIC);
216 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100217 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200218 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100219 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200220
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200221 put_unaligned_le16(count, &rp->num_controllers);
222
223 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200224 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberg32435532011-11-07 22:16:04 +0200225 if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200226 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200227
228 if (test_bit(HCI_SETUP, &d->flags))
229 continue;
230
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200231 put_unaligned_le16(d->id, &rp->index[i++]);
232 BT_DBG("Added hci%u", d->id);
233 }
234
235 read_unlock(&hci_dev_list_lock);
236
Szymon Janc4e51eae2011-02-25 19:05:48 +0100237 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
238 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200239
Johan Hedberga38528f2011-01-22 06:46:43 +0200240 kfree(rp);
241
242 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200243}
244
Szymon Janc4e51eae2011-02-25 19:05:48 +0100245static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200246{
Johan Hedberga38528f2011-01-22 06:46:43 +0200247 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200248 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200249
Szymon Janc4e51eae2011-02-25 19:05:48 +0100250 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200251
Szymon Janc4e51eae2011-02-25 19:05:48 +0100252 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200253 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200254 return cmd_status(sk, index, MGMT_OP_READ_INFO,
255 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200256
Johan Hedberg32435532011-11-07 22:16:04 +0200257 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
258 cancel_delayed_work_sync(&hdev->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200259
Andre Guedes8c156c32011-07-07 10:30:36 -0300260 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200261
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200262 set_bit(HCI_MGMT, &hdev->flags);
263
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200264 memset(&rp, 0, sizeof(rp));
265
Johan Hedberga38528f2011-01-22 06:46:43 +0200266 rp.type = hdev->dev_type;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200267
Johan Hedberga38528f2011-01-22 06:46:43 +0200268 rp.powered = test_bit(HCI_UP, &hdev->flags);
269 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
270 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
271 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200272
273 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200274 rp.sec_mode = 3;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200275 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200276 rp.sec_mode = 4;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200277 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200278 rp.sec_mode = 2;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200279
Johan Hedberga38528f2011-01-22 06:46:43 +0200280 bacpy(&rp.bdaddr, &hdev->bdaddr);
281 memcpy(rp.features, hdev->features, 8);
282 memcpy(rp.dev_class, hdev->dev_class, 3);
283 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
284 rp.hci_ver = hdev->hci_ver;
285 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200286
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200287 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
288
Andre Guedes8c156c32011-07-07 10:30:36 -0300289 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200290 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200291
Szymon Janc4e51eae2011-02-25 19:05:48 +0100292 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200293}
294
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200295static void mgmt_pending_free(struct pending_cmd *cmd)
296{
297 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100298 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200299 kfree(cmd);
300}
301
Johan Hedberg366a0332011-02-19 12:05:55 -0300302static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200303 struct hci_dev *hdev,
304 void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200305{
306 struct pending_cmd *cmd;
307
308 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
309 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300310 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200311
312 cmd->opcode = opcode;
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200313 cmd->index = hdev->id;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200314
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100315 cmd->param = kmalloc(len, GFP_ATOMIC);
316 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200317 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300318 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200319 }
320
Szymon Janc8fce6352011-03-22 13:12:20 +0100321 if (data)
322 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200323
324 cmd->sk = sk;
325 sock_hold(sk);
326
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200327 list_add(&cmd->list, &hdev->mgmt_pending);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200328
Johan Hedberg366a0332011-02-19 12:05:55 -0300329 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200330}
331
Johan Hedberg744cf192011-11-08 20:40:14 +0200332static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200333 void (*cb)(struct pending_cmd *cmd, void *data),
334 void *data)
335{
336 struct list_head *p, *n;
337
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200338 list_for_each_safe(p, n, &hdev->mgmt_pending) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200339 struct pending_cmd *cmd;
340
341 cmd = list_entry(p, struct pending_cmd, list);
342
Johan Hedbergb24752f2011-11-03 14:40:33 +0200343 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200344 continue;
345
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200346 cb(cmd, data);
347 }
348}
349
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200350static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200351{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200352 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200353
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200354 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberg2aeabcb2011-11-09 13:58:57 +0200355 if (cmd->opcode == opcode)
356 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200357 }
358
359 return NULL;
360}
361
Johan Hedberga664b5b2011-02-19 12:06:02 -0300362static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200363{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200364 list_del(&cmd->list);
365 mgmt_pending_free(cmd);
366}
367
Johan Hedberg86805702011-11-11 16:18:52 +0200368static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
369{
370 struct mgmt_mode rp;
371
372 rp.val = val;
373
374 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
375}
376
Szymon Janc4e51eae2011-02-25 19:05:48 +0100377static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200378{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200379 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200380 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300381 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300382 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200383
384 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200385
Szymon Janc4e51eae2011-02-25 19:05:48 +0100386 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200387
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100388 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200389 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
390 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100391
Szymon Janc4e51eae2011-02-25 19:05:48 +0100392 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200393 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200394 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
395 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200396
Andre Guedes8c156c32011-07-07 10:30:36 -0300397 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200398
399 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200400 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg86805702011-11-11 16:18:52 +0200401 err = send_mode_rsp(sk, index, MGMT_OP_SET_POWERED, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200402 goto failed;
403 }
404
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200405 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200406 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
407 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200408 goto failed;
409 }
410
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200411 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300412 if (!cmd) {
413 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200414 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300415 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200416
Johan Hedberg72a734e2010-12-30 00:38:22 +0200417 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200418 queue_work(hdev->workqueue, &hdev->power_on);
419 else
Johan Hedberg32435532011-11-07 22:16:04 +0200420 queue_work(hdev->workqueue, &hdev->power_off.work);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200421
Johan Hedberg366a0332011-02-19 12:05:55 -0300422 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200423
424failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300425 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200426 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300427 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200428}
429
Szymon Janc4e51eae2011-02-25 19:05:48 +0100430static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
431 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200432{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200433 struct mgmt_cp_set_discoverable *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200434 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300435 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200436 u8 scan;
437 int err;
438
439 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200440
Szymon Janc4e51eae2011-02-25 19:05:48 +0100441 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200442
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100443 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200444 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
445 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100446
Szymon Janc4e51eae2011-02-25 19:05:48 +0100447 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200448 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200449 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
450 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200451
Andre Guedes8c156c32011-07-07 10:30:36 -0300452 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200453
454 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200455 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
456 MGMT_STATUS_NOT_POWERED);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200457 goto failed;
458 }
459
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200460 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
461 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200462 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
463 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200464 goto failed;
465 }
466
Johan Hedberg72a734e2010-12-30 00:38:22 +0200467 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200468 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg86805702011-11-11 16:18:52 +0200469 err = send_mode_rsp(sk, index, MGMT_OP_SET_DISCOVERABLE,
470 cp->val);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200471 goto failed;
472 }
473
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200474 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300475 if (!cmd) {
476 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200477 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300478 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200479
480 scan = SCAN_PAGE;
481
Johan Hedberg72a734e2010-12-30 00:38:22 +0200482 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200483 scan |= SCAN_INQUIRY;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200484 else
Johan Hedberge0f93092011-11-09 01:44:22 +0200485 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200486
487 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
488 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300489 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200490
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200491 if (cp->val)
492 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
493
Johan Hedberg73f22f62010-12-29 16:00:25 +0200494failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300495 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200496 hci_dev_put(hdev);
497
498 return err;
499}
500
Szymon Janc4e51eae2011-02-25 19:05:48 +0100501static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
502 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200503{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200504 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200505 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300506 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200507 u8 scan;
508 int err;
509
510 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200511
Szymon Janc4e51eae2011-02-25 19:05:48 +0100512 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200513
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100514 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200515 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
516 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100517
Szymon Janc4e51eae2011-02-25 19:05:48 +0100518 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200519 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200520 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
521 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200522
Andre Guedes8c156c32011-07-07 10:30:36 -0300523 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200524
525 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200526 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
527 MGMT_STATUS_NOT_POWERED);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200528 goto failed;
529 }
530
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200531 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
532 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200533 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
534 MGMT_STATUS_BUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200535 goto failed;
536 }
537
Johan Hedberg72a734e2010-12-30 00:38:22 +0200538 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg86805702011-11-11 16:18:52 +0200539 err = send_mode_rsp(sk, index, MGMT_OP_SET_CONNECTABLE,
540 cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200541 goto failed;
542 }
543
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200544 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300545 if (!cmd) {
546 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200547 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300548 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200549
Johan Hedberg72a734e2010-12-30 00:38:22 +0200550 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200551 scan = SCAN_PAGE;
552 else
553 scan = 0;
554
555 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
556 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300557 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200558
559failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300560 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200561 hci_dev_put(hdev);
562
563 return err;
564}
565
Johan Hedberg744cf192011-11-08 20:40:14 +0200566static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
567 u16 data_len, struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200568{
569 struct sk_buff *skb;
570 struct mgmt_hdr *hdr;
571
572 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
573 if (!skb)
574 return -ENOMEM;
575
576 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
577
578 hdr = (void *) skb_put(skb, sizeof(*hdr));
579 hdr->opcode = cpu_to_le16(event);
Johan Hedberg744cf192011-11-08 20:40:14 +0200580 if (hdev)
581 hdr->index = cpu_to_le16(hdev->id);
582 else
583 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergc542a062011-01-26 13:11:03 +0200584 hdr->len = cpu_to_le16(data_len);
585
Szymon Janc4e51eae2011-02-25 19:05:48 +0100586 if (data)
587 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200588
589 hci_send_to_sock(NULL, skb, skip_sk);
590 kfree_skb(skb);
591
592 return 0;
593}
594
Szymon Janc4e51eae2011-02-25 19:05:48 +0100595static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
596 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200597{
598 struct mgmt_mode *cp, ev;
599 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200600 int err;
601
602 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200603
Szymon Janc4e51eae2011-02-25 19:05:48 +0100604 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200605
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100606 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200607 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
608 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100609
Szymon Janc4e51eae2011-02-25 19:05:48 +0100610 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200611 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200612 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
613 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergc542a062011-01-26 13:11:03 +0200614
Andre Guedes8c156c32011-07-07 10:30:36 -0300615 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200616
617 if (cp->val)
618 set_bit(HCI_PAIRABLE, &hdev->flags);
619 else
620 clear_bit(HCI_PAIRABLE, &hdev->flags);
621
Szymon Janc4e51eae2011-02-25 19:05:48 +0100622 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200623 if (err < 0)
624 goto failed;
625
Johan Hedbergc542a062011-01-26 13:11:03 +0200626 ev.val = cp->val;
627
Johan Hedberg744cf192011-11-08 20:40:14 +0200628 err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200629
630failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300631 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200632 hci_dev_put(hdev);
633
634 return err;
635}
636
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300637#define EIR_FLAGS 0x01 /* flags */
638#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
639#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
640#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
641#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
642#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
643#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
644#define EIR_NAME_SHORT 0x08 /* shortened local name */
645#define EIR_NAME_COMPLETE 0x09 /* complete local name */
646#define EIR_TX_POWER 0x0A /* transmit power level */
647#define EIR_DEVICE_ID 0x10 /* device ID */
648
649#define PNP_INFO_SVCLASS_ID 0x1200
650
651static u8 bluetooth_base_uuid[] = {
652 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
653 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
654};
655
656static u16 get_uuid16(u8 *uuid128)
657{
658 u32 val;
659 int i;
660
661 for (i = 0; i < 12; i++) {
662 if (bluetooth_base_uuid[i] != uuid128[i])
663 return 0;
664 }
665
666 memcpy(&val, &uuid128[12], 4);
667
668 val = le32_to_cpu(val);
669 if (val > 0xffff)
670 return 0;
671
672 return (u16) val;
673}
674
675static void create_eir(struct hci_dev *hdev, u8 *data)
676{
677 u8 *ptr = data;
678 u16 eir_len = 0;
679 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
680 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200681 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300682 size_t name_len;
683
684 name_len = strlen(hdev->dev_name);
685
686 if (name_len > 0) {
687 /* EIR Data type */
688 if (name_len > 48) {
689 name_len = 48;
690 ptr[1] = EIR_NAME_SHORT;
691 } else
692 ptr[1] = EIR_NAME_COMPLETE;
693
694 /* EIR Data length */
695 ptr[0] = name_len + 1;
696
697 memcpy(ptr + 2, hdev->dev_name, name_len);
698
699 eir_len += (name_len + 2);
700 ptr += (name_len + 2);
701 }
702
703 memset(uuid16_list, 0, sizeof(uuid16_list));
704
705 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200706 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300707 u16 uuid16;
708
709 uuid16 = get_uuid16(uuid->uuid);
710 if (uuid16 == 0)
711 return;
712
713 if (uuid16 < 0x1100)
714 continue;
715
716 if (uuid16 == PNP_INFO_SVCLASS_ID)
717 continue;
718
719 /* Stop if not enough space to put next UUID */
720 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
721 truncated = 1;
722 break;
723 }
724
725 /* Check for duplicates */
726 for (i = 0; uuid16_list[i] != 0; i++)
727 if (uuid16_list[i] == uuid16)
728 break;
729
730 if (uuid16_list[i] == 0) {
731 uuid16_list[i] = uuid16;
732 eir_len += sizeof(u16);
733 }
734 }
735
736 if (uuid16_list[0] != 0) {
737 u8 *length = ptr;
738
739 /* EIR Data type */
740 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
741
742 ptr += 2;
743 eir_len += 2;
744
745 for (i = 0; uuid16_list[i] != 0; i++) {
746 *ptr++ = (uuid16_list[i] & 0x00ff);
747 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
748 }
749
750 /* EIR Data length */
751 *length = (i * sizeof(u16)) + 1;
752 }
753}
754
755static int update_eir(struct hci_dev *hdev)
756{
757 struct hci_cp_write_eir cp;
758
759 if (!(hdev->features[6] & LMP_EXT_INQ))
760 return 0;
761
762 if (hdev->ssp_mode == 0)
763 return 0;
764
765 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
766 return 0;
767
768 memset(&cp, 0, sizeof(cp));
769
770 create_eir(hdev, cp.data);
771
772 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
773 return 0;
774
775 memcpy(hdev->eir, cp.data, sizeof(cp.data));
776
777 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
778}
779
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200780static u8 get_service_classes(struct hci_dev *hdev)
781{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300782 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200783 u8 val = 0;
784
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300785 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200786 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200787
788 return val;
789}
790
791static int update_class(struct hci_dev *hdev)
792{
793 u8 cod[3];
794
795 BT_DBG("%s", hdev->name);
796
797 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
798 return 0;
799
800 cod[0] = hdev->minor_class;
801 cod[1] = hdev->major_class;
802 cod[2] = get_service_classes(hdev);
803
804 if (memcmp(cod, hdev->dev_class, 3) == 0)
805 return 0;
806
807 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
808}
809
Szymon Janc4e51eae2011-02-25 19:05:48 +0100810static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200811{
812 struct mgmt_cp_add_uuid *cp;
813 struct hci_dev *hdev;
814 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200815 int err;
816
817 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200818
Szymon Janc4e51eae2011-02-25 19:05:48 +0100819 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200820
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100821 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200822 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
823 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100824
Szymon Janc4e51eae2011-02-25 19:05:48 +0100825 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200826 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200827 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
828 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200829
Andre Guedes8c156c32011-07-07 10:30:36 -0300830 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200831
832 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
833 if (!uuid) {
834 err = -ENOMEM;
835 goto failed;
836 }
837
838 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200839 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200840
841 list_add(&uuid->list, &hdev->uuids);
842
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200843 err = update_class(hdev);
844 if (err < 0)
845 goto failed;
846
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300847 err = update_eir(hdev);
848 if (err < 0)
849 goto failed;
850
Szymon Janc4e51eae2011-02-25 19:05:48 +0100851 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200852
853failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300854 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200855 hci_dev_put(hdev);
856
857 return err;
858}
859
Szymon Janc4e51eae2011-02-25 19:05:48 +0100860static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200861{
862 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100863 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200864 struct hci_dev *hdev;
865 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 +0200866 int err, found;
867
868 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200869
Szymon Janc4e51eae2011-02-25 19:05:48 +0100870 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200871
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100872 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200873 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
874 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100875
Szymon Janc4e51eae2011-02-25 19:05:48 +0100876 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200877 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200878 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
879 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200880
Andre Guedes8c156c32011-07-07 10:30:36 -0300881 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200882
883 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
884 err = hci_uuids_clear(hdev);
885 goto unlock;
886 }
887
888 found = 0;
889
890 list_for_each_safe(p, n, &hdev->uuids) {
891 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
892
893 if (memcmp(match->uuid, cp->uuid, 16) != 0)
894 continue;
895
896 list_del(&match->list);
897 found++;
898 }
899
900 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200901 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
902 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200903 goto unlock;
904 }
905
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200906 err = update_class(hdev);
907 if (err < 0)
908 goto unlock;
909
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300910 err = update_eir(hdev);
911 if (err < 0)
912 goto unlock;
913
Szymon Janc4e51eae2011-02-25 19:05:48 +0100914 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200915
916unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300917 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200918 hci_dev_put(hdev);
919
920 return err;
921}
922
Szymon Janc4e51eae2011-02-25 19:05:48 +0100923static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
924 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200925{
926 struct hci_dev *hdev;
927 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200928 int err;
929
930 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200931
Szymon Janc4e51eae2011-02-25 19:05:48 +0100932 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200933
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100934 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200935 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
936 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100937
Szymon Janc4e51eae2011-02-25 19:05:48 +0100938 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200939 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200940 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
941 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200942
Andre Guedes8c156c32011-07-07 10:30:36 -0300943 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200944
945 hdev->major_class = cp->major;
946 hdev->minor_class = cp->minor;
947
948 err = update_class(hdev);
949
950 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100951 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200952
Andre Guedes8c156c32011-07-07 10:30:36 -0300953 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200954 hci_dev_put(hdev);
955
956 return err;
957}
958
Szymon Janc4e51eae2011-02-25 19:05:48 +0100959static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
960 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200961{
962 struct hci_dev *hdev;
963 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200964 int err;
965
966 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200967
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100968 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200969 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE,
970 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100971
Szymon Janc4e51eae2011-02-25 19:05:48 +0100972 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200973 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200974 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE,
975 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200976
Andre Guedes8c156c32011-07-07 10:30:36 -0300977 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200978
Szymon Janc4e51eae2011-02-25 19:05:48 +0100979 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200980
981 if (cp->enable) {
982 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
983 err = 0;
984 } else {
985 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
986 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300987 if (err == 0)
988 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200989 }
990
991 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100992 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
993 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -0300994 else
995 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
996
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200997
Andre Guedes8c156c32011-07-07 10:30:36 -0300998 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200999 hci_dev_put(hdev);
1000
1001 return err;
1002}
1003
Johan Hedberg86742e12011-11-07 23:13:38 +02001004static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
1005 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001006{
1007 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001008 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001009 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001010 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001011
1012 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001013
1014 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001015 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1016 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001017
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001018 key_count = get_unaligned_le16(&cp->key_count);
1019
Johan Hedberg86742e12011-11-07 23:13:38 +02001020 expected_len = sizeof(*cp) + key_count *
1021 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001022 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001023 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001024 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001025 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1026 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001027 }
1028
Szymon Janc4e51eae2011-02-25 19:05:48 +01001029 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001030 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001031 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1032 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001033
Szymon Janc4e51eae2011-02-25 19:05:48 +01001034 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001035 key_count);
1036
Andre Guedes8c156c32011-07-07 10:30:36 -03001037 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001038
1039 hci_link_keys_clear(hdev);
1040
1041 set_bit(HCI_LINK_KEYS, &hdev->flags);
1042
1043 if (cp->debug_keys)
1044 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1045 else
1046 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1047
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001048 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001049 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001050
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001051 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001052 key->pin_len);
1053 }
1054
Andre Guedes8c156c32011-07-07 10:30:36 -03001055 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001056 hci_dev_put(hdev);
1057
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001058 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001059}
1060
Johan Hedberg86742e12011-11-07 23:13:38 +02001061static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
1062 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001063{
1064 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001065 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001066 struct mgmt_rp_remove_keys rp;
1067 struct hci_cp_disconnect dc;
1068 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001069 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001070 int err;
1071
1072 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001073
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001074 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001075 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1076 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001077
Szymon Janc4e51eae2011-02-25 19:05:48 +01001078 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001079 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001080 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1081 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001082
Andre Guedes8c156c32011-07-07 10:30:36 -03001083 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001084
Johan Hedberga8a1d192011-11-10 15:54:38 +02001085 memset(&rp, 0, sizeof(rp));
1086 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001087 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001088
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001089 err = hci_remove_link_key(hdev, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001090 if (err < 0) {
1091 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001092 goto unlock;
Johan Hedbergca69b792011-11-11 18:10:00 +02001093 }
Johan Hedberga8a1d192011-11-10 15:54:38 +02001094
1095 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1096 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1097 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001098 goto unlock;
1099 }
1100
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001101 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001102 if (!conn) {
1103 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1104 sizeof(rp));
1105 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001106 }
1107
Johan Hedberga8a1d192011-11-10 15:54:38 +02001108 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1109 if (!cmd) {
1110 err = -ENOMEM;
1111 goto unlock;
1112 }
1113
1114 put_unaligned_le16(conn->handle, &dc.handle);
1115 dc.reason = 0x13; /* Remote User Terminated Connection */
1116 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1117 if (err < 0)
1118 mgmt_pending_remove(cmd);
1119
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001120unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001121 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001122 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1123 sizeof(rp));
Andre Guedes8c156c32011-07-07 10:30:36 -03001124 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001125 hci_dev_put(hdev);
1126
1127 return err;
1128}
1129
Szymon Janc4e51eae2011-02-25 19:05:48 +01001130static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001131{
1132 struct hci_dev *hdev;
1133 struct mgmt_cp_disconnect *cp;
1134 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001135 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001136 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001137 int err;
1138
1139 BT_DBG("");
1140
1141 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001142
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001143 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001144 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1145 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001146
Szymon Janc4e51eae2011-02-25 19:05:48 +01001147 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001148 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001149 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1150 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001151
Andre Guedes8c156c32011-07-07 10:30:36 -03001152 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001153
1154 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001155 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1156 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001157 goto failed;
1158 }
1159
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001160 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001161 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1162 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001163 goto failed;
1164 }
1165
1166 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001167 if (!conn)
1168 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1169
Johan Hedberg8962ee72011-01-20 12:40:27 +02001170 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001171 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1172 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001173 goto failed;
1174 }
1175
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001176 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001177 if (!cmd) {
1178 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001179 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001180 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001181
1182 put_unaligned_le16(conn->handle, &dc.handle);
1183 dc.reason = 0x13; /* Remote User Terminated Connection */
1184
1185 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1186 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001187 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001188
1189failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001190 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001191 hci_dev_put(hdev);
1192
1193 return err;
1194}
1195
Johan Hedberg48264f02011-11-09 13:58:58 +02001196static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001197{
1198 switch (link_type) {
1199 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001200 switch (addr_type) {
1201 case ADDR_LE_DEV_PUBLIC:
1202 return MGMT_ADDR_LE_PUBLIC;
1203 case ADDR_LE_DEV_RANDOM:
1204 return MGMT_ADDR_LE_RANDOM;
1205 default:
1206 return MGMT_ADDR_INVALID;
1207 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001208 case ACL_LINK:
1209 return MGMT_ADDR_BREDR;
1210 default:
1211 return MGMT_ADDR_INVALID;
1212 }
1213}
1214
Szymon Janc8ce62842011-03-01 16:55:32 +01001215static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001216{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001217 struct mgmt_rp_get_connections *rp;
1218 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001219 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001220 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001221 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001222 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001223 int i, err;
1224
1225 BT_DBG("");
1226
Szymon Janc4e51eae2011-02-25 19:05:48 +01001227 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001228 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001229 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1230 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001231
Andre Guedes8c156c32011-07-07 10:30:36 -03001232 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001233
1234 count = 0;
1235 list_for_each(p, &hdev->conn_hash.list) {
1236 count++;
1237 }
1238
Johan Hedberg4c659c32011-11-07 23:13:39 +02001239 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001240 rp = kmalloc(rp_len, GFP_ATOMIC);
1241 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001242 err = -ENOMEM;
1243 goto unlock;
1244 }
1245
Johan Hedberg2784eb42011-01-21 13:56:35 +02001246 put_unaligned_le16(count, &rp->conn_count);
1247
Johan Hedberg2784eb42011-01-21 13:56:35 +02001248 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001249 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1250 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001251 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001252 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1253 continue;
1254 i++;
1255 }
1256
1257 /* Recalculate length in case of filtered SCO connections, etc */
1258 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001259
Szymon Janc4e51eae2011-02-25 19:05:48 +01001260 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001261
1262unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001263 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001264 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001265 hci_dev_put(hdev);
1266 return err;
1267}
1268
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001269static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1270 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1271{
1272 struct pending_cmd *cmd;
1273 int err;
1274
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001275 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001276 sizeof(*cp));
1277 if (!cmd)
1278 return -ENOMEM;
1279
1280 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1281 &cp->bdaddr);
1282 if (err < 0)
1283 mgmt_pending_remove(cmd);
1284
1285 return err;
1286}
1287
Szymon Janc4e51eae2011-02-25 19:05:48 +01001288static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1289 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001290{
1291 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001292 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001293 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001294 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001295 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001296 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001297 int err;
1298
1299 BT_DBG("");
1300
1301 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001302
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001303 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001304 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1305 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001306
Szymon Janc4e51eae2011-02-25 19:05:48 +01001307 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001308 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001309 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1310 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001311
Andre Guedes8c156c32011-07-07 10:30:36 -03001312 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001313
1314 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001315 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1316 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001317 goto failed;
1318 }
1319
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001320 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1321 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001322 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1323 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001324 goto failed;
1325 }
1326
1327 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1328 bacpy(&ncp.bdaddr, &cp->bdaddr);
1329
1330 BT_ERR("PIN code is not 16 bytes long");
1331
1332 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1333 if (err >= 0)
1334 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001335 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001336
1337 goto failed;
1338 }
1339
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001340 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001341 if (!cmd) {
1342 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001343 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001344 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001345
1346 bacpy(&reply.bdaddr, &cp->bdaddr);
1347 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001348 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001349
1350 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1351 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001352 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001353
1354failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001355 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001356 hci_dev_put(hdev);
1357
1358 return err;
1359}
1360
Szymon Janc4e51eae2011-02-25 19:05:48 +01001361static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1362 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001363{
1364 struct hci_dev *hdev;
1365 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001366 int err;
1367
1368 BT_DBG("");
1369
1370 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001371
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001372 if (len != sizeof(*cp))
1373 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001374 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001375
Szymon Janc4e51eae2011-02-25 19:05:48 +01001376 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001377 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001378 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001379 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001380
Andre Guedes8c156c32011-07-07 10:30:36 -03001381 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001382
1383 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001384 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001385 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001386 goto failed;
1387 }
1388
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001389 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001390
1391failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001392 hci_dev_unlock_bh(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 set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1399 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001400{
1401 struct hci_dev *hdev;
1402 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001403
1404 BT_DBG("");
1405
1406 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001407
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001408 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001409 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1410 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001411
Szymon Janc4e51eae2011-02-25 19:05:48 +01001412 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001413 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001414 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1415 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001416
Andre Guedes8c156c32011-07-07 10:30:36 -03001417 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001418
1419 hdev->io_capability = cp->io_capability;
1420
1421 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001422 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001423
Andre Guedes8c156c32011-07-07 10:30:36 -03001424 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001425 hci_dev_put(hdev);
1426
Szymon Janc4e51eae2011-02-25 19:05:48 +01001427 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001428}
1429
Johan Hedberge9a416b2011-02-19 12:05:56 -03001430static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1431{
1432 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001433 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001434
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001435 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001436 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1437 continue;
1438
Johan Hedberge9a416b2011-02-19 12:05:56 -03001439 if (cmd->user_data != conn)
1440 continue;
1441
1442 return cmd;
1443 }
1444
1445 return NULL;
1446}
1447
1448static void pairing_complete(struct pending_cmd *cmd, u8 status)
1449{
1450 struct mgmt_rp_pair_device rp;
1451 struct hci_conn *conn = cmd->user_data;
1452
Johan Hedbergba4e5642011-11-11 00:07:34 +02001453 bacpy(&rp.addr.bdaddr, &conn->dst);
1454 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001455 rp.status = status;
1456
Szymon Janc4e51eae2011-02-25 19:05:48 +01001457 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001458
1459 /* So we don't get further callbacks for this connection */
1460 conn->connect_cfm_cb = NULL;
1461 conn->security_cfm_cb = NULL;
1462 conn->disconn_cfm_cb = NULL;
1463
1464 hci_conn_put(conn);
1465
Johan Hedberga664b5b2011-02-19 12:06:02 -03001466 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001467}
1468
1469static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1470{
1471 struct pending_cmd *cmd;
1472
1473 BT_DBG("status %u", status);
1474
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001475 cmd = find_pairing(conn);
1476 if (!cmd)
1477 BT_DBG("Unable to find a pending command");
1478 else
1479 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001480}
1481
Szymon Janc4e51eae2011-02-25 19:05:48 +01001482static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001483{
1484 struct hci_dev *hdev;
1485 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001486 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001487 struct pending_cmd *cmd;
1488 u8 sec_level, auth_type;
1489 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001490 int err;
1491
1492 BT_DBG("");
1493
1494 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001495
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001496 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001497 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1498 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001499
Szymon Janc4e51eae2011-02-25 19:05:48 +01001500 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001501 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001502 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1503 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001504
Andre Guedes8c156c32011-07-07 10:30:36 -03001505 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001506
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001507 sec_level = BT_SECURITY_MEDIUM;
1508 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001509 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001510 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001511 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001512
Johan Hedbergba4e5642011-11-11 00:07:34 +02001513 if (cp->addr.type == MGMT_ADDR_BREDR)
1514 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001515 auth_type);
1516 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001517 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001518 auth_type);
1519
Johan Hedberg1425acb2011-11-11 00:07:35 +02001520 memset(&rp, 0, sizeof(rp));
1521 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1522 rp.addr.type = cp->addr.type;
1523
Ville Tervo30e76272011-02-22 16:10:53 -03001524 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001525 rp.status = -PTR_ERR(conn);
1526 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1527 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001528 goto unlock;
1529 }
1530
1531 if (conn->connect_cfm_cb) {
1532 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001533 rp.status = EBUSY;
1534 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1535 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001536 goto unlock;
1537 }
1538
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001539 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001540 if (!cmd) {
1541 err = -ENOMEM;
1542 hci_conn_put(conn);
1543 goto unlock;
1544 }
1545
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001546 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001547 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001548 conn->connect_cfm_cb = pairing_complete_cb;
1549
Johan Hedberge9a416b2011-02-19 12:05:56 -03001550 conn->security_cfm_cb = pairing_complete_cb;
1551 conn->disconn_cfm_cb = pairing_complete_cb;
1552 conn->io_capability = cp->io_cap;
1553 cmd->user_data = conn;
1554
1555 if (conn->state == BT_CONNECTED &&
1556 hci_conn_security(conn, sec_level, auth_type))
1557 pairing_complete(cmd, 0);
1558
1559 err = 0;
1560
1561unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001562 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001563 hci_dev_put(hdev);
1564
1565 return err;
1566}
1567
Szymon Janc4e51eae2011-02-25 19:05:48 +01001568static int user_confirm_reply(struct sock *sk, u16 index, unsigned char *data,
1569 u16 len, int success)
Johan Hedberga5c29682011-02-19 12:05:57 -03001570{
1571 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001572 u16 mgmt_op, hci_op;
Johan Hedberga5c29682011-02-19 12:05:57 -03001573 struct pending_cmd *cmd;
1574 struct hci_dev *hdev;
1575 int err;
1576
1577 BT_DBG("");
1578
Johan Hedberga5c29682011-02-19 12:05:57 -03001579 if (success) {
1580 mgmt_op = MGMT_OP_USER_CONFIRM_REPLY;
1581 hci_op = HCI_OP_USER_CONFIRM_REPLY;
1582 } else {
1583 mgmt_op = MGMT_OP_USER_CONFIRM_NEG_REPLY;
1584 hci_op = HCI_OP_USER_CONFIRM_NEG_REPLY;
1585 }
1586
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001587 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001588 return cmd_status(sk, index, mgmt_op,
1589 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001590
Szymon Janc4e51eae2011-02-25 19:05:48 +01001591 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001592 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001593 return cmd_status(sk, index, mgmt_op,
1594 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001595
Andre Guedes8c156c32011-07-07 10:30:36 -03001596 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001597
Johan Hedberga5c29682011-02-19 12:05:57 -03001598 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001599 err = cmd_status(sk, index, mgmt_op, ENETDOWN);
Johan Hedberga5c29682011-02-19 12:05:57 -03001600 goto failed;
1601 }
1602
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001603 cmd = mgmt_pending_add(sk, mgmt_op, hdev, data, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03001604 if (!cmd) {
1605 err = -ENOMEM;
1606 goto failed;
1607 }
1608
1609 err = hci_send_cmd(hdev, hci_op, sizeof(cp->bdaddr), &cp->bdaddr);
Johan Hedberga664b5b2011-02-19 12:06:02 -03001610 if (err < 0)
1611 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001612
1613failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001614 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001615 hci_dev_put(hdev);
1616
1617 return err;
1618}
1619
Johan Hedbergb312b1612011-03-16 14:29:37 +02001620static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1621 u16 len)
1622{
1623 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1624 struct hci_cp_write_local_name hci_cp;
1625 struct hci_dev *hdev;
1626 struct pending_cmd *cmd;
1627 int err;
1628
1629 BT_DBG("");
1630
1631 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001632 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1633 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001634
1635 hdev = hci_dev_get(index);
1636 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001637 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1638 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001639
Andre Guedes8c156c32011-07-07 10:30:36 -03001640 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001641
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001642 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001643 if (!cmd) {
1644 err = -ENOMEM;
1645 goto failed;
1646 }
1647
1648 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1649 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1650 &hci_cp);
1651 if (err < 0)
1652 mgmt_pending_remove(cmd);
1653
1654failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001655 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001656 hci_dev_put(hdev);
1657
1658 return err;
1659}
1660
Szymon Jancc35938b2011-03-22 13:12:21 +01001661static int read_local_oob_data(struct sock *sk, u16 index)
1662{
1663 struct hci_dev *hdev;
1664 struct pending_cmd *cmd;
1665 int err;
1666
1667 BT_DBG("hci%u", index);
1668
1669 hdev = hci_dev_get(index);
1670 if (!hdev)
1671 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001672 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001673
Andre Guedes8c156c32011-07-07 10:30:36 -03001674 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001675
1676 if (!test_bit(HCI_UP, &hdev->flags)) {
1677 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001678 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001679 goto unlock;
1680 }
1681
1682 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1683 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001684 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001685 goto unlock;
1686 }
1687
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001688 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001689 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1690 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001691 goto unlock;
1692 }
1693
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001694 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001695 if (!cmd) {
1696 err = -ENOMEM;
1697 goto unlock;
1698 }
1699
1700 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1701 if (err < 0)
1702 mgmt_pending_remove(cmd);
1703
1704unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001705 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001706 hci_dev_put(hdev);
1707
1708 return err;
1709}
1710
Szymon Janc2763eda2011-03-22 13:12:22 +01001711static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1712 u16 len)
1713{
1714 struct hci_dev *hdev;
1715 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1716 int err;
1717
1718 BT_DBG("hci%u ", index);
1719
1720 if (len != sizeof(*cp))
1721 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001722 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001723
1724 hdev = hci_dev_get(index);
1725 if (!hdev)
1726 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001727 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001728
Andre Guedes8c156c32011-07-07 10:30:36 -03001729 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001730
1731 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1732 cp->randomizer);
1733 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001734 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1735 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001736 else
1737 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1738 0);
1739
Andre Guedes8c156c32011-07-07 10:30:36 -03001740 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001741 hci_dev_put(hdev);
1742
1743 return err;
1744}
1745
1746static int remove_remote_oob_data(struct sock *sk, u16 index,
1747 unsigned char *data, u16 len)
1748{
1749 struct hci_dev *hdev;
1750 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1751 int err;
1752
1753 BT_DBG("hci%u ", index);
1754
1755 if (len != sizeof(*cp))
1756 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001757 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001758
1759 hdev = hci_dev_get(index);
1760 if (!hdev)
1761 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001762 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001763
Andre Guedes8c156c32011-07-07 10:30:36 -03001764 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001765
1766 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1767 if (err < 0)
1768 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001769 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001770 else
1771 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1772 NULL, 0);
1773
Andre Guedes8c156c32011-07-07 10:30:36 -03001774 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001775 hci_dev_put(hdev);
1776
1777 return err;
1778}
1779
Johan Hedberg14a53662011-04-27 10:29:56 -04001780static int start_discovery(struct sock *sk, u16 index)
1781{
Johan Hedberg14a53662011-04-27 10:29:56 -04001782 struct pending_cmd *cmd;
1783 struct hci_dev *hdev;
1784 int err;
1785
1786 BT_DBG("hci%u", index);
1787
1788 hdev = hci_dev_get(index);
1789 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001790 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1791 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001792
1793 hci_dev_lock_bh(hdev);
1794
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001795 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001796 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1797 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001798 goto failed;
1799 }
1800
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001801 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001802 if (!cmd) {
1803 err = -ENOMEM;
1804 goto failed;
1805 }
1806
Andre Guedes2519a1f2011-11-07 11:45:24 -03001807 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001808 if (err < 0)
1809 mgmt_pending_remove(cmd);
1810
1811failed:
1812 hci_dev_unlock_bh(hdev);
1813 hci_dev_put(hdev);
1814
1815 return err;
1816}
1817
1818static int stop_discovery(struct sock *sk, u16 index)
1819{
1820 struct hci_dev *hdev;
1821 struct pending_cmd *cmd;
1822 int err;
1823
1824 BT_DBG("hci%u", index);
1825
1826 hdev = hci_dev_get(index);
1827 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001828 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1829 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001830
1831 hci_dev_lock_bh(hdev);
1832
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001833 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001834 if (!cmd) {
1835 err = -ENOMEM;
1836 goto failed;
1837 }
1838
Andre Guedes023d50492011-11-04 14:16:52 -03001839 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001840 if (err < 0)
1841 mgmt_pending_remove(cmd);
1842
1843failed:
1844 hci_dev_unlock_bh(hdev);
1845 hci_dev_put(hdev);
1846
1847 return err;
1848}
1849
Antti Julku7fbec222011-06-15 12:01:15 +03001850static int block_device(struct sock *sk, u16 index, unsigned char *data,
1851 u16 len)
1852{
1853 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001854 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001855 int err;
1856
1857 BT_DBG("hci%u", index);
1858
Antti Julku7fbec222011-06-15 12:01:15 +03001859 if (len != sizeof(*cp))
1860 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001861 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001862
1863 hdev = hci_dev_get(index);
1864 if (!hdev)
1865 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001866 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001867
Antti Julku5e762442011-08-25 16:48:02 +03001868 hci_dev_lock_bh(hdev);
1869
Antti Julku7fbec222011-06-15 12:01:15 +03001870 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001871 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001872 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1873 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03001874 else
1875 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1876 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001877
Antti Julku5e762442011-08-25 16:48:02 +03001878 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001879 hci_dev_put(hdev);
1880
1881 return err;
1882}
1883
1884static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1885 u16 len)
1886{
1887 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001888 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001889 int err;
1890
1891 BT_DBG("hci%u", index);
1892
Antti Julku7fbec222011-06-15 12:01:15 +03001893 if (len != sizeof(*cp))
1894 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001895 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001896
1897 hdev = hci_dev_get(index);
1898 if (!hdev)
1899 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001900 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001901
Antti Julku5e762442011-08-25 16:48:02 +03001902 hci_dev_lock_bh(hdev);
1903
Antti Julku7fbec222011-06-15 12:01:15 +03001904 err = hci_blacklist_del(hdev, &cp->bdaddr);
1905
1906 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001907 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1908 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001909 else
1910 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1911 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001912
Antti Julku5e762442011-08-25 16:48:02 +03001913 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001914 hci_dev_put(hdev);
1915
1916 return err;
1917}
1918
Antti Julkuf6422ec2011-06-22 13:11:56 +03001919static int set_fast_connectable(struct sock *sk, u16 index,
1920 unsigned char *data, u16 len)
1921{
1922 struct hci_dev *hdev;
1923 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
1924 struct hci_cp_write_page_scan_activity acp;
1925 u8 type;
1926 int err;
1927
1928 BT_DBG("hci%u", index);
1929
1930 if (len != sizeof(*cp))
1931 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001932 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03001933
1934 hdev = hci_dev_get(index);
1935 if (!hdev)
1936 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001937 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03001938
1939 hci_dev_lock(hdev);
1940
1941 if (cp->enable) {
1942 type = PAGE_SCAN_TYPE_INTERLACED;
1943 acp.interval = 0x0024; /* 22.5 msec page scan interval */
1944 } else {
1945 type = PAGE_SCAN_TYPE_STANDARD; /* default */
1946 acp.interval = 0x0800; /* default 1.28 sec page scan */
1947 }
1948
1949 acp.window = 0x0012; /* default 11.25 msec page scan window */
1950
1951 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
1952 sizeof(acp), &acp);
1953 if (err < 0) {
1954 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001955 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03001956 goto done;
1957 }
1958
1959 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
1960 if (err < 0) {
1961 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001962 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03001963 goto done;
1964 }
1965
1966 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
1967 NULL, 0);
1968done:
1969 hci_dev_unlock(hdev);
1970 hci_dev_put(hdev);
1971
1972 return err;
1973}
1974
Johan Hedberg03811012010-12-08 00:21:06 +02001975int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
1976{
1977 unsigned char *buf;
1978 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001979 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02001980 int err;
1981
1982 BT_DBG("got %zu bytes", msglen);
1983
1984 if (msglen < sizeof(*hdr))
1985 return -EINVAL;
1986
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03001987 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02001988 if (!buf)
1989 return -ENOMEM;
1990
1991 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
1992 err = -EFAULT;
1993 goto done;
1994 }
1995
1996 hdr = (struct mgmt_hdr *) buf;
1997 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01001998 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02001999 len = get_unaligned_le16(&hdr->len);
2000
2001 if (len != msglen - sizeof(*hdr)) {
2002 err = -EINVAL;
2003 goto done;
2004 }
2005
2006 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002007 case MGMT_OP_READ_VERSION:
2008 err = read_version(sk);
2009 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002010 case MGMT_OP_READ_INDEX_LIST:
2011 err = read_index_list(sk);
2012 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002013 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002014 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002015 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002016 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002017 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002018 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002019 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002020 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002021 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002022 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002023 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002024 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002025 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002026 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002027 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002028 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002029 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002030 break;
2031 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002032 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002033 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002034 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002035 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002036 break;
2037 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002038 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002039 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002040 case MGMT_OP_LOAD_LINK_KEYS:
2041 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002042 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002043 case MGMT_OP_REMOVE_KEYS:
2044 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002045 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002046 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002047 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002048 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002049 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002050 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002051 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002052 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002053 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002054 break;
2055 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002056 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002057 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002058 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002059 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002060 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002061 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002062 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002063 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002064 case MGMT_OP_USER_CONFIRM_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002065 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 1);
Johan Hedberga5c29682011-02-19 12:05:57 -03002066 break;
2067 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002068 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len, 0);
Johan Hedberga5c29682011-02-19 12:05:57 -03002069 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002070 case MGMT_OP_SET_LOCAL_NAME:
2071 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2072 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002073 case MGMT_OP_READ_LOCAL_OOB_DATA:
2074 err = read_local_oob_data(sk, index);
2075 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002076 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2077 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2078 break;
2079 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2080 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2081 len);
2082 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002083 case MGMT_OP_START_DISCOVERY:
2084 err = start_discovery(sk, index);
2085 break;
2086 case MGMT_OP_STOP_DISCOVERY:
2087 err = stop_discovery(sk, index);
2088 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002089 case MGMT_OP_BLOCK_DEVICE:
2090 err = block_device(sk, index, buf + sizeof(*hdr), len);
2091 break;
2092 case MGMT_OP_UNBLOCK_DEVICE:
2093 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
2094 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002095 case MGMT_OP_SET_FAST_CONNECTABLE:
2096 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
2097 len);
2098 break;
Johan Hedberg03811012010-12-08 00:21:06 +02002099 default:
2100 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002101 err = cmd_status(sk, index, opcode,
2102 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg03811012010-12-08 00:21:06 +02002103 break;
2104 }
2105
Johan Hedberge41d8b42010-12-13 21:07:03 +02002106 if (err < 0)
2107 goto done;
2108
Johan Hedberg03811012010-12-08 00:21:06 +02002109 err = msglen;
2110
2111done:
2112 kfree(buf);
2113 return err;
2114}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002115
Johan Hedbergb24752f2011-11-03 14:40:33 +02002116static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2117{
2118 u8 *status = data;
2119
2120 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2121 mgmt_pending_remove(cmd);
2122}
2123
Johan Hedberg744cf192011-11-08 20:40:14 +02002124int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002125{
Johan Hedberg744cf192011-11-08 20:40:14 +02002126 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002127}
2128
Johan Hedberg744cf192011-11-08 20:40:14 +02002129int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002130{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002131 u8 status = ENODEV;
2132
Johan Hedberg744cf192011-11-08 20:40:14 +02002133 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002134
Johan Hedberg744cf192011-11-08 20:40:14 +02002135 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002136}
2137
Johan Hedberg73f22f62010-12-29 16:00:25 +02002138struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002139 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002140 struct sock *sk;
2141};
2142
Johan Hedberg72a734e2010-12-30 00:38:22 +02002143static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002144{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002145 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002146 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002147
Johan Hedberg72a734e2010-12-30 00:38:22 +02002148 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002149 return;
2150
Johan Hedberg053f0212011-01-26 13:07:10 +02002151 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002152
2153 list_del(&cmd->list);
2154
2155 if (match->sk == NULL) {
2156 match->sk = cmd->sk;
2157 sock_hold(match->sk);
2158 }
2159
2160 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002161}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002162
Johan Hedberg744cf192011-11-08 20:40:14 +02002163int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002164{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002165 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002166 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002167 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002168
Johan Hedberg744cf192011-11-08 20:40:14 +02002169 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002170
Johan Hedbergb24752f2011-11-03 14:40:33 +02002171 if (!powered) {
2172 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002173 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002174 }
2175
Johan Hedberg72a734e2010-12-30 00:38:22 +02002176 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002177
Johan Hedberg744cf192011-11-08 20:40:14 +02002178 ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002179
2180 if (match.sk)
2181 sock_put(match.sk);
2182
2183 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002184}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002185
Johan Hedberg744cf192011-11-08 20:40:14 +02002186int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002187{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002188 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002189 struct cmd_lookup match = { discoverable, NULL };
2190 int ret;
2191
Johan Hedberg744cf192011-11-08 20:40:14 +02002192 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002193
Johan Hedberg72a734e2010-12-30 00:38:22 +02002194 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002195
Johan Hedberg744cf192011-11-08 20:40:14 +02002196 ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002197 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002198
2199 if (match.sk)
2200 sock_put(match.sk);
2201
2202 return ret;
2203}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002204
Johan Hedberg744cf192011-11-08 20:40:14 +02002205int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002206{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002207 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002208 struct cmd_lookup match = { connectable, NULL };
2209 int ret;
2210
Johan Hedberg744cf192011-11-08 20:40:14 +02002211 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002212
Johan Hedberg72a734e2010-12-30 00:38:22 +02002213 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002214
Johan Hedberg744cf192011-11-08 20:40:14 +02002215 ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002216
2217 if (match.sk)
2218 sock_put(match.sk);
2219
2220 return ret;
2221}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002222
Johan Hedberg744cf192011-11-08 20:40:14 +02002223int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002224{
Johan Hedbergca69b792011-11-11 18:10:00 +02002225 u8 mgmt_err = mgmt_status(status);
2226
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002227 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002228 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002229 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002230
2231 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002232 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002233 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002234
2235 return 0;
2236}
2237
Johan Hedberg744cf192011-11-08 20:40:14 +02002238int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2239 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002240{
Johan Hedberg86742e12011-11-07 23:13:38 +02002241 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002242
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002243 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002244
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002245 ev.store_hint = persistent;
2246 bacpy(&ev.key.bdaddr, &key->bdaddr);
2247 ev.key.type = key->type;
2248 memcpy(ev.key.val, key->val, 16);
2249 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002250
Johan Hedberg744cf192011-11-08 20:40:14 +02002251 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002252}
Johan Hedbergf7520542011-01-20 12:34:39 +02002253
Johan Hedberg48264f02011-11-09 13:58:58 +02002254int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2255 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002256{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002257 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002258
Johan Hedbergf7520542011-01-20 12:34:39 +02002259 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002260 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002261
Johan Hedberg744cf192011-11-08 20:40:14 +02002262 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002263}
2264
Johan Hedberg8962ee72011-01-20 12:40:27 +02002265static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2266{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002267 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002268 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002269 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002270
Johan Hedberga38528f2011-01-22 06:46:43 +02002271 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002272 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002273
Szymon Janc4e51eae2011-02-25 19:05:48 +01002274 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002275
2276 *sk = cmd->sk;
2277 sock_hold(*sk);
2278
Johan Hedberga664b5b2011-02-19 12:06:02 -03002279 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002280}
2281
Johan Hedberga8a1d192011-11-10 15:54:38 +02002282static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2283{
2284 u8 *status = data;
2285 struct mgmt_cp_remove_keys *cp = cmd->param;
2286 struct mgmt_rp_remove_keys rp;
2287
2288 memset(&rp, 0, sizeof(rp));
2289 bacpy(&rp.bdaddr, &cp->bdaddr);
2290 if (status != NULL)
2291 rp.status = *status;
2292
2293 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2294 sizeof(rp));
2295
2296 mgmt_pending_remove(cmd);
2297}
2298
Johan Hedberg48264f02011-11-09 13:58:58 +02002299int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2300 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002301{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002302 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002303 struct sock *sk = NULL;
2304 int err;
2305
Johan Hedberg744cf192011-11-08 20:40:14 +02002306 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002307
Johan Hedbergf7520542011-01-20 12:34:39 +02002308 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002309 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002310
Johan Hedberg744cf192011-11-08 20:40:14 +02002311 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002312
2313 if (sk)
2314 sock_put(sk);
2315
Johan Hedberga8a1d192011-11-10 15:54:38 +02002316 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2317
Johan Hedberg8962ee72011-01-20 12:40:27 +02002318 return err;
2319}
2320
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002321int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002322{
2323 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002324 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002325 int err;
2326
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002327 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002328 if (!cmd)
2329 return -ENOENT;
2330
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002331 if (bdaddr) {
2332 struct mgmt_rp_disconnect rp;
2333
2334 bacpy(&rp.bdaddr, bdaddr);
2335 rp.status = status;
2336
2337 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2338 &rp, sizeof(rp));
2339 } else
2340 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002341 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002342
Johan Hedberga664b5b2011-02-19 12:06:02 -03002343 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002344
2345 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002346}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002347
Johan Hedberg48264f02011-11-09 13:58:58 +02002348int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2349 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002350{
2351 struct mgmt_ev_connect_failed ev;
2352
Johan Hedberg4c659c32011-11-07 23:13:39 +02002353 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002354 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002355 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002356
Johan Hedberg744cf192011-11-08 20:40:14 +02002357 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002358}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002359
Johan Hedberg744cf192011-11-08 20:40:14 +02002360int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002361{
2362 struct mgmt_ev_pin_code_request ev;
2363
Johan Hedberg980e1a52011-01-22 06:10:07 +02002364 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002365 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002366
Johan Hedberg744cf192011-11-08 20:40:14 +02002367 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002368 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002369}
2370
Johan Hedberg744cf192011-11-08 20:40:14 +02002371int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2372 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002373{
2374 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002375 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002376 int err;
2377
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002378 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002379 if (!cmd)
2380 return -ENOENT;
2381
Johan Hedbergac56fb12011-02-19 12:05:59 -03002382 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002383 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002384
Johan Hedberg744cf192011-11-08 20:40:14 +02002385 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002386 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002387
Johan Hedberga664b5b2011-02-19 12:06:02 -03002388 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002389
2390 return err;
2391}
2392
Johan Hedberg744cf192011-11-08 20:40:14 +02002393int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2394 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002395{
2396 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002397 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002398 int err;
2399
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002400 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002401 if (!cmd)
2402 return -ENOENT;
2403
Johan Hedbergac56fb12011-02-19 12:05:59 -03002404 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002405 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002406
Johan Hedberg744cf192011-11-08 20:40:14 +02002407 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002408 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002409
Johan Hedberga664b5b2011-02-19 12:06:02 -03002410 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002411
2412 return err;
2413}
Johan Hedberga5c29682011-02-19 12:05:57 -03002414
Johan Hedberg744cf192011-11-08 20:40:14 +02002415int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2416 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002417{
2418 struct mgmt_ev_user_confirm_request ev;
2419
Johan Hedberg744cf192011-11-08 20:40:14 +02002420 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002421
Johan Hedberga5c29682011-02-19 12:05:57 -03002422 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002423 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002424 put_unaligned_le32(value, &ev.value);
2425
Johan Hedberg744cf192011-11-08 20:40:14 +02002426 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002427 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002428}
2429
Johan Hedberg744cf192011-11-08 20:40:14 +02002430static int confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2431 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002432{
2433 struct pending_cmd *cmd;
2434 struct mgmt_rp_user_confirm_reply rp;
2435 int err;
2436
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002437 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002438 if (!cmd)
2439 return -ENOENT;
2440
Johan Hedberga5c29682011-02-19 12:05:57 -03002441 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002442 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002443 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002444
Johan Hedberga664b5b2011-02-19 12:06:02 -03002445 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002446
2447 return err;
2448}
2449
Johan Hedberg744cf192011-11-08 20:40:14 +02002450int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2451 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002452{
Johan Hedbergca69b792011-11-11 18:10:00 +02002453 return confirm_reply_complete(hdev, bdaddr, mgmt_status(status),
Johan Hedberga5c29682011-02-19 12:05:57 -03002454 MGMT_OP_USER_CONFIRM_REPLY);
2455}
2456
Johan Hedberg744cf192011-11-08 20:40:14 +02002457int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2458 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002459{
Johan Hedbergca69b792011-11-11 18:10:00 +02002460 return confirm_reply_complete(hdev, bdaddr, mgmt_status(status),
Johan Hedberga5c29682011-02-19 12:05:57 -03002461 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2462}
Johan Hedberg2a611692011-02-19 12:06:00 -03002463
Johan Hedberg744cf192011-11-08 20:40:14 +02002464int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002465{
2466 struct mgmt_ev_auth_failed ev;
2467
Johan Hedberg2a611692011-02-19 12:06:00 -03002468 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002469 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002470
Johan Hedberg744cf192011-11-08 20:40:14 +02002471 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002472}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002473
Johan Hedberg744cf192011-11-08 20:40:14 +02002474int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002475{
2476 struct pending_cmd *cmd;
2477 struct mgmt_cp_set_local_name ev;
2478 int err;
2479
2480 memset(&ev, 0, sizeof(ev));
2481 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2482
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002483 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002484 if (!cmd)
2485 goto send_event;
2486
2487 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002488 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002489 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002490 goto failed;
2491 }
2492
Johan Hedberg744cf192011-11-08 20:40:14 +02002493 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002494
Johan Hedberg744cf192011-11-08 20:40:14 +02002495 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002496 sizeof(ev));
2497 if (err < 0)
2498 goto failed;
2499
2500send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002501 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002502 cmd ? cmd->sk : NULL);
2503
2504failed:
2505 if (cmd)
2506 mgmt_pending_remove(cmd);
2507 return err;
2508}
Szymon Jancc35938b2011-03-22 13:12:21 +01002509
Johan Hedberg744cf192011-11-08 20:40:14 +02002510int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2511 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002512{
2513 struct pending_cmd *cmd;
2514 int err;
2515
Johan Hedberg744cf192011-11-08 20:40:14 +02002516 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002517
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002518 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002519 if (!cmd)
2520 return -ENOENT;
2521
2522 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002523 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002524 MGMT_OP_READ_LOCAL_OOB_DATA,
2525 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002526 } else {
2527 struct mgmt_rp_read_local_oob_data rp;
2528
2529 memcpy(rp.hash, hash, sizeof(rp.hash));
2530 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2531
Johan Hedberg744cf192011-11-08 20:40:14 +02002532 err = cmd_complete(cmd->sk, hdev->id,
2533 MGMT_OP_READ_LOCAL_OOB_DATA,
2534 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002535 }
2536
2537 mgmt_pending_remove(cmd);
2538
2539 return err;
2540}
Johan Hedberge17acd42011-03-30 23:57:16 +03002541
Johan Hedberg48264f02011-11-09 13:58:58 +02002542int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2543 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002544{
2545 struct mgmt_ev_device_found ev;
2546
2547 memset(&ev, 0, sizeof(ev));
2548
Johan Hedberg4c659c32011-11-07 23:13:39 +02002549 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002550 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002551 ev.rssi = rssi;
2552
2553 if (eir)
2554 memcpy(ev.eir, eir, sizeof(ev.eir));
2555
Andre Guedesf8523592011-09-09 18:56:26 -03002556 if (dev_class)
2557 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2558
Johan Hedberg744cf192011-11-08 20:40:14 +02002559 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002560}
Johan Hedberga88a9652011-03-30 13:18:12 +03002561
Johan Hedberg744cf192011-11-08 20:40:14 +02002562int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002563{
2564 struct mgmt_ev_remote_name ev;
2565
2566 memset(&ev, 0, sizeof(ev));
2567
2568 bacpy(&ev.bdaddr, bdaddr);
2569 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2570
Johan Hedberg744cf192011-11-08 20:40:14 +02002571 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002572}
Johan Hedberg314b2382011-04-27 10:29:57 -04002573
Andre Guedes7a135102011-11-09 17:14:25 -03002574int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002575{
2576 struct pending_cmd *cmd;
2577 int err;
2578
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002579 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002580 if (!cmd)
2581 return -ENOENT;
2582
Johan Hedbergca69b792011-11-11 18:10:00 +02002583 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002584 mgmt_pending_remove(cmd);
2585
2586 return err;
2587}
2588
Andre Guedese6d465c2011-11-09 17:14:26 -03002589int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2590{
2591 struct pending_cmd *cmd;
2592 int err;
2593
2594 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2595 if (!cmd)
2596 return -ENOENT;
2597
2598 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
2599 mgmt_pending_remove(cmd);
2600
2601 return err;
2602}
2603
Johan Hedberg744cf192011-11-08 20:40:14 +02002604int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002605{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002606 struct pending_cmd *cmd;
2607
2608 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002609 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002610 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002611 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002612
2613 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002614 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002615 mgmt_pending_remove(cmd);
2616 }
2617
Johan Hedberg744cf192011-11-08 20:40:14 +02002618 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002619 sizeof(discovering), NULL);
2620}
Antti Julku5e762442011-08-25 16:48:02 +03002621
Johan Hedberg744cf192011-11-08 20:40:14 +02002622int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002623{
2624 struct pending_cmd *cmd;
2625 struct mgmt_ev_device_blocked ev;
2626
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002627 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002628
2629 bacpy(&ev.bdaddr, bdaddr);
2630
Johan Hedberg744cf192011-11-08 20:40:14 +02002631 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2632 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002633}
2634
Johan Hedberg744cf192011-11-08 20:40:14 +02002635int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002636{
2637 struct pending_cmd *cmd;
2638 struct mgmt_ev_device_unblocked ev;
2639
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002640 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002641
2642 bacpy(&ev.bdaddr, bdaddr);
2643
Johan Hedberg744cf192011-11-08 20:40:14 +02002644 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2645 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002646}