blob: ffd1c01c7d0ec4fb0134781bddcab8a46680d58b [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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300260 hci_dev_lock(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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300289 hci_dev_unlock(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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300397 hci_dev_lock(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)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200418 schedule_work(&hdev->power_on);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200419 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200420 schedule_work(&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:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300425 hci_dev_unlock(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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300452 hci_dev_lock(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:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300495 hci_dev_unlock(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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300523 hci_dev_lock(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:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300560 hci_dev_unlock(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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300615 hci_dev_lock(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:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300631 hci_dev_unlock(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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300830 hci_dev_lock(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:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300854 hci_dev_unlock(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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300881 hci_dev_lock(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:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300917 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200918 hci_dev_put(hdev);
919
920 return err;
921}
922
Szymon Janc4e51eae2011-02-25 19:05:48 +0100923static int 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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300943 hci_dev_lock(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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300953 hci_dev_unlock(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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300977 hci_dev_lock(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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300998 hci_dev_unlock(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
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001037 hci_dev_lock(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
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001055 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1056
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001057 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001058 hci_dev_put(hdev);
1059
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001060 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001061}
1062
Johan Hedberg86742e12011-11-07 23:13:38 +02001063static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
1064 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001065{
1066 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001067 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001068 struct mgmt_rp_remove_keys rp;
1069 struct hci_cp_disconnect dc;
1070 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001071 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001072 int err;
1073
1074 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001075
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001076 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001077 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1078 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001079
Szymon Janc4e51eae2011-02-25 19:05:48 +01001080 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001081 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001082 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1083 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001084
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001085 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001086
Johan Hedberga8a1d192011-11-10 15:54:38 +02001087 memset(&rp, 0, sizeof(rp));
1088 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001089 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001090
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001091 err = hci_remove_link_key(hdev, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001092 if (err < 0) {
1093 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001094 goto unlock;
Johan Hedbergca69b792011-11-11 18:10:00 +02001095 }
Johan Hedberga8a1d192011-11-10 15:54:38 +02001096
1097 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1098 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1099 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001100 goto unlock;
1101 }
1102
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001103 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001104 if (!conn) {
1105 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1106 sizeof(rp));
1107 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001108 }
1109
Johan Hedberga8a1d192011-11-10 15:54:38 +02001110 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1111 if (!cmd) {
1112 err = -ENOMEM;
1113 goto unlock;
1114 }
1115
1116 put_unaligned_le16(conn->handle, &dc.handle);
1117 dc.reason = 0x13; /* Remote User Terminated Connection */
1118 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1119 if (err < 0)
1120 mgmt_pending_remove(cmd);
1121
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001122unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001123 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001124 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1125 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001126 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001127 hci_dev_put(hdev);
1128
1129 return err;
1130}
1131
Szymon Janc4e51eae2011-02-25 19:05:48 +01001132static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001133{
1134 struct hci_dev *hdev;
1135 struct mgmt_cp_disconnect *cp;
1136 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001137 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001138 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001139 int err;
1140
1141 BT_DBG("");
1142
1143 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001144
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001145 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001146 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1147 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001148
Szymon Janc4e51eae2011-02-25 19:05:48 +01001149 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001150 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001151 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1152 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001153
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001154 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001155
1156 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001157 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1158 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001159 goto failed;
1160 }
1161
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001162 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001163 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1164 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001165 goto failed;
1166 }
1167
1168 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001169 if (!conn)
1170 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1171
Johan Hedberg8962ee72011-01-20 12:40:27 +02001172 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001173 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1174 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001175 goto failed;
1176 }
1177
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001178 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001179 if (!cmd) {
1180 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001181 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001182 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001183
1184 put_unaligned_le16(conn->handle, &dc.handle);
1185 dc.reason = 0x13; /* Remote User Terminated Connection */
1186
1187 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1188 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001189 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001190
1191failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001192 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001193 hci_dev_put(hdev);
1194
1195 return err;
1196}
1197
Johan Hedberg48264f02011-11-09 13:58:58 +02001198static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001199{
1200 switch (link_type) {
1201 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001202 switch (addr_type) {
1203 case ADDR_LE_DEV_PUBLIC:
1204 return MGMT_ADDR_LE_PUBLIC;
1205 case ADDR_LE_DEV_RANDOM:
1206 return MGMT_ADDR_LE_RANDOM;
1207 default:
1208 return MGMT_ADDR_INVALID;
1209 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001210 case ACL_LINK:
1211 return MGMT_ADDR_BREDR;
1212 default:
1213 return MGMT_ADDR_INVALID;
1214 }
1215}
1216
Szymon Janc8ce62842011-03-01 16:55:32 +01001217static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001218{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001219 struct mgmt_rp_get_connections *rp;
1220 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001221 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001222 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001223 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001224 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001225 int i, err;
1226
1227 BT_DBG("");
1228
Szymon Janc4e51eae2011-02-25 19:05:48 +01001229 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001230 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001231 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1232 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001233
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001234 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001235
1236 count = 0;
1237 list_for_each(p, &hdev->conn_hash.list) {
1238 count++;
1239 }
1240
Johan Hedberg4c659c32011-11-07 23:13:39 +02001241 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001242 rp = kmalloc(rp_len, GFP_ATOMIC);
1243 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001244 err = -ENOMEM;
1245 goto unlock;
1246 }
1247
Johan Hedberg2784eb42011-01-21 13:56:35 +02001248 put_unaligned_le16(count, &rp->conn_count);
1249
Johan Hedberg2784eb42011-01-21 13:56:35 +02001250 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001251 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1252 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001253 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001254 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1255 continue;
1256 i++;
1257 }
1258
1259 /* Recalculate length in case of filtered SCO connections, etc */
1260 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001261
Szymon Janc4e51eae2011-02-25 19:05:48 +01001262 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001263
1264unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001265 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001266 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001267 hci_dev_put(hdev);
1268 return err;
1269}
1270
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001271static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1272 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1273{
1274 struct pending_cmd *cmd;
1275 int err;
1276
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001277 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001278 sizeof(*cp));
1279 if (!cmd)
1280 return -ENOMEM;
1281
1282 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1283 &cp->bdaddr);
1284 if (err < 0)
1285 mgmt_pending_remove(cmd);
1286
1287 return err;
1288}
1289
Szymon Janc4e51eae2011-02-25 19:05:48 +01001290static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1291 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001292{
1293 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001294 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001295 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001296 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001297 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001298 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001299 int err;
1300
1301 BT_DBG("");
1302
1303 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001304
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001305 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001306 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1307 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001308
Szymon Janc4e51eae2011-02-25 19:05:48 +01001309 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001310 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001311 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1312 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001313
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001314 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001315
1316 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001317 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1318 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001319 goto failed;
1320 }
1321
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001322 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1323 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001324 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1325 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001326 goto failed;
1327 }
1328
1329 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1330 bacpy(&ncp.bdaddr, &cp->bdaddr);
1331
1332 BT_ERR("PIN code is not 16 bytes long");
1333
1334 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1335 if (err >= 0)
1336 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001337 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001338
1339 goto failed;
1340 }
1341
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001342 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001343 if (!cmd) {
1344 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001345 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001346 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001347
1348 bacpy(&reply.bdaddr, &cp->bdaddr);
1349 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001350 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001351
1352 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1353 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001354 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001355
1356failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001357 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001358 hci_dev_put(hdev);
1359
1360 return err;
1361}
1362
Szymon Janc4e51eae2011-02-25 19:05:48 +01001363static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1364 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001365{
1366 struct hci_dev *hdev;
1367 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001368 int err;
1369
1370 BT_DBG("");
1371
1372 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001373
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001374 if (len != sizeof(*cp))
1375 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001376 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001377
Szymon Janc4e51eae2011-02-25 19:05:48 +01001378 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001379 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001380 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001381 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001382
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001383 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001384
1385 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001386 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001387 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001388 goto failed;
1389 }
1390
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001391 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001392
1393failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001394 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001395 hci_dev_put(hdev);
1396
1397 return err;
1398}
1399
Szymon Janc4e51eae2011-02-25 19:05:48 +01001400static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1401 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001402{
1403 struct hci_dev *hdev;
1404 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001405
1406 BT_DBG("");
1407
1408 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001409
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001410 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001411 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1412 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001413
Szymon Janc4e51eae2011-02-25 19:05:48 +01001414 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001415 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001416 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1417 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001418
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001419 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001420
1421 hdev->io_capability = cp->io_capability;
1422
1423 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001424 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001425
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001426 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001427 hci_dev_put(hdev);
1428
Szymon Janc4e51eae2011-02-25 19:05:48 +01001429 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001430}
1431
Johan Hedberge9a416b2011-02-19 12:05:56 -03001432static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1433{
1434 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001435 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001436
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001437 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001438 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1439 continue;
1440
Johan Hedberge9a416b2011-02-19 12:05:56 -03001441 if (cmd->user_data != conn)
1442 continue;
1443
1444 return cmd;
1445 }
1446
1447 return NULL;
1448}
1449
1450static void pairing_complete(struct pending_cmd *cmd, u8 status)
1451{
1452 struct mgmt_rp_pair_device rp;
1453 struct hci_conn *conn = cmd->user_data;
1454
Johan Hedbergba4e5642011-11-11 00:07:34 +02001455 bacpy(&rp.addr.bdaddr, &conn->dst);
1456 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001457 rp.status = status;
1458
Szymon Janc4e51eae2011-02-25 19:05:48 +01001459 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001460
1461 /* So we don't get further callbacks for this connection */
1462 conn->connect_cfm_cb = NULL;
1463 conn->security_cfm_cb = NULL;
1464 conn->disconn_cfm_cb = NULL;
1465
1466 hci_conn_put(conn);
1467
Johan Hedberga664b5b2011-02-19 12:06:02 -03001468 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001469}
1470
1471static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1472{
1473 struct pending_cmd *cmd;
1474
1475 BT_DBG("status %u", status);
1476
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001477 cmd = find_pairing(conn);
1478 if (!cmd)
1479 BT_DBG("Unable to find a pending command");
1480 else
1481 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001482}
1483
Szymon Janc4e51eae2011-02-25 19:05:48 +01001484static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001485{
1486 struct hci_dev *hdev;
1487 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001488 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001489 struct pending_cmd *cmd;
1490 u8 sec_level, auth_type;
1491 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001492 int err;
1493
1494 BT_DBG("");
1495
1496 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001497
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001498 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001499 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1500 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001501
Szymon Janc4e51eae2011-02-25 19:05:48 +01001502 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001503 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001504 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1505 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001506
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001507 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001508
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001509 sec_level = BT_SECURITY_MEDIUM;
1510 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001511 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001512 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001513 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001514
Johan Hedbergba4e5642011-11-11 00:07:34 +02001515 if (cp->addr.type == MGMT_ADDR_BREDR)
1516 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001517 auth_type);
1518 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001519 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001520 auth_type);
1521
Johan Hedberg1425acb2011-11-11 00:07:35 +02001522 memset(&rp, 0, sizeof(rp));
1523 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1524 rp.addr.type = cp->addr.type;
1525
Ville Tervo30e76272011-02-22 16:10:53 -03001526 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001527 rp.status = -PTR_ERR(conn);
1528 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1529 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001530 goto unlock;
1531 }
1532
1533 if (conn->connect_cfm_cb) {
1534 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001535 rp.status = EBUSY;
1536 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1537 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001538 goto unlock;
1539 }
1540
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001541 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001542 if (!cmd) {
1543 err = -ENOMEM;
1544 hci_conn_put(conn);
1545 goto unlock;
1546 }
1547
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001548 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001549 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001550 conn->connect_cfm_cb = pairing_complete_cb;
1551
Johan Hedberge9a416b2011-02-19 12:05:56 -03001552 conn->security_cfm_cb = pairing_complete_cb;
1553 conn->disconn_cfm_cb = pairing_complete_cb;
1554 conn->io_capability = cp->io_cap;
1555 cmd->user_data = conn;
1556
1557 if (conn->state == BT_CONNECTED &&
1558 hci_conn_security(conn, sec_level, auth_type))
1559 pairing_complete(cmd, 0);
1560
1561 err = 0;
1562
1563unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001564 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001565 hci_dev_put(hdev);
1566
1567 return err;
1568}
1569
Brian Gix0df4c182011-11-16 13:53:13 -08001570static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1571 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001572{
Johan Hedberga5c29682011-02-19 12:05:57 -03001573 struct pending_cmd *cmd;
1574 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001575 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001576 int err;
1577
Szymon Janc4e51eae2011-02-25 19:05:48 +01001578 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001579 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001580 return cmd_status(sk, index, mgmt_op,
1581 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001582
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001583 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001584
Johan Hedberga5c29682011-02-19 12:05:57 -03001585 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001586 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1587 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001588 }
1589
Brian Gix47c15e22011-11-16 13:53:14 -08001590 /*
1591 * Check for an existing ACL link, if present pair via
1592 * HCI commands.
1593 *
1594 * If no ACL link is present, check for an LE link and if
1595 * present, pair via the SMP engine.
1596 *
1597 * If neither ACL nor LE links are present, fail with error.
1598 */
1599 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1600 if (!conn) {
1601 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1602 if (!conn) {
1603 err = cmd_status(sk, index, mgmt_op,
1604 MGMT_STATUS_NOT_CONNECTED);
1605 goto done;
1606 }
1607
1608 /* Continue with pairing via SMP */
1609
1610 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_SUCCESS);
1611 goto done;
1612 }
1613
Brian Gix0df4c182011-11-16 13:53:13 -08001614 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001615 if (!cmd) {
1616 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001617 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001618 }
1619
Brian Gix0df4c182011-11-16 13:53:13 -08001620 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001621 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1622 struct hci_cp_user_passkey_reply cp;
1623
1624 bacpy(&cp.bdaddr, bdaddr);
1625 cp.passkey = passkey;
1626 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1627 } else
1628 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1629
Johan Hedberga664b5b2011-02-19 12:06:02 -03001630 if (err < 0)
1631 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001632
Brian Gix0df4c182011-11-16 13:53:13 -08001633done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001634 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001635 hci_dev_put(hdev);
1636
1637 return err;
1638}
1639
Brian Gix0df4c182011-11-16 13:53:13 -08001640static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1641{
1642 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1643
1644 BT_DBG("");
1645
1646 if (len != sizeof(*cp))
1647 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1648 MGMT_STATUS_INVALID_PARAMS);
1649
1650 return user_pairing_resp(sk, index, &cp->bdaddr,
1651 MGMT_OP_USER_CONFIRM_REPLY,
1652 HCI_OP_USER_CONFIRM_REPLY, 0);
1653}
1654
1655static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1656 u16 len)
1657{
1658 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1659
1660 BT_DBG("");
1661
1662 if (len != sizeof(*cp))
1663 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1664 MGMT_STATUS_INVALID_PARAMS);
1665
1666 return user_pairing_resp(sk, index, &cp->bdaddr,
1667 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1668 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1669}
1670
Brian Gix604086b2011-11-23 08:28:33 -08001671static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1672{
1673 struct mgmt_cp_user_passkey_reply *cp = (void *) data;
1674
1675 BT_DBG("");
1676
1677 if (len != sizeof(*cp))
1678 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1679 EINVAL);
1680
1681 return user_pairing_resp(sk, index, &cp->bdaddr,
1682 MGMT_OP_USER_PASSKEY_REPLY,
1683 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1684}
1685
1686static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1687 u16 len)
1688{
1689 struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data;
1690
1691 BT_DBG("");
1692
1693 if (len != sizeof(*cp))
1694 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1695 EINVAL);
1696
1697 return user_pairing_resp(sk, index, &cp->bdaddr,
1698 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1699 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1700}
1701
Johan Hedbergb312b1612011-03-16 14:29:37 +02001702static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1703 u16 len)
1704{
1705 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1706 struct hci_cp_write_local_name hci_cp;
1707 struct hci_dev *hdev;
1708 struct pending_cmd *cmd;
1709 int err;
1710
1711 BT_DBG("");
1712
1713 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001714 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1715 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001716
1717 hdev = hci_dev_get(index);
1718 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001719 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1720 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001721
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001722 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001723
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001724 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001725 if (!cmd) {
1726 err = -ENOMEM;
1727 goto failed;
1728 }
1729
1730 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1731 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1732 &hci_cp);
1733 if (err < 0)
1734 mgmt_pending_remove(cmd);
1735
1736failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001737 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001738 hci_dev_put(hdev);
1739
1740 return err;
1741}
1742
Szymon Jancc35938b2011-03-22 13:12:21 +01001743static int read_local_oob_data(struct sock *sk, u16 index)
1744{
1745 struct hci_dev *hdev;
1746 struct pending_cmd *cmd;
1747 int err;
1748
1749 BT_DBG("hci%u", index);
1750
1751 hdev = hci_dev_get(index);
1752 if (!hdev)
1753 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001754 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001755
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001756 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001757
1758 if (!test_bit(HCI_UP, &hdev->flags)) {
1759 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001760 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001761 goto unlock;
1762 }
1763
1764 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1765 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001766 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001767 goto unlock;
1768 }
1769
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001770 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001771 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1772 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001773 goto unlock;
1774 }
1775
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001776 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001777 if (!cmd) {
1778 err = -ENOMEM;
1779 goto unlock;
1780 }
1781
1782 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1783 if (err < 0)
1784 mgmt_pending_remove(cmd);
1785
1786unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001787 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001788 hci_dev_put(hdev);
1789
1790 return err;
1791}
1792
Szymon Janc2763eda2011-03-22 13:12:22 +01001793static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1794 u16 len)
1795{
1796 struct hci_dev *hdev;
1797 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1798 int err;
1799
1800 BT_DBG("hci%u ", index);
1801
1802 if (len != sizeof(*cp))
1803 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001804 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001805
1806 hdev = hci_dev_get(index);
1807 if (!hdev)
1808 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001809 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001811 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001812
1813 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1814 cp->randomizer);
1815 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001816 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1817 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001818 else
1819 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1820 0);
1821
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001822 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001823 hci_dev_put(hdev);
1824
1825 return err;
1826}
1827
1828static int remove_remote_oob_data(struct sock *sk, u16 index,
1829 unsigned char *data, u16 len)
1830{
1831 struct hci_dev *hdev;
1832 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1833 int err;
1834
1835 BT_DBG("hci%u ", index);
1836
1837 if (len != sizeof(*cp))
1838 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001839 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001840
1841 hdev = hci_dev_get(index);
1842 if (!hdev)
1843 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001844 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001845
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001846 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001847
1848 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1849 if (err < 0)
1850 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001851 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001852 else
1853 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1854 NULL, 0);
1855
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001856 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001857 hci_dev_put(hdev);
1858
1859 return err;
1860}
1861
Johan Hedberg450dfda2011-11-12 11:58:22 +02001862static int start_discovery(struct sock *sk, u16 index,
1863 unsigned char *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001864{
Johan Hedberg450dfda2011-11-12 11:58:22 +02001865 struct mgmt_cp_start_discovery *cp = (void *) data;
Johan Hedberg14a53662011-04-27 10:29:56 -04001866 struct pending_cmd *cmd;
1867 struct hci_dev *hdev;
1868 int err;
1869
1870 BT_DBG("hci%u", index);
1871
Johan Hedberg450dfda2011-11-12 11:58:22 +02001872 if (len != sizeof(*cp))
1873 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1874 MGMT_STATUS_INVALID_PARAMS);
1875
Johan Hedberg14a53662011-04-27 10:29:56 -04001876 hdev = hci_dev_get(index);
1877 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001878 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1879 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001880
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001881 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001882
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001883 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001884 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1885 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001886 goto failed;
1887 }
1888
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001889 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001890 if (!cmd) {
1891 err = -ENOMEM;
1892 goto failed;
1893 }
1894
Andre Guedes2519a1f2011-11-07 11:45:24 -03001895 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001896 if (err < 0)
1897 mgmt_pending_remove(cmd);
1898
1899failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001900 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001901 hci_dev_put(hdev);
1902
1903 return err;
1904}
1905
1906static int stop_discovery(struct sock *sk, u16 index)
1907{
1908 struct hci_dev *hdev;
1909 struct pending_cmd *cmd;
1910 int err;
1911
1912 BT_DBG("hci%u", index);
1913
1914 hdev = hci_dev_get(index);
1915 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001916 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1917 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001918
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001919 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001920
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001921 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001922 if (!cmd) {
1923 err = -ENOMEM;
1924 goto failed;
1925 }
1926
Andre Guedes023d50492011-11-04 14:16:52 -03001927 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001928 if (err < 0)
1929 mgmt_pending_remove(cmd);
1930
1931failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001932 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001933 hci_dev_put(hdev);
1934
1935 return err;
1936}
1937
Antti Julku7fbec222011-06-15 12:01:15 +03001938static int block_device(struct sock *sk, u16 index, unsigned char *data,
1939 u16 len)
1940{
1941 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001942 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001943 int err;
1944
1945 BT_DBG("hci%u", index);
1946
Antti Julku7fbec222011-06-15 12:01:15 +03001947 if (len != sizeof(*cp))
1948 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001949 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001950
1951 hdev = hci_dev_get(index);
1952 if (!hdev)
1953 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001954 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001955
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001956 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03001957
Antti Julku7fbec222011-06-15 12:01:15 +03001958 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001959 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001960 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1961 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03001962 else
1963 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1964 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001965
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001966 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001967 hci_dev_put(hdev);
1968
1969 return err;
1970}
1971
1972static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1973 u16 len)
1974{
1975 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001976 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001977 int err;
1978
1979 BT_DBG("hci%u", index);
1980
Antti Julku7fbec222011-06-15 12:01:15 +03001981 if (len != sizeof(*cp))
1982 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001983 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001984
1985 hdev = hci_dev_get(index);
1986 if (!hdev)
1987 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001988 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001989
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001990 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03001991
Antti Julku7fbec222011-06-15 12:01:15 +03001992 err = hci_blacklist_del(hdev, &cp->bdaddr);
1993
1994 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001995 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1996 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001997 else
1998 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1999 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002000
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002001 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002002 hci_dev_put(hdev);
2003
2004 return err;
2005}
2006
Antti Julkuf6422ec2011-06-22 13:11:56 +03002007static int set_fast_connectable(struct sock *sk, u16 index,
2008 unsigned char *data, u16 len)
2009{
2010 struct hci_dev *hdev;
2011 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
2012 struct hci_cp_write_page_scan_activity acp;
2013 u8 type;
2014 int err;
2015
2016 BT_DBG("hci%u", index);
2017
2018 if (len != sizeof(*cp))
2019 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002020 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002021
2022 hdev = hci_dev_get(index);
2023 if (!hdev)
2024 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002025 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002026
2027 hci_dev_lock(hdev);
2028
2029 if (cp->enable) {
2030 type = PAGE_SCAN_TYPE_INTERLACED;
2031 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2032 } else {
2033 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2034 acp.interval = 0x0800; /* default 1.28 sec page scan */
2035 }
2036
2037 acp.window = 0x0012; /* default 11.25 msec page scan window */
2038
2039 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2040 sizeof(acp), &acp);
2041 if (err < 0) {
2042 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002043 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002044 goto done;
2045 }
2046
2047 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2048 if (err < 0) {
2049 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002050 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002051 goto done;
2052 }
2053
2054 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2055 NULL, 0);
2056done:
2057 hci_dev_unlock(hdev);
2058 hci_dev_put(hdev);
2059
2060 return err;
2061}
2062
Johan Hedberg03811012010-12-08 00:21:06 +02002063int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2064{
2065 unsigned char *buf;
2066 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002067 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002068 int err;
2069
2070 BT_DBG("got %zu bytes", msglen);
2071
2072 if (msglen < sizeof(*hdr))
2073 return -EINVAL;
2074
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002075 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002076 if (!buf)
2077 return -ENOMEM;
2078
2079 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2080 err = -EFAULT;
2081 goto done;
2082 }
2083
2084 hdr = (struct mgmt_hdr *) buf;
2085 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002086 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002087 len = get_unaligned_le16(&hdr->len);
2088
2089 if (len != msglen - sizeof(*hdr)) {
2090 err = -EINVAL;
2091 goto done;
2092 }
2093
2094 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002095 case MGMT_OP_READ_VERSION:
2096 err = read_version(sk);
2097 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002098 case MGMT_OP_READ_INDEX_LIST:
2099 err = read_index_list(sk);
2100 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002101 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002102 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002103 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002104 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002105 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002106 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002107 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002108 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002109 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002110 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002111 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002112 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002113 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002114 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002115 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002116 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002117 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002118 break;
2119 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002120 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002121 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002122 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002123 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002124 break;
2125 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002126 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002127 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002128 case MGMT_OP_LOAD_LINK_KEYS:
2129 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002130 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002131 case MGMT_OP_REMOVE_KEYS:
2132 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002133 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002134 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002135 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002136 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002137 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002138 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002139 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002140 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002141 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002142 break;
2143 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002144 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002145 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002146 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002147 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002148 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002149 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002150 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002151 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002152 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002153 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002154 break;
2155 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002156 err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr),
2157 len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002158 break;
Brian Gix604086b2011-11-23 08:28:33 -08002159 case MGMT_OP_USER_PASSKEY_REPLY:
2160 err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len);
2161 break;
2162 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
2163 err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr),
2164 len);
2165 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002166 case MGMT_OP_SET_LOCAL_NAME:
2167 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2168 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002169 case MGMT_OP_READ_LOCAL_OOB_DATA:
2170 err = read_local_oob_data(sk, index);
2171 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002172 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2173 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2174 break;
2175 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2176 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2177 len);
2178 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002179 case MGMT_OP_START_DISCOVERY:
Johan Hedberg450dfda2011-11-12 11:58:22 +02002180 err = start_discovery(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002181 break;
2182 case MGMT_OP_STOP_DISCOVERY:
2183 err = stop_discovery(sk, index);
2184 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002185 case MGMT_OP_BLOCK_DEVICE:
2186 err = block_device(sk, index, buf + sizeof(*hdr), len);
2187 break;
2188 case MGMT_OP_UNBLOCK_DEVICE:
2189 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
2190 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002191 case MGMT_OP_SET_FAST_CONNECTABLE:
2192 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
2193 len);
2194 break;
Johan Hedberg03811012010-12-08 00:21:06 +02002195 default:
2196 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002197 err = cmd_status(sk, index, opcode,
2198 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg03811012010-12-08 00:21:06 +02002199 break;
2200 }
2201
Johan Hedberge41d8b42010-12-13 21:07:03 +02002202 if (err < 0)
2203 goto done;
2204
Johan Hedberg03811012010-12-08 00:21:06 +02002205 err = msglen;
2206
2207done:
2208 kfree(buf);
2209 return err;
2210}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002211
Johan Hedbergb24752f2011-11-03 14:40:33 +02002212static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2213{
2214 u8 *status = data;
2215
2216 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2217 mgmt_pending_remove(cmd);
2218}
2219
Johan Hedberg744cf192011-11-08 20:40:14 +02002220int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002221{
Johan Hedberg744cf192011-11-08 20:40:14 +02002222 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002223}
2224
Johan Hedberg744cf192011-11-08 20:40:14 +02002225int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002226{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002227 u8 status = ENODEV;
2228
Johan Hedberg744cf192011-11-08 20:40:14 +02002229 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002230
Johan Hedberg744cf192011-11-08 20:40:14 +02002231 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002232}
2233
Johan Hedberg73f22f62010-12-29 16:00:25 +02002234struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002235 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002236 struct sock *sk;
2237};
2238
Johan Hedberg72a734e2010-12-30 00:38:22 +02002239static void mode_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002240{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002241 struct mgmt_mode *cp = cmd->param;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002242 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002243
Johan Hedberg72a734e2010-12-30 00:38:22 +02002244 if (cp->val != match->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002245 return;
2246
Johan Hedberg053f0212011-01-26 13:07:10 +02002247 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002248
2249 list_del(&cmd->list);
2250
2251 if (match->sk == NULL) {
2252 match->sk = cmd->sk;
2253 sock_hold(match->sk);
2254 }
2255
2256 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002257}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002258
Johan Hedberg744cf192011-11-08 20:40:14 +02002259int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002260{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002261 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002262 struct cmd_lookup match = { powered, NULL };
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002263 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002264
Johan Hedberg744cf192011-11-08 20:40:14 +02002265 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002266
Johan Hedbergb24752f2011-11-03 14:40:33 +02002267 if (!powered) {
2268 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002269 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002270 }
2271
Johan Hedberg72a734e2010-12-30 00:38:22 +02002272 ev.val = powered;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002273
Johan Hedberg744cf192011-11-08 20:40:14 +02002274 ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002275
2276 if (match.sk)
2277 sock_put(match.sk);
2278
2279 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002280}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002281
Johan Hedberg744cf192011-11-08 20:40:14 +02002282int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002283{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002284 struct mgmt_mode ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002285 struct cmd_lookup match = { discoverable, NULL };
2286 int ret;
2287
Johan Hedberg744cf192011-11-08 20:40:14 +02002288 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002289
Johan Hedberg72a734e2010-12-30 00:38:22 +02002290 ev.val = discoverable;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002291
Johan Hedberg744cf192011-11-08 20:40:14 +02002292 ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002293 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002294
2295 if (match.sk)
2296 sock_put(match.sk);
2297
2298 return ret;
2299}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002300
Johan Hedberg744cf192011-11-08 20:40:14 +02002301int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002302{
Johan Hedberg72a734e2010-12-30 00:38:22 +02002303 struct mgmt_mode ev;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002304 struct cmd_lookup match = { connectable, NULL };
2305 int ret;
2306
Johan Hedberg744cf192011-11-08 20:40:14 +02002307 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002308
Johan Hedberg72a734e2010-12-30 00:38:22 +02002309 ev.val = connectable;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002310
Johan Hedberg744cf192011-11-08 20:40:14 +02002311 ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002312
2313 if (match.sk)
2314 sock_put(match.sk);
2315
2316 return ret;
2317}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002318
Johan Hedberg744cf192011-11-08 20:40:14 +02002319int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002320{
Johan Hedbergca69b792011-11-11 18:10:00 +02002321 u8 mgmt_err = mgmt_status(status);
2322
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002323 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002324 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002325 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002326
2327 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002328 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002329 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002330
2331 return 0;
2332}
2333
Johan Hedberg744cf192011-11-08 20:40:14 +02002334int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2335 u8 persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002336{
Johan Hedberg86742e12011-11-07 23:13:38 +02002337 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002338
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002339 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002340
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002341 ev.store_hint = persistent;
2342 bacpy(&ev.key.bdaddr, &key->bdaddr);
2343 ev.key.type = key->type;
2344 memcpy(ev.key.val, key->val, 16);
2345 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002346
Johan Hedberg744cf192011-11-08 20:40:14 +02002347 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002348}
Johan Hedbergf7520542011-01-20 12:34:39 +02002349
Johan Hedberg48264f02011-11-09 13:58:58 +02002350int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2351 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002352{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002353 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002354
Johan Hedbergf7520542011-01-20 12:34:39 +02002355 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002356 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002357
Johan Hedberg744cf192011-11-08 20:40:14 +02002358 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002359}
2360
Johan Hedberg8962ee72011-01-20 12:40:27 +02002361static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2362{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002363 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002364 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002365 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002366
Johan Hedberga38528f2011-01-22 06:46:43 +02002367 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002368 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002369
Szymon Janc4e51eae2011-02-25 19:05:48 +01002370 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002371
2372 *sk = cmd->sk;
2373 sock_hold(*sk);
2374
Johan Hedberga664b5b2011-02-19 12:06:02 -03002375 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002376}
2377
Johan Hedberga8a1d192011-11-10 15:54:38 +02002378static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2379{
2380 u8 *status = data;
2381 struct mgmt_cp_remove_keys *cp = cmd->param;
2382 struct mgmt_rp_remove_keys rp;
2383
2384 memset(&rp, 0, sizeof(rp));
2385 bacpy(&rp.bdaddr, &cp->bdaddr);
2386 if (status != NULL)
2387 rp.status = *status;
2388
2389 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2390 sizeof(rp));
2391
2392 mgmt_pending_remove(cmd);
2393}
2394
Johan Hedberg48264f02011-11-09 13:58:58 +02002395int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2396 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002397{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002398 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002399 struct sock *sk = NULL;
2400 int err;
2401
Johan Hedberg744cf192011-11-08 20:40:14 +02002402 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002403
Johan Hedbergf7520542011-01-20 12:34:39 +02002404 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002405 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002406
Johan Hedberg744cf192011-11-08 20:40:14 +02002407 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002408
2409 if (sk)
2410 sock_put(sk);
2411
Johan Hedberga8a1d192011-11-10 15:54:38 +02002412 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2413
Johan Hedberg8962ee72011-01-20 12:40:27 +02002414 return err;
2415}
2416
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002417int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002418{
2419 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002420 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002421 int err;
2422
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002423 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002424 if (!cmd)
2425 return -ENOENT;
2426
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002427 if (bdaddr) {
2428 struct mgmt_rp_disconnect rp;
2429
2430 bacpy(&rp.bdaddr, bdaddr);
2431 rp.status = status;
2432
2433 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2434 &rp, sizeof(rp));
2435 } else
2436 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002437 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002438
Johan Hedberga664b5b2011-02-19 12:06:02 -03002439 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002440
2441 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002442}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002443
Johan Hedberg48264f02011-11-09 13:58:58 +02002444int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2445 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002446{
2447 struct mgmt_ev_connect_failed ev;
2448
Johan Hedberg4c659c32011-11-07 23:13:39 +02002449 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002450 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002451 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002452
Johan Hedberg744cf192011-11-08 20:40:14 +02002453 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002454}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002455
Johan Hedberg744cf192011-11-08 20:40:14 +02002456int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002457{
2458 struct mgmt_ev_pin_code_request ev;
2459
Johan Hedberg980e1a52011-01-22 06:10:07 +02002460 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002461 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002462
Johan Hedberg744cf192011-11-08 20:40:14 +02002463 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002464 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002465}
2466
Johan Hedberg744cf192011-11-08 20:40:14 +02002467int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2468 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002469{
2470 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002471 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002472 int err;
2473
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002474 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002475 if (!cmd)
2476 return -ENOENT;
2477
Johan Hedbergac56fb12011-02-19 12:05:59 -03002478 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002479 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002480
Johan Hedberg744cf192011-11-08 20:40:14 +02002481 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002482 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002483
Johan Hedberga664b5b2011-02-19 12:06:02 -03002484 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002485
2486 return err;
2487}
2488
Johan Hedberg744cf192011-11-08 20:40:14 +02002489int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2490 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002491{
2492 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002493 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002494 int err;
2495
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002496 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002497 if (!cmd)
2498 return -ENOENT;
2499
Johan Hedbergac56fb12011-02-19 12:05:59 -03002500 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002501 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002502
Johan Hedberg744cf192011-11-08 20:40:14 +02002503 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002504 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002505
Johan Hedberga664b5b2011-02-19 12:06:02 -03002506 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002507
2508 return err;
2509}
Johan Hedberga5c29682011-02-19 12:05:57 -03002510
Johan Hedberg744cf192011-11-08 20:40:14 +02002511int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2512 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002513{
2514 struct mgmt_ev_user_confirm_request ev;
2515
Johan Hedberg744cf192011-11-08 20:40:14 +02002516 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002517
Johan Hedberga5c29682011-02-19 12:05:57 -03002518 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002519 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002520 put_unaligned_le32(value, &ev.value);
2521
Johan Hedberg744cf192011-11-08 20:40:14 +02002522 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002523 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002524}
2525
Brian Gix604086b2011-11-23 08:28:33 -08002526int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2527{
2528 struct mgmt_ev_user_passkey_request ev;
2529
2530 BT_DBG("%s", hdev->name);
2531
2532 bacpy(&ev.bdaddr, bdaddr);
2533
2534 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2535 NULL);
2536}
2537
Brian Gix0df4c182011-11-16 13:53:13 -08002538static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002539 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002540{
2541 struct pending_cmd *cmd;
2542 struct mgmt_rp_user_confirm_reply rp;
2543 int err;
2544
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002545 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002546 if (!cmd)
2547 return -ENOENT;
2548
Johan Hedberga5c29682011-02-19 12:05:57 -03002549 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002550 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002551 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002552
Johan Hedberga664b5b2011-02-19 12:06:02 -03002553 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002554
2555 return err;
2556}
2557
Johan Hedberg744cf192011-11-08 20:40:14 +02002558int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2559 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002560{
Brian Gix0df4c182011-11-16 13:53:13 -08002561 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002562 MGMT_OP_USER_CONFIRM_REPLY);
2563}
2564
Johan Hedberg744cf192011-11-08 20:40:14 +02002565int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2566 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002567{
Brian Gix0df4c182011-11-16 13:53:13 -08002568 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002569 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2570}
Johan Hedberg2a611692011-02-19 12:06:00 -03002571
Brian Gix604086b2011-11-23 08:28:33 -08002572int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2573 u8 status)
2574{
2575 return user_pairing_resp_complete(hdev, bdaddr, status,
2576 MGMT_OP_USER_PASSKEY_REPLY);
2577}
2578
2579int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2580 bdaddr_t *bdaddr, u8 status)
2581{
2582 return user_pairing_resp_complete(hdev, bdaddr, status,
2583 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2584}
2585
Johan Hedberg744cf192011-11-08 20:40:14 +02002586int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002587{
2588 struct mgmt_ev_auth_failed ev;
2589
Johan Hedberg2a611692011-02-19 12:06:00 -03002590 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002591 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002592
Johan Hedberg744cf192011-11-08 20:40:14 +02002593 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002594}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002595
Johan Hedberg744cf192011-11-08 20:40:14 +02002596int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002597{
2598 struct pending_cmd *cmd;
2599 struct mgmt_cp_set_local_name ev;
2600 int err;
2601
2602 memset(&ev, 0, sizeof(ev));
2603 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2604
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002605 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002606 if (!cmd)
2607 goto send_event;
2608
2609 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002610 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002611 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002612 goto failed;
2613 }
2614
Johan Hedberg744cf192011-11-08 20:40:14 +02002615 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002616
Johan Hedberg744cf192011-11-08 20:40:14 +02002617 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002618 sizeof(ev));
2619 if (err < 0)
2620 goto failed;
2621
2622send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002623 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002624 cmd ? cmd->sk : NULL);
2625
2626failed:
2627 if (cmd)
2628 mgmt_pending_remove(cmd);
2629 return err;
2630}
Szymon Jancc35938b2011-03-22 13:12:21 +01002631
Johan Hedberg744cf192011-11-08 20:40:14 +02002632int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2633 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002634{
2635 struct pending_cmd *cmd;
2636 int err;
2637
Johan Hedberg744cf192011-11-08 20:40:14 +02002638 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002639
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002640 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002641 if (!cmd)
2642 return -ENOENT;
2643
2644 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002645 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002646 MGMT_OP_READ_LOCAL_OOB_DATA,
2647 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002648 } else {
2649 struct mgmt_rp_read_local_oob_data rp;
2650
2651 memcpy(rp.hash, hash, sizeof(rp.hash));
2652 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2653
Johan Hedberg744cf192011-11-08 20:40:14 +02002654 err = cmd_complete(cmd->sk, hdev->id,
2655 MGMT_OP_READ_LOCAL_OOB_DATA,
2656 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002657 }
2658
2659 mgmt_pending_remove(cmd);
2660
2661 return err;
2662}
Johan Hedberge17acd42011-03-30 23:57:16 +03002663
Johan Hedberg48264f02011-11-09 13:58:58 +02002664int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2665 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002666{
2667 struct mgmt_ev_device_found ev;
2668
2669 memset(&ev, 0, sizeof(ev));
2670
Johan Hedberg4c659c32011-11-07 23:13:39 +02002671 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002672 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002673 ev.rssi = rssi;
2674
2675 if (eir)
2676 memcpy(ev.eir, eir, sizeof(ev.eir));
2677
Andre Guedesf8523592011-09-09 18:56:26 -03002678 if (dev_class)
2679 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2680
Johan Hedberg744cf192011-11-08 20:40:14 +02002681 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002682}
Johan Hedberga88a9652011-03-30 13:18:12 +03002683
Johan Hedberg744cf192011-11-08 20:40:14 +02002684int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002685{
2686 struct mgmt_ev_remote_name ev;
2687
2688 memset(&ev, 0, sizeof(ev));
2689
2690 bacpy(&ev.bdaddr, bdaddr);
2691 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2692
Johan Hedberg744cf192011-11-08 20:40:14 +02002693 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002694}
Johan Hedberg314b2382011-04-27 10:29:57 -04002695
Andre Guedes7a135102011-11-09 17:14:25 -03002696int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002697{
2698 struct pending_cmd *cmd;
2699 int err;
2700
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002701 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002702 if (!cmd)
2703 return -ENOENT;
2704
Johan Hedbergca69b792011-11-11 18:10:00 +02002705 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002706 mgmt_pending_remove(cmd);
2707
2708 return err;
2709}
2710
Andre Guedese6d465c2011-11-09 17:14:26 -03002711int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2712{
2713 struct pending_cmd *cmd;
2714 int err;
2715
2716 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2717 if (!cmd)
2718 return -ENOENT;
2719
2720 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
2721 mgmt_pending_remove(cmd);
2722
2723 return err;
2724}
2725
Johan Hedberg744cf192011-11-08 20:40:14 +02002726int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002727{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002728 struct pending_cmd *cmd;
2729
2730 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002731 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002732 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002733 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002734
2735 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002736 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002737 mgmt_pending_remove(cmd);
2738 }
2739
Johan Hedberg744cf192011-11-08 20:40:14 +02002740 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002741 sizeof(discovering), NULL);
2742}
Antti Julku5e762442011-08-25 16:48:02 +03002743
Johan Hedberg744cf192011-11-08 20:40:14 +02002744int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002745{
2746 struct pending_cmd *cmd;
2747 struct mgmt_ev_device_blocked ev;
2748
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002749 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002750
2751 bacpy(&ev.bdaddr, bdaddr);
2752
Johan Hedberg744cf192011-11-08 20:40:14 +02002753 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2754 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002755}
2756
Johan Hedberg744cf192011-11-08 20:40:14 +02002757int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002758{
2759 struct pending_cmd *cmd;
2760 struct mgmt_ev_device_unblocked ev;
2761
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002762 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002763
2764 bacpy(&ev.bdaddr, bdaddr);
2765
Johan Hedberg744cf192011-11-08 20:40:14 +02002766 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2767 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002768}