blob: 61d0250bd77e0aa139e945603a50cc603e8b7176 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
Johan Hedbergea585ab2012-02-17 14:50:39 +02003
Johan Hedberg03811012010-12-08 00:21:06 +02004 Copyright (C) 2010 Nokia Corporation
Johan Hedbergea585ab2012-02-17 14:50:39 +02005 Copyright (C) 2011-2012 Intel Corporation
Johan Hedberg03811012010-12-08 00:21:06 +02006
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI Management interface */
26
Johan Hedbergca69b792011-11-11 18:10:00 +020027#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010028#include <linux/uaccess.h>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040029#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020030#include <asm/unaligned.h>
31
32#include <net/bluetooth/bluetooth.h>
33#include <net/bluetooth/hci_core.h>
34#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080035#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020036
Johan Hedberg02d98122010-12-13 21:07:04 +020037#define MGMT_VERSION 0
38#define MGMT_REVISION 1
39
Johan Hedberge70bb2e2012-02-13 16:59:33 +020040static const u16 mgmt_commands[] = {
41 MGMT_OP_READ_INDEX_LIST,
42 MGMT_OP_READ_INFO,
43 MGMT_OP_SET_POWERED,
44 MGMT_OP_SET_DISCOVERABLE,
45 MGMT_OP_SET_CONNECTABLE,
46 MGMT_OP_SET_FAST_CONNECTABLE,
47 MGMT_OP_SET_PAIRABLE,
48 MGMT_OP_SET_LINK_SECURITY,
49 MGMT_OP_SET_SSP,
50 MGMT_OP_SET_HS,
51 MGMT_OP_SET_LE,
52 MGMT_OP_SET_DEV_CLASS,
53 MGMT_OP_SET_LOCAL_NAME,
54 MGMT_OP_ADD_UUID,
55 MGMT_OP_REMOVE_UUID,
56 MGMT_OP_LOAD_LINK_KEYS,
57 MGMT_OP_LOAD_LONG_TERM_KEYS,
58 MGMT_OP_DISCONNECT,
59 MGMT_OP_GET_CONNECTIONS,
60 MGMT_OP_PIN_CODE_REPLY,
61 MGMT_OP_PIN_CODE_NEG_REPLY,
62 MGMT_OP_SET_IO_CAPABILITY,
63 MGMT_OP_PAIR_DEVICE,
64 MGMT_OP_CANCEL_PAIR_DEVICE,
65 MGMT_OP_UNPAIR_DEVICE,
66 MGMT_OP_USER_CONFIRM_REPLY,
67 MGMT_OP_USER_CONFIRM_NEG_REPLY,
68 MGMT_OP_USER_PASSKEY_REPLY,
69 MGMT_OP_USER_PASSKEY_NEG_REPLY,
70 MGMT_OP_READ_LOCAL_OOB_DATA,
71 MGMT_OP_ADD_REMOTE_OOB_DATA,
72 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
73 MGMT_OP_START_DISCOVERY,
74 MGMT_OP_STOP_DISCOVERY,
75 MGMT_OP_CONFIRM_NAME,
76 MGMT_OP_BLOCK_DEVICE,
77 MGMT_OP_UNBLOCK_DEVICE,
78};
79
80static const u16 mgmt_events[] = {
81 MGMT_EV_CONTROLLER_ERROR,
82 MGMT_EV_INDEX_ADDED,
83 MGMT_EV_INDEX_REMOVED,
84 MGMT_EV_NEW_SETTINGS,
85 MGMT_EV_CLASS_OF_DEV_CHANGED,
86 MGMT_EV_LOCAL_NAME_CHANGED,
87 MGMT_EV_NEW_LINK_KEY,
88 MGMT_EV_NEW_LONG_TERM_KEY,
89 MGMT_EV_DEVICE_CONNECTED,
90 MGMT_EV_DEVICE_DISCONNECTED,
91 MGMT_EV_CONNECT_FAILED,
92 MGMT_EV_PIN_CODE_REQUEST,
93 MGMT_EV_USER_CONFIRM_REQUEST,
94 MGMT_EV_USER_PASSKEY_REQUEST,
95 MGMT_EV_AUTH_FAILED,
96 MGMT_EV_DEVICE_FOUND,
97 MGMT_EV_DISCOVERING,
98 MGMT_EV_DEVICE_BLOCKED,
99 MGMT_EV_DEVICE_UNBLOCKED,
100 MGMT_EV_DEVICE_UNPAIRED,
101};
102
Andre Guedes3fd24152012-02-03 17:48:01 -0300103/*
104 * These LE scan and inquiry parameters were chosen according to LE General
105 * Discovery Procedure specification.
106 */
107#define LE_SCAN_TYPE 0x01
108#define LE_SCAN_WIN 0x12
109#define LE_SCAN_INT 0x12
110#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300111#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300112
Andre Guedese8777522012-02-03 17:48:02 -0300113#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300115
Johan Hedberg7d785252011-12-15 00:47:39 +0200116#define SERVICE_CACHE_TIMEOUT (5 * 1000)
117
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200118struct pending_cmd {
119 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200120 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200121 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100122 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200123 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300124 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200125};
126
Johan Hedbergca69b792011-11-11 18:10:00 +0200127/* HCI to MGMT error code conversion table */
128static u8 mgmt_status_table[] = {
129 MGMT_STATUS_SUCCESS,
130 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
131 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
132 MGMT_STATUS_FAILED, /* Hardware Failure */
133 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
134 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
135 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
136 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
137 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
138 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
139 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
140 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
141 MGMT_STATUS_BUSY, /* Command Disallowed */
142 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
143 MGMT_STATUS_REJECTED, /* Rejected Security */
144 MGMT_STATUS_REJECTED, /* Rejected Personal */
145 MGMT_STATUS_TIMEOUT, /* Host Timeout */
146 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
147 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
148 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
149 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
150 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
151 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
152 MGMT_STATUS_BUSY, /* Repeated Attempts */
153 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
154 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
155 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
156 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
157 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
158 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
159 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
160 MGMT_STATUS_FAILED, /* Unspecified Error */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
162 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
163 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
164 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
165 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
166 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
167 MGMT_STATUS_FAILED, /* Unit Link Key Used */
168 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
169 MGMT_STATUS_TIMEOUT, /* Instant Passed */
170 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
171 MGMT_STATUS_FAILED, /* Transaction Collision */
172 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
173 MGMT_STATUS_REJECTED, /* QoS Rejected */
174 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
175 MGMT_STATUS_REJECTED, /* Insufficient Security */
176 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
177 MGMT_STATUS_BUSY, /* Role Switch Pending */
178 MGMT_STATUS_FAILED, /* Slot Violation */
179 MGMT_STATUS_FAILED, /* Role Switch Failed */
180 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
181 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
182 MGMT_STATUS_BUSY, /* Host Busy Pairing */
183 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
184 MGMT_STATUS_BUSY, /* Controller Busy */
185 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
186 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
187 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
188 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
189 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
190};
191
192static u8 mgmt_status(u8 hci_status)
193{
194 if (hci_status < ARRAY_SIZE(mgmt_status_table))
195 return mgmt_status_table[hci_status];
196
197 return MGMT_STATUS_FAILED;
198}
199
Szymon Janc4e51eae2011-02-25 19:05:48 +0100200static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200201{
202 struct sk_buff *skb;
203 struct mgmt_hdr *hdr;
204 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300205 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200206
Szymon Janc34eb5252011-02-28 14:10:08 +0100207 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200208
209 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
210 if (!skb)
211 return -ENOMEM;
212
213 hdr = (void *) skb_put(skb, sizeof(*hdr));
214
215 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100216 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200217 hdr->len = cpu_to_le16(sizeof(*ev));
218
219 ev = (void *) skb_put(skb, sizeof(*ev));
220 ev->status = status;
221 put_unaligned_le16(cmd, &ev->opcode);
222
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300223 err = sock_queue_rcv_skb(sk, skb);
224 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200225 kfree_skb(skb);
226
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300227 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200228}
229
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200230static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
231 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200232{
233 struct sk_buff *skb;
234 struct mgmt_hdr *hdr;
235 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300236 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200237
238 BT_DBG("sock %p", sk);
239
Johan Hedberga38528f2011-01-22 06:46:43 +0200240 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200241 if (!skb)
242 return -ENOMEM;
243
244 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200245
Johan Hedberg02d98122010-12-13 21:07:04 +0200246 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100247 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200248 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200249
Johan Hedberga38528f2011-01-22 06:46:43 +0200250 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
251 put_unaligned_le16(cmd, &ev->opcode);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200252 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100253
254 if (rp)
255 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200256
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300257 err = sock_queue_rcv_skb(sk, skb);
258 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200259 kfree_skb(skb);
260
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300261 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200262}
263
Johan Hedberga38528f2011-01-22 06:46:43 +0200264static int read_version(struct sock *sk)
265{
266 struct mgmt_rp_read_version rp;
267
268 BT_DBG("sock %p", sk);
269
270 rp.version = MGMT_VERSION;
271 put_unaligned_le16(MGMT_REVISION, &rp.revision);
272
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200273 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100274 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200275}
276
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200277static int read_commands(struct sock *sk)
278{
279 struct mgmt_rp_read_commands *rp;
280 u16 num_commands = ARRAY_SIZE(mgmt_commands);
281 u16 num_events = ARRAY_SIZE(mgmt_events);
282 u16 *opcode;
283 size_t rp_size;
284 int i, err;
285
286 BT_DBG("sock %p", sk);
287
288 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
289
290 rp = kmalloc(rp_size, GFP_KERNEL);
291 if (!rp)
292 return -ENOMEM;
293
294 put_unaligned_le16(num_commands, &rp->num_commands);
295 put_unaligned_le16(num_events, &rp->num_events);
296
297 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
298 put_unaligned_le16(mgmt_commands[i], opcode);
299
300 for (i = 0; i < num_events; i++, opcode++)
301 put_unaligned_le16(mgmt_events[i], opcode);
302
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200303 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200304 rp_size);
305 kfree(rp);
306
307 return err;
308}
309
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200310static int read_index_list(struct sock *sk)
311{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200312 struct mgmt_rp_read_index_list *rp;
313 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200314 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200315 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200316 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200317 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318
319 BT_DBG("sock %p", sk);
320
321 read_lock(&hci_dev_list_lock);
322
323 count = 0;
324 list_for_each(p, &hci_dev_list) {
325 count++;
326 }
327
Johan Hedberga38528f2011-01-22 06:46:43 +0200328 rp_len = sizeof(*rp) + (2 * count);
329 rp = kmalloc(rp_len, GFP_ATOMIC);
330 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100331 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200332 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100333 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200334
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200335 put_unaligned_le16(count, &rp->num_controllers);
336
337 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200338 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200339 if (test_and_clear_bit(HCI_AUTO_OFF, &d->dev_flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200340 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200341
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200342 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200343 continue;
344
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345 put_unaligned_le16(d->id, &rp->index[i++]);
346 BT_DBG("Added hci%u", d->id);
347 }
348
349 read_unlock(&hci_dev_list_lock);
350
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200351 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +0100352 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200353
Johan Hedberga38528f2011-01-22 06:46:43 +0200354 kfree(rp);
355
356 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200357}
358
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200359static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200360{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200361 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200362
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200363 settings |= MGMT_SETTING_POWERED;
364 settings |= MGMT_SETTING_CONNECTABLE;
365 settings |= MGMT_SETTING_FAST_CONNECTABLE;
366 settings |= MGMT_SETTING_DISCOVERABLE;
367 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 if (hdev->features[6] & LMP_SIMPLE_PAIR)
370 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200371
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200372 if (!(hdev->features[4] & LMP_NO_BREDR)) {
373 settings |= MGMT_SETTING_BREDR;
374 settings |= MGMT_SETTING_LINK_SECURITY;
375 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200376
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200377 if (hdev->features[4] & LMP_LE)
378 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200379
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200380 return settings;
381}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200382
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200383static u32 get_current_settings(struct hci_dev *hdev)
384{
385 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200386
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200387 if (test_bit(HCI_UP, &hdev->flags))
388 settings |= MGMT_SETTING_POWERED;
389 else
390 return settings;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200391
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200392 if (test_bit(HCI_PSCAN, &hdev->flags))
393 settings |= MGMT_SETTING_CONNECTABLE;
394
395 if (test_bit(HCI_ISCAN, &hdev->flags))
396 settings |= MGMT_SETTING_DISCOVERABLE;
397
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200398 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200399 settings |= MGMT_SETTING_PAIRABLE;
400
401 if (!(hdev->features[4] & LMP_NO_BREDR))
402 settings |= MGMT_SETTING_BREDR;
403
Andre Guedes59e29402011-12-30 10:34:03 -0300404 if (hdev->host_features[0] & LMP_HOST_LE)
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200405 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200406
407 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200408 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200409
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200410 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200411 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200412
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200414}
415
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300416#define PNP_INFO_SVCLASS_ID 0x1200
417
418static u8 bluetooth_base_uuid[] = {
419 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
420 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
421};
422
423static u16 get_uuid16(u8 *uuid128)
424{
425 u32 val;
426 int i;
427
428 for (i = 0; i < 12; i++) {
429 if (bluetooth_base_uuid[i] != uuid128[i])
430 return 0;
431 }
432
433 memcpy(&val, &uuid128[12], 4);
434
435 val = le32_to_cpu(val);
436 if (val > 0xffff)
437 return 0;
438
439 return (u16) val;
440}
441
442static void create_eir(struct hci_dev *hdev, u8 *data)
443{
444 u8 *ptr = data;
445 u16 eir_len = 0;
446 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
447 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200448 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300449 size_t name_len;
450
451 name_len = strlen(hdev->dev_name);
452
453 if (name_len > 0) {
454 /* EIR Data type */
455 if (name_len > 48) {
456 name_len = 48;
457 ptr[1] = EIR_NAME_SHORT;
458 } else
459 ptr[1] = EIR_NAME_COMPLETE;
460
461 /* EIR Data length */
462 ptr[0] = name_len + 1;
463
464 memcpy(ptr + 2, hdev->dev_name, name_len);
465
466 eir_len += (name_len + 2);
467 ptr += (name_len + 2);
468 }
469
470 memset(uuid16_list, 0, sizeof(uuid16_list));
471
472 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200473 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300474 u16 uuid16;
475
476 uuid16 = get_uuid16(uuid->uuid);
477 if (uuid16 == 0)
478 return;
479
480 if (uuid16 < 0x1100)
481 continue;
482
483 if (uuid16 == PNP_INFO_SVCLASS_ID)
484 continue;
485
486 /* Stop if not enough space to put next UUID */
487 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
488 truncated = 1;
489 break;
490 }
491
492 /* Check for duplicates */
493 for (i = 0; uuid16_list[i] != 0; i++)
494 if (uuid16_list[i] == uuid16)
495 break;
496
497 if (uuid16_list[i] == 0) {
498 uuid16_list[i] = uuid16;
499 eir_len += sizeof(u16);
500 }
501 }
502
503 if (uuid16_list[0] != 0) {
504 u8 *length = ptr;
505
506 /* EIR Data type */
507 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
508
509 ptr += 2;
510 eir_len += 2;
511
512 for (i = 0; uuid16_list[i] != 0; i++) {
513 *ptr++ = (uuid16_list[i] & 0x00ff);
514 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
515 }
516
517 /* EIR Data length */
518 *length = (i * sizeof(u16)) + 1;
519 }
520}
521
522static int update_eir(struct hci_dev *hdev)
523{
524 struct hci_cp_write_eir cp;
525
526 if (!(hdev->features[6] & LMP_EXT_INQ))
527 return 0;
528
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200529 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300530 return 0;
531
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200532 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300533 return 0;
534
535 memset(&cp, 0, sizeof(cp));
536
537 create_eir(hdev, cp.data);
538
539 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
540 return 0;
541
542 memcpy(hdev->eir, cp.data, sizeof(cp.data));
543
544 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
545}
546
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200547static u8 get_service_classes(struct hci_dev *hdev)
548{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300549 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200550 u8 val = 0;
551
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300552 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200553 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200554
555 return val;
556}
557
558static int update_class(struct hci_dev *hdev)
559{
560 u8 cod[3];
561
562 BT_DBG("%s", hdev->name);
563
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200564 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200565 return 0;
566
567 cod[0] = hdev->minor_class;
568 cod[1] = hdev->major_class;
569 cod[2] = get_service_classes(hdev);
570
571 if (memcmp(cod, hdev->dev_class, 3) == 0)
572 return 0;
573
574 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
575}
576
Johan Hedberg7d785252011-12-15 00:47:39 +0200577static void service_cache_off(struct work_struct *work)
578{
579 struct hci_dev *hdev = container_of(work, struct hci_dev,
580 service_cache.work);
581
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200582 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200583 return;
584
585 hci_dev_lock(hdev);
586
587 update_eir(hdev);
588 update_class(hdev);
589
590 hci_dev_unlock(hdev);
591}
592
593static void mgmt_init_hdev(struct hci_dev *hdev)
594{
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200595 if (!test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200596 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
597
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200598 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200599 schedule_delayed_work(&hdev->service_cache,
600 msecs_to_jiffies(SERVICE_CACHE_TIMEOUT));
601}
602
Johan Hedberg03811012010-12-08 00:21:06 +0200603static int read_controller_info(struct sock *sk, u16 index)
604{
605 struct mgmt_rp_read_info rp;
606 struct hci_dev *hdev;
607
608 BT_DBG("sock %p hci%u", sk, index);
609
610 hdev = hci_dev_get(index);
611 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200612 return cmd_status(sk, index, MGMT_OP_READ_INFO,
613 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200614
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200615 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags))
Johan Hedberg03811012010-12-08 00:21:06 +0200616 cancel_delayed_work_sync(&hdev->power_off);
617
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300618 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200619
Johan Hedberg7d785252011-12-15 00:47:39 +0200620 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags))
621 mgmt_init_hdev(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200622
623 memset(&rp, 0, sizeof(rp));
624
Johan Hedberg03811012010-12-08 00:21:06 +0200625 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200626
627 rp.version = hdev->hci_ver;
628
Johan Hedberg03811012010-12-08 00:21:06 +0200629 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200630
631 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
632 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
633
634 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200635
636 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
637
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300638 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200639 hci_dev_put(hdev);
640
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200641 return cmd_complete(sk, index, MGMT_OP_READ_INFO, 0, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200642}
643
644static void mgmt_pending_free(struct pending_cmd *cmd)
645{
646 sock_put(cmd->sk);
647 kfree(cmd->param);
648 kfree(cmd);
649}
650
651static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
652 struct hci_dev *hdev,
653 void *data, u16 len)
654{
655 struct pending_cmd *cmd;
656
657 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
658 if (!cmd)
659 return NULL;
660
661 cmd->opcode = opcode;
662 cmd->index = hdev->id;
663
664 cmd->param = kmalloc(len, GFP_ATOMIC);
665 if (!cmd->param) {
666 kfree(cmd);
667 return NULL;
668 }
669
670 if (data)
671 memcpy(cmd->param, data, len);
672
673 cmd->sk = sk;
674 sock_hold(sk);
675
676 list_add(&cmd->list, &hdev->mgmt_pending);
677
678 return cmd;
679}
680
681static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
682 void (*cb)(struct pending_cmd *cmd, void *data),
683 void *data)
684{
685 struct list_head *p, *n;
686
687 list_for_each_safe(p, n, &hdev->mgmt_pending) {
688 struct pending_cmd *cmd;
689
690 cmd = list_entry(p, struct pending_cmd, list);
691
692 if (opcode > 0 && cmd->opcode != opcode)
693 continue;
694
695 cb(cmd, data);
696 }
697}
698
699static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
700{
701 struct pending_cmd *cmd;
702
703 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
704 if (cmd->opcode == opcode)
705 return cmd;
706 }
707
708 return NULL;
709}
710
711static void mgmt_pending_remove(struct pending_cmd *cmd)
712{
713 list_del(&cmd->list);
714 mgmt_pending_free(cmd);
715}
716
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200717static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200718{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200719 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200720
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200721 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
722 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200723}
724
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300725static int set_powered(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200726{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300727 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200728 struct hci_dev *hdev;
729 struct pending_cmd *cmd;
730 int err, up;
731
Johan Hedberg03811012010-12-08 00:21:06 +0200732 BT_DBG("request for hci%u", index);
733
734 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200735 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
736 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200737
738 hdev = hci_dev_get(index);
739 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200740 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
741 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200742
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300743 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200744
745 up = test_bit(HCI_UP, &hdev->flags);
746 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200747 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200748 goto failed;
749 }
750
751 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200752 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
753 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200754 goto failed;
755 }
756
757 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
758 if (!cmd) {
759 err = -ENOMEM;
760 goto failed;
761 }
762
763 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200764 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200765 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200766 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200767
768 err = 0;
769
770failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300771 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200772 hci_dev_put(hdev);
773 return err;
774}
775
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300776static int set_discoverable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200777{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300778 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberge41d8b42010-12-13 21:07:03 +0200779 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200780 struct pending_cmd *cmd;
781 u8 scan;
782 int err;
783
Johan Hedberg03811012010-12-08 00:21:06 +0200784 BT_DBG("request for hci%u", index);
785
786 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200787 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
788 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg03811012010-12-08 00:21:06 +0200789
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200790 hdev = hci_dev_get(index);
791 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200792 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
793 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200794
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300795 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200796
797 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200798 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
799 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200800 goto failed;
801 }
802
803 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
804 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200805 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
806 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200807 goto failed;
808 }
809
810 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
811 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200812 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200813 goto failed;
814 }
815
816 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
817 if (!cmd) {
818 err = -ENOMEM;
819 goto failed;
820 }
821
822 scan = SCAN_PAGE;
823
824 if (cp->val)
825 scan |= SCAN_INQUIRY;
826 else
827 cancel_delayed_work(&hdev->discov_off);
828
829 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
830 if (err < 0)
831 mgmt_pending_remove(cmd);
832
Johan Hedberg03811012010-12-08 00:21:06 +0200833 if (cp->val)
834 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
835
Johan Hedberge41d8b42010-12-13 21:07:03 +0200836failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300837 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200838 hci_dev_put(hdev);
839
840 return err;
841}
842
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300843static int set_connectable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200844{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300845 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200846 struct hci_dev *hdev;
847 struct pending_cmd *cmd;
848 u8 scan;
849 int err;
850
Johan Hedberge41d8b42010-12-13 21:07:03 +0200851 BT_DBG("request for hci%u", index);
852
Johan Hedberg03811012010-12-08 00:21:06 +0200853 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200854 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
855 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200856
857 hdev = hci_dev_get(index);
858 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200859 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
860 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200861
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300862 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200863
864 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200865 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
866 MGMT_STATUS_NOT_POWERED);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200867 goto failed;
868 }
869
870 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
871 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200872 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
873 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200874 goto failed;
875 }
876
877 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200878 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200879 goto failed;
880 }
881
882 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
883 if (!cmd) {
884 err = -ENOMEM;
885 goto failed;
886 }
887
888 if (cp->val)
889 scan = SCAN_PAGE;
890 else
891 scan = 0;
892
893 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
894 if (err < 0)
895 mgmt_pending_remove(cmd);
896
897failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300898 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200899 hci_dev_put(hdev);
900
901 return err;
902}
903
904static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
905 u16 data_len, struct sock *skip_sk)
906{
907 struct sk_buff *skb;
908 struct mgmt_hdr *hdr;
909
910 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
911 if (!skb)
912 return -ENOMEM;
913
914 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
915
916 hdr = (void *) skb_put(skb, sizeof(*hdr));
917 hdr->opcode = cpu_to_le16(event);
918 if (hdev)
919 hdr->index = cpu_to_le16(hdev->id);
920 else
921 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
922 hdr->len = cpu_to_le16(data_len);
923
924 if (data)
925 memcpy(skb_put(skb, data_len), data, data_len);
926
927 hci_send_to_sock(NULL, skb, skip_sk);
928 kfree_skb(skb);
929
930 return 0;
931}
932
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300933static int set_pairable(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200934{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300935 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200936 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200937 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200938 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200939
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200940 BT_DBG("request for hci%u", index);
941
942 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200943 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
944 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200945
946 hdev = hci_dev_get(index);
947 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200948 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
949 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200950
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300951 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200952
953 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200954 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200955 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200956 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200957
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200958 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200959 if (err < 0)
960 goto failed;
961
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200962 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200963
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200964 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200965
966failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300967 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200968 hci_dev_put(hdev);
969
970 return err;
971}
Johan Hedberg72a734e2010-12-30 00:38:22 +0200972
Johan Hedberg33ef95e2012-02-16 23:56:27 +0200973static int set_link_security(struct sock *sk, u16 index, void *data, u16 len)
974{
975 struct mgmt_mode *cp = data;
976 struct pending_cmd *cmd;
977 struct hci_dev *hdev;
978 uint8_t val;
979 int err;
980
981 BT_DBG("request for hci%u", index);
982
983 if (len != sizeof(*cp))
984 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
985 MGMT_STATUS_INVALID_PARAMS);
986
987 hdev = hci_dev_get(index);
988 if (!hdev)
989 return cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
990 MGMT_STATUS_INVALID_PARAMS);
991
992 hci_dev_lock(hdev);
993
994 if (!test_bit(HCI_UP, &hdev->flags)) {
995 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
996 MGMT_STATUS_NOT_POWERED);
997 goto failed;
998 }
999
1000 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
1001 err = cmd_status(sk, index, MGMT_OP_SET_LINK_SECURITY,
1002 MGMT_STATUS_BUSY);
1003 goto failed;
1004 }
1005
1006 val = !!cp->val;
1007
1008 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1009 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1010 goto failed;
1011 }
1012
1013 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1014 if (!cmd) {
1015 err = -ENOMEM;
1016 goto failed;
1017 }
1018
1019 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1020 if (err < 0) {
1021 mgmt_pending_remove(cmd);
1022 goto failed;
1023 }
1024
1025failed:
1026 hci_dev_unlock(hdev);
1027 hci_dev_put(hdev);
1028
1029 return err;
1030}
1031
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001032static int set_ssp(struct sock *sk, u16 index, void *data, u16 len)
1033{
1034 struct mgmt_mode *cp = data;
1035 struct pending_cmd *cmd;
1036 struct hci_dev *hdev;
1037 uint8_t val;
1038 int err;
1039
1040 BT_DBG("request for hci%u", index);
1041
1042 if (len != sizeof(*cp))
1043 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1044 MGMT_STATUS_INVALID_PARAMS);
1045
1046 hdev = hci_dev_get(index);
1047 if (!hdev)
1048 return cmd_status(sk, index, MGMT_OP_SET_SSP,
1049 MGMT_STATUS_INVALID_PARAMS);
1050
1051 hci_dev_lock(hdev);
1052
1053 if (!test_bit(HCI_UP, &hdev->flags)) {
1054 err = cmd_status(sk, index, MGMT_OP_SET_SSP,
1055 MGMT_STATUS_NOT_POWERED);
1056 goto failed;
1057 }
1058
1059 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
1060 err = cmd_status(sk, index, MGMT_OP_SET_SSP, MGMT_STATUS_BUSY);
1061 goto failed;
1062 }
1063
1064 val = !!cp->val;
1065
1066 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1067 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1068 goto failed;
1069 }
1070
1071 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1072 if (!cmd) {
1073 err = -ENOMEM;
1074 goto failed;
1075 }
1076
1077 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1078 if (err < 0) {
1079 mgmt_pending_remove(cmd);
1080 goto failed;
1081 }
1082
1083failed:
1084 hci_dev_unlock(hdev);
1085 hci_dev_put(hdev);
1086
1087 return err;
1088}
1089
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001090static int add_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001091{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001092 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001093 struct hci_dev *hdev;
1094 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001095 int err;
1096
Szymon Janc4e51eae2011-02-25 19:05:48 +01001097 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001098
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001099 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001100 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1101 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001102
Szymon Janc4e51eae2011-02-25 19:05:48 +01001103 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001104 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001105 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
1106 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001107
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001108 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001109
1110 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1111 if (!uuid) {
1112 err = -ENOMEM;
1113 goto failed;
1114 }
1115
1116 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001117 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001118
1119 list_add(&uuid->list, &hdev->uuids);
1120
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001121 err = update_class(hdev);
1122 if (err < 0)
1123 goto failed;
1124
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001125 err = update_eir(hdev);
1126 if (err < 0)
1127 goto failed;
1128
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001129 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001130
1131failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001132 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001133 hci_dev_put(hdev);
1134
1135 return err;
1136}
1137
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001138static int remove_uuid(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001139{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001140 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001141 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001142 struct hci_dev *hdev;
1143 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 +02001144 int err, found;
1145
Szymon Janc4e51eae2011-02-25 19:05:48 +01001146 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001147
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001148 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001149 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1150 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001151
Szymon Janc4e51eae2011-02-25 19:05:48 +01001152 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001153 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001154 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1155 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001156
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001157 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001158
1159 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1160 err = hci_uuids_clear(hdev);
1161 goto unlock;
1162 }
1163
1164 found = 0;
1165
1166 list_for_each_safe(p, n, &hdev->uuids) {
1167 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1168
1169 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1170 continue;
1171
1172 list_del(&match->list);
1173 found++;
1174 }
1175
1176 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001177 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
1178 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001179 goto unlock;
1180 }
1181
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001182 err = update_class(hdev);
1183 if (err < 0)
1184 goto unlock;
1185
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001186 err = update_eir(hdev);
1187 if (err < 0)
1188 goto unlock;
1189
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001190 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, 0, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001191
1192unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001193 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001194 hci_dev_put(hdev);
1195
1196 return err;
1197}
1198
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001199static int set_dev_class(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001200{
1201 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001202 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001203 int err;
1204
Szymon Janc4e51eae2011-02-25 19:05:48 +01001205 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001206
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001207 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001208 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1209 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001210
Szymon Janc4e51eae2011-02-25 19:05:48 +01001211 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001212 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001213 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
1214 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001215
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001216 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001217
1218 hdev->major_class = cp->major;
1219 hdev->minor_class = cp->minor;
1220
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001221 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001222 hci_dev_unlock(hdev);
1223 cancel_delayed_work_sync(&hdev->service_cache);
1224 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001225 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001226 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001227
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001228 err = update_class(hdev);
1229
1230 if (err == 0)
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001231 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, 0,
1232 NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001233
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001234 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001235 hci_dev_put(hdev);
1236
1237 return err;
1238}
1239
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001240static int load_link_keys(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001241{
1242 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001243 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001244 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001245 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001246
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001247 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001248 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1249 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001250
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001251 key_count = get_unaligned_le16(&cp->key_count);
1252
Johan Hedberg86742e12011-11-07 23:13:38 +02001253 expected_len = sizeof(*cp) + key_count *
1254 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001255 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001256 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001257 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001258 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1259 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001260 }
1261
Szymon Janc4e51eae2011-02-25 19:05:48 +01001262 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001263 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001264 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1265 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001266
Szymon Janc4e51eae2011-02-25 19:05:48 +01001267 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001268 key_count);
1269
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001270 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001271
1272 hci_link_keys_clear(hdev);
1273
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001274 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001275
1276 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001277 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001278 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001279 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001280
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001281 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001282 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001283
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001284 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
1285 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001286 }
1287
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001288 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001289
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001290 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001291 hci_dev_put(hdev);
1292
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001293 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001294}
1295
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001296static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
1297 u8 addr_type, struct sock *skip_sk)
1298{
1299 struct mgmt_ev_device_unpaired ev;
1300
1301 bacpy(&ev.addr.bdaddr, bdaddr);
1302 ev.addr.type = addr_type;
1303
1304 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
1305 skip_sk);
1306}
1307
Johan Hedberg124f6e32012-02-09 13:50:12 +02001308static int unpair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001309{
1310 struct hci_dev *hdev;
Johan Hedberg124f6e32012-02-09 13:50:12 +02001311 struct mgmt_cp_unpair_device *cp = data;
1312 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001313 struct hci_cp_disconnect dc;
1314 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001315 struct hci_conn *conn;
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001316 u8 status = 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001317 int err;
1318
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001319 if (len != sizeof(*cp))
Johan Hedberg124f6e32012-02-09 13:50:12 +02001320 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001321 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001322
Szymon Janc4e51eae2011-02-25 19:05:48 +01001323 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001324 if (!hdev)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001325 return cmd_status(sk, index, MGMT_OP_UNPAIR_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001326 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001327
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001328 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001329
Johan Hedberga8a1d192011-11-10 15:54:38 +02001330 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001331 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1332 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001333
Johan Hedberg124f6e32012-02-09 13:50:12 +02001334 if (cp->addr.type == MGMT_ADDR_BREDR)
1335 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1336 else
1337 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001338
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001339 if (err < 0) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001340 status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001341 goto unlock;
1342 }
1343
Johan Hedberga8a1d192011-11-10 15:54:38 +02001344 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001345 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1346 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001347 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001348 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001349 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001350
Johan Hedberg124f6e32012-02-09 13:50:12 +02001351 if (cp->addr.type == MGMT_ADDR_BREDR)
1352 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1353 &cp->addr.bdaddr);
1354 else
1355 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1356 &cp->addr.bdaddr);
1357
Johan Hedberga8a1d192011-11-10 15:54:38 +02001358 if (!conn) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001359 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1360 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001361 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001362 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001363 }
1364
Johan Hedberg124f6e32012-02-09 13:50:12 +02001365 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
1366 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001367 if (!cmd) {
1368 err = -ENOMEM;
1369 goto unlock;
1370 }
1371
1372 put_unaligned_le16(conn->handle, &dc.handle);
1373 dc.reason = 0x13; /* Remote User Terminated Connection */
1374 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1375 if (err < 0)
1376 mgmt_pending_remove(cmd);
1377
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001378unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001379 if (err < 0)
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001380 err = cmd_complete(sk, index, MGMT_OP_UNPAIR_DEVICE, status,
1381 &rp, sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001382 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001383 hci_dev_put(hdev);
1384
1385 return err;
1386}
1387
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001388static int disconnect(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001389{
1390 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001391 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001392 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001393 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001394 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001395 int err;
1396
1397 BT_DBG("");
1398
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001399 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001400 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1401 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001402
Szymon Janc4e51eae2011-02-25 19:05:48 +01001403 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001404 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001405 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1406 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001407
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001408 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001409
1410 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001411 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1412 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001413 goto failed;
1414 }
1415
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001416 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001417 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1418 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001419 goto failed;
1420 }
1421
Johan Hedberg88c3df12012-02-09 14:27:38 +02001422 if (cp->addr.type == MGMT_ADDR_BREDR)
1423 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1424 else
1425 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001426
Johan Hedberg8962ee72011-01-20 12:40:27 +02001427 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001428 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1429 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001430 goto failed;
1431 }
1432
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001433 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001434 if (!cmd) {
1435 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001436 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001437 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001438
1439 put_unaligned_le16(conn->handle, &dc.handle);
1440 dc.reason = 0x13; /* Remote User Terminated Connection */
1441
1442 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1443 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001444 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001445
1446failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001447 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001448 hci_dev_put(hdev);
1449
1450 return err;
1451}
1452
Johan Hedberg48264f02011-11-09 13:58:58 +02001453static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001454{
1455 switch (link_type) {
1456 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001457 switch (addr_type) {
1458 case ADDR_LE_DEV_PUBLIC:
1459 return MGMT_ADDR_LE_PUBLIC;
1460 case ADDR_LE_DEV_RANDOM:
1461 return MGMT_ADDR_LE_RANDOM;
1462 default:
1463 return MGMT_ADDR_INVALID;
1464 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001465 case ACL_LINK:
1466 return MGMT_ADDR_BREDR;
1467 default:
1468 return MGMT_ADDR_INVALID;
1469 }
1470}
1471
Szymon Janc8ce62842011-03-01 16:55:32 +01001472static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001473{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001474 struct mgmt_rp_get_connections *rp;
1475 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001476 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001477 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001478 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001479 int i, err;
1480
1481 BT_DBG("");
1482
Szymon Janc4e51eae2011-02-25 19:05:48 +01001483 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001484 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001485 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1486 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001487
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001488 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001489
1490 count = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001491 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1492 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1493 count++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001494 }
1495
Johan Hedberg4c659c32011-11-07 23:13:39 +02001496 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001497 rp = kmalloc(rp_len, GFP_ATOMIC);
1498 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001499 err = -ENOMEM;
1500 goto unlock;
1501 }
1502
Johan Hedberg2784eb42011-01-21 13:56:35 +02001503 put_unaligned_le16(count, &rp->conn_count);
1504
Johan Hedberg2784eb42011-01-21 13:56:35 +02001505 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001506 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001507 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1508 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001509 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001510 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001511 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1512 continue;
1513 i++;
1514 }
1515
1516 /* Recalculate length in case of filtered SCO connections, etc */
1517 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001518
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001519 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, 0, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001520
1521unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001522 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001523 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001524 hci_dev_put(hdev);
1525 return err;
1526}
1527
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001528static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1529 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1530{
1531 struct pending_cmd *cmd;
1532 int err;
1533
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001534 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001535 sizeof(*cp));
1536 if (!cmd)
1537 return -ENOMEM;
1538
Johan Hedbergd8457692012-02-17 14:24:57 +02001539 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
1540 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001541 if (err < 0)
1542 mgmt_pending_remove(cmd);
1543
1544 return err;
1545}
1546
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001547static int pin_code_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001548{
1549 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001550 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001551 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001552 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001553 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001554 int err;
1555
1556 BT_DBG("");
1557
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001558 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001559 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1560 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001561
Szymon Janc4e51eae2011-02-25 19:05:48 +01001562 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001563 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001564 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1565 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001566
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001567 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001568
1569 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001570 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1571 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001572 goto failed;
1573 }
1574
Johan Hedbergd8457692012-02-17 14:24:57 +02001575 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001576 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001577 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1578 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001579 goto failed;
1580 }
1581
1582 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001583 struct mgmt_cp_pin_code_neg_reply ncp;
1584
1585 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001586
1587 BT_ERR("PIN code is not 16 bytes long");
1588
1589 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1590 if (err >= 0)
1591 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001592 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001593
1594 goto failed;
1595 }
1596
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001597 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data,
1598 len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001599 if (!cmd) {
1600 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001601 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001602 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001603
Johan Hedbergd8457692012-02-17 14:24:57 +02001604 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001605 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001606 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001607
1608 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1609 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001610 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001611
1612failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001613 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001614 hci_dev_put(hdev);
1615
1616 return err;
1617}
1618
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001619static int pin_code_neg_reply(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001620{
1621 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001622 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001623 int err;
1624
1625 BT_DBG("");
1626
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001627 if (len != sizeof(*cp))
1628 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001629 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001630
Szymon Janc4e51eae2011-02-25 19:05:48 +01001631 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001632 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001633 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001634 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001635
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001636 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001637
1638 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001639 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001640 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001641 goto failed;
1642 }
1643
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001644 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001645
1646failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001647 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001648 hci_dev_put(hdev);
1649
1650 return err;
1651}
1652
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001653static int set_io_capability(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001654{
1655 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001656 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001657
1658 BT_DBG("");
1659
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001660 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001661 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1662 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001663
Szymon Janc4e51eae2011-02-25 19:05:48 +01001664 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001665 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001666 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1667 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001668
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001669 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001670
1671 hdev->io_capability = cp->io_capability;
1672
1673 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001674 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001675
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001676 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001677 hci_dev_put(hdev);
1678
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001679 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, 0, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001680}
1681
Johan Hedberge9a416b2011-02-19 12:05:56 -03001682static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1683{
1684 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001685 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001686
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001687 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001688 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1689 continue;
1690
Johan Hedberge9a416b2011-02-19 12:05:56 -03001691 if (cmd->user_data != conn)
1692 continue;
1693
1694 return cmd;
1695 }
1696
1697 return NULL;
1698}
1699
1700static void pairing_complete(struct pending_cmd *cmd, u8 status)
1701{
1702 struct mgmt_rp_pair_device rp;
1703 struct hci_conn *conn = cmd->user_data;
1704
Johan Hedbergba4e5642011-11-11 00:07:34 +02001705 bacpy(&rp.addr.bdaddr, &conn->dst);
1706 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001707
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001708 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
1709 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001710
1711 /* So we don't get further callbacks for this connection */
1712 conn->connect_cfm_cb = NULL;
1713 conn->security_cfm_cb = NULL;
1714 conn->disconn_cfm_cb = NULL;
1715
1716 hci_conn_put(conn);
1717
Johan Hedberga664b5b2011-02-19 12:06:02 -03001718 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001719}
1720
1721static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1722{
1723 struct pending_cmd *cmd;
1724
1725 BT_DBG("status %u", status);
1726
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001727 cmd = find_pairing(conn);
1728 if (!cmd)
1729 BT_DBG("Unable to find a pending command");
1730 else
1731 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001732}
1733
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001734static int pair_device(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001735{
1736 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001737 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001738 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001739 struct pending_cmd *cmd;
1740 u8 sec_level, auth_type;
1741 struct hci_conn *conn;
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001742 u8 status = 0;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001743 int err;
1744
1745 BT_DBG("");
1746
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001747 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001748 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1749 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001750
Szymon Janc4e51eae2011-02-25 19:05:48 +01001751 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001752 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001753 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1754 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001755
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001756 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001757
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001758 sec_level = BT_SECURITY_MEDIUM;
1759 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001760 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001761 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001762 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001763
Johan Hedbergba4e5642011-11-11 00:07:34 +02001764 if (cp->addr.type == MGMT_ADDR_BREDR)
1765 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001766 auth_type);
1767 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001768 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001769 auth_type);
1770
Johan Hedberg1425acb2011-11-11 00:07:35 +02001771 memset(&rp, 0, sizeof(rp));
1772 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1773 rp.addr.type = cp->addr.type;
1774
Ville Tervo30e76272011-02-22 16:10:53 -03001775 if (IS_ERR(conn)) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001776 status = -PTR_ERR(conn);
1777 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, status,
Johan Hedberg1425acb2011-11-11 00:07:35 +02001778 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001779 goto unlock;
1780 }
1781
1782 if (conn->connect_cfm_cb) {
1783 hci_conn_put(conn);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001784 status = EBUSY;
1785 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE, status,
Johan Hedberg1425acb2011-11-11 00:07:35 +02001786 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001787 goto unlock;
1788 }
1789
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001790 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001791 if (!cmd) {
1792 err = -ENOMEM;
1793 hci_conn_put(conn);
1794 goto unlock;
1795 }
1796
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001797 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001798 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001799 conn->connect_cfm_cb = pairing_complete_cb;
1800
Johan Hedberge9a416b2011-02-19 12:05:56 -03001801 conn->security_cfm_cb = pairing_complete_cb;
1802 conn->disconn_cfm_cb = pairing_complete_cb;
1803 conn->io_capability = cp->io_cap;
1804 cmd->user_data = conn;
1805
1806 if (conn->state == BT_CONNECTED &&
1807 hci_conn_security(conn, sec_level, auth_type))
1808 pairing_complete(cmd, 0);
1809
1810 err = 0;
1811
1812unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001813 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001814 hci_dev_put(hdev);
1815
1816 return err;
1817}
1818
Johan Hedberg28424702012-02-02 04:02:29 +02001819static int cancel_pair_device(struct sock *sk, u16 index,
1820 unsigned char *data, u16 len)
1821{
1822 struct mgmt_addr_info *addr = (void *) data;
1823 struct hci_dev *hdev;
1824 struct pending_cmd *cmd;
1825 struct hci_conn *conn;
1826 int err;
1827
1828 BT_DBG("");
1829
1830 if (len != sizeof(*addr))
1831 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1832 MGMT_STATUS_INVALID_PARAMS);
1833
1834 hdev = hci_dev_get(index);
1835 if (!hdev)
1836 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1837 MGMT_STATUS_INVALID_PARAMS);
1838
1839 hci_dev_lock(hdev);
1840
1841 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1842 if (!cmd) {
1843 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1844 MGMT_STATUS_INVALID_PARAMS);
1845 goto unlock;
1846 }
1847
1848 conn = cmd->user_data;
1849
1850 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1851 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1852 MGMT_STATUS_INVALID_PARAMS);
1853 goto unlock;
1854 }
1855
1856 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1857
Johan Hedbergaee9b2182012-02-18 15:07:59 +02001858 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001859 sizeof(*addr));
1860unlock:
1861 hci_dev_unlock(hdev);
1862 hci_dev_put(hdev);
1863
1864 return err;
1865}
1866
Brian Gix0df4c182011-11-16 13:53:13 -08001867static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001868 u8 type, u16 mgmt_op, u16 hci_op,
1869 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001870{
Johan Hedberga5c29682011-02-19 12:05:57 -03001871 struct pending_cmd *cmd;
1872 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001873 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001874 int err;
1875
Szymon Janc4e51eae2011-02-25 19:05:48 +01001876 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001877 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001878 return cmd_status(sk, index, mgmt_op,
1879 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001880
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001881 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001882
Johan Hedberga5c29682011-02-19 12:05:57 -03001883 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001884 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1885 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001886 }
1887
Johan Hedberg272d90d2012-02-09 15:26:12 +02001888 if (type == MGMT_ADDR_BREDR)
1889 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1890 else
Brian Gix47c15e22011-11-16 13:53:14 -08001891 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001892
Johan Hedberg272d90d2012-02-09 15:26:12 +02001893 if (!conn) {
1894 err = cmd_status(sk, index, mgmt_op,
1895 MGMT_STATUS_NOT_CONNECTED);
1896 goto done;
1897 }
1898
1899 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001900 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001901 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001902
Brian Gix5fe57d92011-12-21 16:12:13 -08001903 if (!err)
1904 err = cmd_status(sk, index, mgmt_op,
1905 MGMT_STATUS_SUCCESS);
1906 else
1907 err = cmd_status(sk, index, mgmt_op,
1908 MGMT_STATUS_FAILED);
1909
Brian Gix47c15e22011-11-16 13:53:14 -08001910 goto done;
1911 }
1912
Brian Gix0df4c182011-11-16 13:53:13 -08001913 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001914 if (!cmd) {
1915 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001916 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001917 }
1918
Brian Gix0df4c182011-11-16 13:53:13 -08001919 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001920 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1921 struct hci_cp_user_passkey_reply cp;
1922
1923 bacpy(&cp.bdaddr, bdaddr);
1924 cp.passkey = passkey;
1925 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1926 } else
1927 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1928
Johan Hedberga664b5b2011-02-19 12:06:02 -03001929 if (err < 0)
1930 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001931
Brian Gix0df4c182011-11-16 13:53:13 -08001932done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001933 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001934 hci_dev_put(hdev);
1935
1936 return err;
1937}
1938
Brian Gix0df4c182011-11-16 13:53:13 -08001939static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1940{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001941 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001942
1943 BT_DBG("");
1944
1945 if (len != sizeof(*cp))
1946 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1947 MGMT_STATUS_INVALID_PARAMS);
1948
Johan Hedberg272d90d2012-02-09 15:26:12 +02001949 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1950 MGMT_OP_USER_CONFIRM_REPLY,
1951 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001952}
1953
1954static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1955 u16 len)
1956{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001957 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001958
1959 BT_DBG("");
1960
1961 if (len != sizeof(*cp))
1962 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1963 MGMT_STATUS_INVALID_PARAMS);
1964
Johan Hedberg272d90d2012-02-09 15:26:12 +02001965 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1966 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1967 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001968}
1969
Brian Gix604086b2011-11-23 08:28:33 -08001970static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1971{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001972 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001973
1974 BT_DBG("");
1975
1976 if (len != sizeof(*cp))
1977 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1978 EINVAL);
1979
Johan Hedberg272d90d2012-02-09 15:26:12 +02001980 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1981 MGMT_OP_USER_PASSKEY_REPLY,
1982 HCI_OP_USER_PASSKEY_REPLY,
1983 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08001984}
1985
1986static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1987 u16 len)
1988{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001989 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001990
1991 BT_DBG("");
1992
1993 if (len != sizeof(*cp))
1994 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1995 EINVAL);
1996
Johan Hedberg272d90d2012-02-09 15:26:12 +02001997 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1998 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1999 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002000}
2001
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002002static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002003 u16 len)
2004{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002005 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002006 struct hci_cp_write_local_name hci_cp;
2007 struct hci_dev *hdev;
2008 struct pending_cmd *cmd;
2009 int err;
2010
2011 BT_DBG("");
2012
2013 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002014 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2015 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002016
2017 hdev = hci_dev_get(index);
2018 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002019 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2020 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002021
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002022 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002023
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002024 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2025 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002026 if (!cmd) {
2027 err = -ENOMEM;
2028 goto failed;
2029 }
2030
2031 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2032 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2033 &hci_cp);
2034 if (err < 0)
2035 mgmt_pending_remove(cmd);
2036
2037failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002038 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002039 hci_dev_put(hdev);
2040
2041 return err;
2042}
2043
Szymon Jancc35938b2011-03-22 13:12:21 +01002044static int read_local_oob_data(struct sock *sk, u16 index)
2045{
2046 struct hci_dev *hdev;
2047 struct pending_cmd *cmd;
2048 int err;
2049
2050 BT_DBG("hci%u", index);
2051
2052 hdev = hci_dev_get(index);
2053 if (!hdev)
2054 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002055 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002056
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002057 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002058
2059 if (!test_bit(HCI_UP, &hdev->flags)) {
2060 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002061 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002062 goto unlock;
2063 }
2064
2065 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2066 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002067 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002068 goto unlock;
2069 }
2070
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002071 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002072 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2073 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002074 goto unlock;
2075 }
2076
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002077 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002078 if (!cmd) {
2079 err = -ENOMEM;
2080 goto unlock;
2081 }
2082
2083 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2084 if (err < 0)
2085 mgmt_pending_remove(cmd);
2086
2087unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002088 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002089 hci_dev_put(hdev);
2090
2091 return err;
2092}
2093
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002094static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2095 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002096{
2097 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002098 struct mgmt_cp_add_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01002099 int err;
2100
2101 BT_DBG("hci%u ", index);
2102
2103 if (len != sizeof(*cp))
2104 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002105 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002106
2107 hdev = hci_dev_get(index);
2108 if (!hdev)
2109 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002110 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002111
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002112 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002113
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002114 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Szymon Janc2763eda2011-03-22 13:12:22 +01002115 cp->randomizer);
2116 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002117 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2118 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01002119 else
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002120 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, 0,
2121 NULL, 0);
Szymon Janc2763eda2011-03-22 13:12:22 +01002122
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002123 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002124 hci_dev_put(hdev);
2125
2126 return err;
2127}
2128
2129static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002130 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002131{
2132 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002133 struct mgmt_cp_remove_remote_oob_data *cp = data;
Szymon Janc2763eda2011-03-22 13:12:22 +01002134 int err;
2135
2136 BT_DBG("hci%u ", index);
2137
2138 if (len != sizeof(*cp))
2139 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002140 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002141
2142 hdev = hci_dev_get(index);
2143 if (!hdev)
2144 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002145 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002146
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002147 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002148
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002149 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002150 if (err < 0)
2151 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002152 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002153 else
2154 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002155 0, NULL, 0);
Szymon Janc2763eda2011-03-22 13:12:22 +01002156
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002157 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002158 hci_dev_put(hdev);
2159
2160 return err;
2161}
2162
Andre Guedes5e0452c2012-02-17 20:39:38 -03002163static int discovery(struct hci_dev *hdev)
2164{
2165 int err;
2166
2167 if (lmp_host_le_capable(hdev)) {
2168 if (lmp_bredr_capable(hdev)) {
2169 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2170 LE_SCAN_INT, LE_SCAN_WIN,
2171 LE_SCAN_TIMEOUT_BREDR_LE);
2172 } else {
2173 hdev->discovery.type = DISCOV_TYPE_LE;
2174 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2175 LE_SCAN_INT, LE_SCAN_WIN,
2176 LE_SCAN_TIMEOUT_LE_ONLY);
2177 }
2178 } else {
2179 hdev->discovery.type = DISCOV_TYPE_BREDR;
2180 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2181 }
2182
2183 return err;
2184}
2185
2186int mgmt_interleaved_discovery(struct hci_dev *hdev)
2187{
2188 int err;
2189
2190 BT_DBG("%s", hdev->name);
2191
2192 hci_dev_lock(hdev);
2193
2194 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2195 if (err < 0)
2196 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2197
2198 hci_dev_unlock(hdev);
2199
2200 return err;
2201}
2202
Johan Hedberg450dfda2011-11-12 11:58:22 +02002203static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002204 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002205{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002206 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002207 struct pending_cmd *cmd;
2208 struct hci_dev *hdev;
2209 int err;
2210
2211 BT_DBG("hci%u", index);
2212
Johan Hedberg450dfda2011-11-12 11:58:22 +02002213 if (len != sizeof(*cp))
2214 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2215 MGMT_STATUS_INVALID_PARAMS);
2216
Johan Hedberg14a53662011-04-27 10:29:56 -04002217 hdev = hci_dev_get(index);
2218 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002219 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2220 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002221
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002222 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002223
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002224 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002225 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2226 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002227 goto failed;
2228 }
2229
Johan Hedbergff9ef572012-01-04 14:23:45 +02002230 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2231 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2232 MGMT_STATUS_BUSY);
2233 goto failed;
2234 }
2235
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002236 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002237 if (!cmd) {
2238 err = -ENOMEM;
2239 goto failed;
2240 }
2241
Andre Guedes4aab14e2012-02-17 20:39:36 -03002242 hdev->discovery.type = cp->type;
2243
2244 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002245 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002246 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002247 break;
2248
2249 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002250 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2251 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002252 break;
2253
Andre Guedes5e0452c2012-02-17 20:39:38 -03002254 case DISCOV_TYPE_INTERLEAVED:
2255 err = discovery(hdev);
2256 break;
2257
Andre Guedesf39799f2012-02-17 20:39:35 -03002258 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002259 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002260 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002261
Johan Hedberg14a53662011-04-27 10:29:56 -04002262 if (err < 0)
2263 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002264 else
2265 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002266
2267failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002268 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002269 hci_dev_put(hdev);
2270
2271 return err;
2272}
2273
2274static int stop_discovery(struct sock *sk, u16 index)
2275{
2276 struct hci_dev *hdev;
2277 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002278 struct hci_cp_remote_name_req_cancel cp;
2279 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002280 int err;
2281
2282 BT_DBG("hci%u", index);
2283
2284 hdev = hci_dev_get(index);
2285 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002286 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2287 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002288
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002289 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002290
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002291 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002292 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2293 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002294 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002295 }
2296
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002297 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002298 if (!cmd) {
2299 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002300 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002301 }
2302
Andre Guedes343f9352012-02-17 20:39:37 -03002303 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002304 err = hci_cancel_inquiry(hdev);
2305 if (err < 0)
2306 mgmt_pending_remove(cmd);
2307 else
2308 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2309 goto unlock;
2310 }
2311
2312 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2313 if (!e) {
2314 mgmt_pending_remove(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002315 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
2316 NULL, 0);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002317 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2318 goto unlock;
2319 }
2320
2321 bacpy(&cp.bdaddr, &e->data.bdaddr);
2322 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2323 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002324 if (err < 0)
2325 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002326 else
2327 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002328
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002329unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002330 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002331 hci_dev_put(hdev);
2332
2333 return err;
2334}
2335
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002336static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002337{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002338 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002339 struct inquiry_entry *e;
2340 struct hci_dev *hdev;
2341 int err;
2342
2343 BT_DBG("hci%u", index);
2344
2345 if (len != sizeof(*cp))
2346 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2347 MGMT_STATUS_INVALID_PARAMS);
2348
2349 hdev = hci_dev_get(index);
2350 if (!hdev)
2351 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2352 MGMT_STATUS_INVALID_PARAMS);
2353
2354 hci_dev_lock(hdev);
2355
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002356 if (!hci_discovery_active(hdev)) {
2357 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2358 MGMT_STATUS_FAILED);
2359 goto failed;
2360 }
2361
Johan Hedberga198e7b2012-02-17 14:27:06 +02002362 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002363 if (!e) {
2364 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2365 MGMT_STATUS_INVALID_PARAMS);
2366 goto failed;
2367 }
2368
2369 if (cp->name_known) {
2370 e->name_state = NAME_KNOWN;
2371 list_del(&e->list);
2372 } else {
2373 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002374 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002375 }
2376
2377 err = 0;
2378
2379failed:
2380 hci_dev_unlock(hdev);
2381
2382 return err;
2383}
2384
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002385static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002386{
2387 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002388 struct mgmt_cp_block_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002389 int err;
2390
2391 BT_DBG("hci%u", index);
2392
Antti Julku7fbec222011-06-15 12:01:15 +03002393 if (len != sizeof(*cp))
2394 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002395 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002396
2397 hdev = hci_dev_get(index);
2398 if (!hdev)
2399 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002400 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002401
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002402 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002403
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002404 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002405 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002406 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
2407 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03002408 else
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002409 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, 0,
2410 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002411
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002412 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002413 hci_dev_put(hdev);
2414
2415 return err;
2416}
2417
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002418static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002419{
2420 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002421 struct mgmt_cp_unblock_device *cp = data;
Antti Julku7fbec222011-06-15 12:01:15 +03002422 int err;
2423
2424 BT_DBG("hci%u", index);
2425
Antti Julku7fbec222011-06-15 12:01:15 +03002426 if (len != sizeof(*cp))
2427 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002428 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002429
2430 hdev = hci_dev_get(index);
2431 if (!hdev)
2432 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002433 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002434
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002435 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002436
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002437 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002438
2439 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002440 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2441 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002442 else
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002443 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, 0,
Antti Julku7fbec222011-06-15 12:01:15 +03002444 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002445
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002446 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002447 hci_dev_put(hdev);
2448
2449 return err;
2450}
2451
Antti Julkuf6422ec2011-06-22 13:11:56 +03002452static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002453 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002454{
2455 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002456 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002457 struct hci_cp_write_page_scan_activity acp;
2458 u8 type;
2459 int err;
2460
2461 BT_DBG("hci%u", index);
2462
2463 if (len != sizeof(*cp))
2464 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002465 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002466
2467 hdev = hci_dev_get(index);
2468 if (!hdev)
2469 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002470 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002471
2472 hci_dev_lock(hdev);
2473
Johan Hedbergf7c68692011-12-15 00:47:36 +02002474 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002475 type = PAGE_SCAN_TYPE_INTERLACED;
2476 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2477 } else {
2478 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2479 acp.interval = 0x0800; /* default 1.28 sec page scan */
2480 }
2481
2482 acp.window = 0x0012; /* default 11.25 msec page scan window */
2483
2484 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2485 sizeof(acp), &acp);
2486 if (err < 0) {
2487 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002488 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002489 goto done;
2490 }
2491
2492 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2493 if (err < 0) {
2494 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002495 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002496 goto done;
2497 }
2498
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002499 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2500 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002501done:
2502 hci_dev_unlock(hdev);
2503 hci_dev_put(hdev);
2504
2505 return err;
2506}
2507
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002508static int load_long_term_keys(struct sock *sk, u16 index,
2509 void *cp_data, u16 len)
2510{
2511 struct hci_dev *hdev;
2512 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2513 u16 key_count, expected_len;
2514 int i;
2515
2516 if (len < sizeof(*cp))
2517 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2518 EINVAL);
2519
2520 key_count = get_unaligned_le16(&cp->key_count);
2521
2522 expected_len = sizeof(*cp) + key_count *
2523 sizeof(struct mgmt_ltk_info);
2524 if (expected_len != len) {
2525 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2526 len, expected_len);
2527 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2528 EINVAL);
2529 }
2530
2531 hdev = hci_dev_get(index);
2532 if (!hdev)
2533 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2534 ENODEV);
2535
2536 BT_DBG("hci%u key_count %u", index, key_count);
2537
2538 hci_dev_lock(hdev);
2539
2540 hci_smp_ltks_clear(hdev);
2541
2542 for (i = 0; i < key_count; i++) {
2543 struct mgmt_ltk_info *key = &cp->keys[i];
2544 u8 type;
2545
2546 if (key->master)
2547 type = HCI_SMP_LTK;
2548 else
2549 type = HCI_SMP_LTK_SLAVE;
2550
2551 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2552 type, 0, key->authenticated, key->val,
2553 key->enc_size, key->ediv, key->rand);
2554 }
2555
2556 hci_dev_unlock(hdev);
2557 hci_dev_put(hdev);
2558
2559 return 0;
2560}
2561
Johan Hedberg03811012010-12-08 00:21:06 +02002562int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2563{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002564 void *buf;
2565 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002566 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002567 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002568 int err;
2569
2570 BT_DBG("got %zu bytes", msglen);
2571
2572 if (msglen < sizeof(*hdr))
2573 return -EINVAL;
2574
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002575 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002576 if (!buf)
2577 return -ENOMEM;
2578
2579 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2580 err = -EFAULT;
2581 goto done;
2582 }
2583
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002584 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002585 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002586 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002587 len = get_unaligned_le16(&hdr->len);
2588
2589 if (len != msglen - sizeof(*hdr)) {
2590 err = -EINVAL;
2591 goto done;
2592 }
2593
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002594 cp = buf + sizeof(*hdr);
2595
Johan Hedberg03811012010-12-08 00:21:06 +02002596 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002597 case MGMT_OP_READ_VERSION:
2598 err = read_version(sk);
2599 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002600 case MGMT_OP_READ_COMMANDS:
2601 err = read_commands(sk);
2602 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002603 case MGMT_OP_READ_INDEX_LIST:
2604 err = read_index_list(sk);
2605 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002606 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002607 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002608 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002609 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002610 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002611 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002612 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002613 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002614 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002615 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002616 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002617 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002618 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002619 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c68692011-12-15 00:47:36 +02002620 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002621 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002622 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002623 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002624 case MGMT_OP_SET_LINK_SECURITY:
2625 err = set_link_security(sk, index, cp, len);
2626 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002627 case MGMT_OP_SET_SSP:
2628 err = set_ssp(sk, index, cp, len);
2629 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002630 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002631 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002632 break;
2633 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002634 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002635 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002636 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002637 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002638 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002639 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002640 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002641 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002642 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002643 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002644 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002645 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002646 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002647 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002648 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002649 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002650 break;
2651 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002652 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002653 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002654 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002655 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002656 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002657 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002658 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002659 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002660 case MGMT_OP_CANCEL_PAIR_DEVICE:
2661 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2662 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002663 case MGMT_OP_UNPAIR_DEVICE:
2664 err = unpair_device(sk, index, cp, len);
2665 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002666 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002667 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002668 break;
2669 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002670 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002671 break;
Brian Gix604086b2011-11-23 08:28:33 -08002672 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002673 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002674 break;
2675 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002676 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002677 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002678 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002679 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002680 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002681 case MGMT_OP_READ_LOCAL_OOB_DATA:
2682 err = read_local_oob_data(sk, index);
2683 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002684 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002685 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002686 break;
2687 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002688 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002689 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002690 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002691 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002692 break;
2693 case MGMT_OP_STOP_DISCOVERY:
2694 err = stop_discovery(sk, index);
2695 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002696 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002697 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002698 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002699 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002700 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002701 break;
2702 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002703 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002704 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002705 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2706 err = load_long_term_keys(sk, index, cp, len);
2707 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002708 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002709 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002710 err = cmd_status(sk, index, opcode,
2711 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002712 break;
2713 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002714
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002715 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002716 goto done;
2717
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002718 err = msglen;
2719
2720done:
2721 kfree(buf);
2722 return err;
2723}
2724
Johan Hedbergb24752f2011-11-03 14:40:33 +02002725static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2726{
2727 u8 *status = data;
2728
2729 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2730 mgmt_pending_remove(cmd);
2731}
2732
Johan Hedberg744cf192011-11-08 20:40:14 +02002733int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002734{
Johan Hedberg744cf192011-11-08 20:40:14 +02002735 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002736}
2737
Johan Hedberg744cf192011-11-08 20:40:14 +02002738int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002739{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002740 u8 status = ENODEV;
2741
Johan Hedberg744cf192011-11-08 20:40:14 +02002742 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002743
Johan Hedberg744cf192011-11-08 20:40:14 +02002744 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002745}
2746
2747struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002748 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002749 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002750};
2751
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002752static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002753{
Johan Hedberg03811012010-12-08 00:21:06 +02002754 struct cmd_lookup *match = data;
2755
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002756 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002757
2758 list_del(&cmd->list);
2759
2760 if (match->sk == NULL) {
2761 match->sk = cmd->sk;
2762 sock_hold(match->sk);
2763 }
2764
2765 mgmt_pending_free(cmd);
2766}
2767
Johan Hedberg744cf192011-11-08 20:40:14 +02002768int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002769{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002770 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002771 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002772 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002773
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002774 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002775
Johan Hedbergb24752f2011-11-03 14:40:33 +02002776 if (!powered) {
2777 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002778 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002779 }
2780
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002781 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002782
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002783 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002784 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002785
2786 if (match.sk)
2787 sock_put(match.sk);
2788
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002789 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002790}
2791
Johan Hedberg744cf192011-11-08 20:40:14 +02002792int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002793{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002794 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002795 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002796 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002797
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002798 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002799
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002800 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002801
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002802 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002803 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002804 if (match.sk)
2805 sock_put(match.sk);
2806
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002807 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002808}
2809
Johan Hedberg744cf192011-11-08 20:40:14 +02002810int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002811{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002812 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002813 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002814 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002815
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002816 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2817 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002818
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002819 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002820
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002821 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002822
2823 if (match.sk)
2824 sock_put(match.sk);
2825
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002826 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002827}
2828
Johan Hedberg744cf192011-11-08 20:40:14 +02002829int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002830{
Johan Hedbergca69b792011-11-11 18:10:00 +02002831 u8 mgmt_err = mgmt_status(status);
2832
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002833 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002834 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002835 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002836
2837 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002838 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002839 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002840
2841 return 0;
2842}
2843
Johan Hedberg744cf192011-11-08 20:40:14 +02002844int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2845 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002846{
Johan Hedberg86742e12011-11-07 23:13:38 +02002847 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002848
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002849 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002850
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002851 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002852 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2853 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002854 ev.key.type = key->type;
2855 memcpy(ev.key.val, key->val, 16);
2856 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002857
Johan Hedberg744cf192011-11-08 20:40:14 +02002858 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002859}
Johan Hedbergf7520542011-01-20 12:34:39 +02002860
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002861int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2862{
2863 struct mgmt_ev_new_long_term_key ev;
2864
2865 memset(&ev, 0, sizeof(ev));
2866
2867 ev.store_hint = persistent;
2868 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2869 ev.key.addr.type = key->bdaddr_type;
2870 ev.key.authenticated = key->authenticated;
2871 ev.key.enc_size = key->enc_size;
2872 ev.key.ediv = key->ediv;
2873
2874 if (key->type == HCI_SMP_LTK)
2875 ev.key.master = 1;
2876
2877 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2878 memcpy(ev.key.val, key->val, sizeof(key->val));
2879
2880 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2881 &ev, sizeof(ev), NULL);
2882}
2883
Johan Hedbergafc747a2012-01-15 18:11:07 +02002884int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002885 u8 addr_type, u8 *name, u8 name_len,
2886 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002887{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002888 char buf[512];
2889 struct mgmt_ev_device_connected *ev = (void *) buf;
2890 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002891
Johan Hedbergb644ba32012-01-17 21:48:47 +02002892 bacpy(&ev->addr.bdaddr, bdaddr);
2893 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002894
Johan Hedbergb644ba32012-01-17 21:48:47 +02002895 if (name_len > 0)
2896 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2897 name, name_len);
2898
2899 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2900 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2901 EIR_CLASS_OF_DEV, dev_class, 3);
2902
2903 put_unaligned_le16(eir_len, &ev->eir_len);
2904
2905 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2906 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002907}
2908
Johan Hedberg8962ee72011-01-20 12:40:27 +02002909static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2910{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002911 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002912 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002913 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002914
Johan Hedberg88c3df12012-02-09 14:27:38 +02002915 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2916 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002917
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002918 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
2919 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002920
2921 *sk = cmd->sk;
2922 sock_hold(*sk);
2923
Johan Hedberga664b5b2011-02-19 12:06:02 -03002924 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002925}
2926
Johan Hedberg124f6e32012-02-09 13:50:12 +02002927static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002928{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002929 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002930 struct mgmt_cp_unpair_device *cp = cmd->param;
2931 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002932
2933 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002934 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2935 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002936
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002937 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2938
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002939 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002940
2941 mgmt_pending_remove(cmd);
2942}
2943
Johan Hedbergafc747a2012-01-15 18:11:07 +02002944int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2945 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002946{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002947 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002948 struct sock *sk = NULL;
2949 int err;
2950
Johan Hedberg744cf192011-11-08 20:40:14 +02002951 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002952
Johan Hedbergf7520542011-01-20 12:34:39 +02002953 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002954 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002955
Johan Hedbergafc747a2012-01-15 18:11:07 +02002956 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2957 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002958
2959 if (sk)
2960 sock_put(sk);
2961
Johan Hedberg124f6e32012-02-09 13:50:12 +02002962 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002963 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002964
Johan Hedberg8962ee72011-01-20 12:40:27 +02002965 return err;
2966}
2967
Johan Hedberg88c3df12012-02-09 14:27:38 +02002968int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
2969 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002970{
Johan Hedberg88c3df12012-02-09 14:27:38 +02002971 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002972 struct pending_cmd *cmd;
2973 int err;
2974
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002975 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002976 if (!cmd)
2977 return -ENOENT;
2978
Johan Hedberg88c3df12012-02-09 14:27:38 +02002979 bacpy(&rp.addr.bdaddr, bdaddr);
2980 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002981
Johan Hedberg88c3df12012-02-09 14:27:38 +02002982 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02002983 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002984
Johan Hedberga664b5b2011-02-19 12:06:02 -03002985 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002986
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002987 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
2988 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002989 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002990}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002991
Johan Hedberg48264f02011-11-09 13:58:58 +02002992int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2993 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002994{
2995 struct mgmt_ev_connect_failed ev;
2996
Johan Hedberg4c659c32011-11-07 23:13:39 +02002997 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002998 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002999 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003000
Johan Hedberg744cf192011-11-08 20:40:14 +02003001 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003002}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003003
Johan Hedberg744cf192011-11-08 20:40:14 +02003004int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003005{
3006 struct mgmt_ev_pin_code_request ev;
3007
Johan Hedbergd8457692012-02-17 14:24:57 +02003008 bacpy(&ev.addr.bdaddr, bdaddr);
3009 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003010 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003011
Johan Hedberg744cf192011-11-08 20:40:14 +02003012 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003013 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003014}
3015
Johan Hedberg744cf192011-11-08 20:40:14 +02003016int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3017 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003018{
3019 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003020 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003021 int err;
3022
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003023 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003024 if (!cmd)
3025 return -ENOENT;
3026
Johan Hedbergd8457692012-02-17 14:24:57 +02003027 bacpy(&rp.addr.bdaddr, bdaddr);
3028 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003029
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003030 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3031 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003032
Johan Hedberga664b5b2011-02-19 12:06:02 -03003033 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003034
3035 return err;
3036}
3037
Johan Hedberg744cf192011-11-08 20:40:14 +02003038int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3039 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003040{
3041 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003042 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003043 int err;
3044
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003045 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003046 if (!cmd)
3047 return -ENOENT;
3048
Johan Hedbergd8457692012-02-17 14:24:57 +02003049 bacpy(&rp.addr.bdaddr, bdaddr);
3050 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003051
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003052 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3053 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003054
Johan Hedberga664b5b2011-02-19 12:06:02 -03003055 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003056
3057 return err;
3058}
Johan Hedberga5c29682011-02-19 12:05:57 -03003059
Johan Hedberg744cf192011-11-08 20:40:14 +02003060int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003061 u8 link_type, u8 addr_type, __le32 value,
3062 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003063{
3064 struct mgmt_ev_user_confirm_request ev;
3065
Johan Hedberg744cf192011-11-08 20:40:14 +02003066 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003067
Johan Hedberg272d90d2012-02-09 15:26:12 +02003068 bacpy(&ev.addr.bdaddr, bdaddr);
3069 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003070 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003071 put_unaligned_le32(value, &ev.value);
3072
Johan Hedberg744cf192011-11-08 20:40:14 +02003073 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003074 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003075}
3076
Johan Hedberg272d90d2012-02-09 15:26:12 +02003077int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3078 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003079{
3080 struct mgmt_ev_user_passkey_request ev;
3081
3082 BT_DBG("%s", hdev->name);
3083
Johan Hedberg272d90d2012-02-09 15:26:12 +02003084 bacpy(&ev.addr.bdaddr, bdaddr);
3085 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003086
3087 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3088 NULL);
3089}
3090
Brian Gix0df4c182011-11-16 13:53:13 -08003091static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003092 u8 link_type, u8 addr_type, u8 status,
3093 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003094{
3095 struct pending_cmd *cmd;
3096 struct mgmt_rp_user_confirm_reply rp;
3097 int err;
3098
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003099 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003100 if (!cmd)
3101 return -ENOENT;
3102
Johan Hedberg272d90d2012-02-09 15:26:12 +02003103 bacpy(&rp.addr.bdaddr, bdaddr);
3104 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003105 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3106 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003107
Johan Hedberga664b5b2011-02-19 12:06:02 -03003108 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003109
3110 return err;
3111}
3112
Johan Hedberg744cf192011-11-08 20:40:14 +02003113int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003114 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003115{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003116 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3117 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003118}
3119
Johan Hedberg272d90d2012-02-09 15:26:12 +02003120int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3121 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003122{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003123 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3124 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003125}
Johan Hedberg2a611692011-02-19 12:06:00 -03003126
Brian Gix604086b2011-11-23 08:28:33 -08003127int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003128 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003129{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003130 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3131 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003132}
3133
Johan Hedberg272d90d2012-02-09 15:26:12 +02003134int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3135 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003136{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003137 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3138 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003139}
3140
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003141int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3142 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003143{
3144 struct mgmt_ev_auth_failed ev;
3145
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003146 bacpy(&ev.addr.bdaddr, bdaddr);
3147 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003148 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003149
Johan Hedberg744cf192011-11-08 20:40:14 +02003150 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003151}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003152
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003153int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3154{
3155 struct cmd_lookup match = { NULL, hdev };
3156 __le32 ev;
3157 int err;
3158
3159 if (status) {
3160 u8 mgmt_err = mgmt_status(status);
3161 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3162 cmd_status_rsp, &mgmt_err);
3163 return 0;
3164 }
3165
3166 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3167 &match);
3168
3169 ev = cpu_to_le32(get_current_settings(hdev));
3170 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3171
3172 if (match.sk)
3173 sock_put(match.sk);
3174
3175 return err;
3176}
3177
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003178int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3179{
3180 struct cmd_lookup match = { NULL, hdev };
3181 __le32 ev;
3182 int err;
3183
3184 if (status) {
3185 u8 mgmt_err = mgmt_status(status);
3186 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3187 cmd_status_rsp, &mgmt_err);
3188 return 0;
3189 }
3190
3191 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3192
3193 ev = cpu_to_le32(get_current_settings(hdev));
3194 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3195
3196 if (match.sk)
3197 sock_put(match.sk);
3198
3199 return err;
3200}
3201
Johan Hedberg744cf192011-11-08 20:40:14 +02003202int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003203{
3204 struct pending_cmd *cmd;
3205 struct mgmt_cp_set_local_name ev;
3206 int err;
3207
3208 memset(&ev, 0, sizeof(ev));
3209 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3210
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003211 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003212 if (!cmd)
3213 goto send_event;
3214
3215 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003216 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003217 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003218 goto failed;
3219 }
3220
Johan Hedberg744cf192011-11-08 20:40:14 +02003221 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003222
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003223 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003224 sizeof(ev));
3225 if (err < 0)
3226 goto failed;
3227
3228send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003229 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003230 cmd ? cmd->sk : NULL);
3231
3232failed:
3233 if (cmd)
3234 mgmt_pending_remove(cmd);
3235 return err;
3236}
Szymon Jancc35938b2011-03-22 13:12:21 +01003237
Johan Hedberg744cf192011-11-08 20:40:14 +02003238int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3239 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003240{
3241 struct pending_cmd *cmd;
3242 int err;
3243
Johan Hedberg744cf192011-11-08 20:40:14 +02003244 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003245
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003246 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003247 if (!cmd)
3248 return -ENOENT;
3249
3250 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003251 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003252 MGMT_OP_READ_LOCAL_OOB_DATA,
3253 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003254 } else {
3255 struct mgmt_rp_read_local_oob_data rp;
3256
3257 memcpy(rp.hash, hash, sizeof(rp.hash));
3258 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3259
Johan Hedberg744cf192011-11-08 20:40:14 +02003260 err = cmd_complete(cmd->sk, hdev->id,
3261 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003262 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003263 }
3264
3265 mgmt_pending_remove(cmd);
3266
3267 return err;
3268}
Johan Hedberge17acd42011-03-30 23:57:16 +03003269
Johan Hedberg48264f02011-11-09 13:58:58 +02003270int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003271 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003272 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003273{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003274 char buf[512];
3275 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003276 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003277
Johan Hedberg1dc06092012-01-15 21:01:23 +02003278 /* Leave 5 bytes for a potential CoD field */
3279 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003280 return -EINVAL;
3281
Johan Hedberg1dc06092012-01-15 21:01:23 +02003282 memset(buf, 0, sizeof(buf));
3283
Johan Hedberge319d2e2012-01-15 19:51:59 +02003284 bacpy(&ev->addr.bdaddr, bdaddr);
3285 ev->addr.type = link_to_mgmt(link_type, addr_type);
3286 ev->rssi = rssi;
3287 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003288
Johan Hedberg1dc06092012-01-15 21:01:23 +02003289 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003290 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003291
Johan Hedberg1dc06092012-01-15 21:01:23 +02003292 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3293 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3294 dev_class, 3);
3295
3296 put_unaligned_le16(eir_len, &ev->eir_len);
3297
3298 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003299
Johan Hedberge319d2e2012-01-15 19:51:59 +02003300 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003301}
Johan Hedberga88a9652011-03-30 13:18:12 +03003302
Johan Hedbergb644ba32012-01-17 21:48:47 +02003303int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3304 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003305{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003306 struct mgmt_ev_device_found *ev;
3307 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3308 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003309
Johan Hedbergb644ba32012-01-17 21:48:47 +02003310 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003311
Johan Hedbergb644ba32012-01-17 21:48:47 +02003312 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003313
Johan Hedbergb644ba32012-01-17 21:48:47 +02003314 bacpy(&ev->addr.bdaddr, bdaddr);
3315 ev->addr.type = link_to_mgmt(link_type, addr_type);
3316 ev->rssi = rssi;
3317
3318 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3319 name_len);
3320
3321 put_unaligned_le16(eir_len, &ev->eir_len);
3322
Johan Hedberg053c7e02012-02-04 00:06:00 +02003323 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3324 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003325}
Johan Hedberg314b2382011-04-27 10:29:57 -04003326
Andre Guedes7a135102011-11-09 17:14:25 -03003327int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003328{
3329 struct pending_cmd *cmd;
3330 int err;
3331
Andre Guedes203159d2012-02-13 15:41:01 -03003332 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3333
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003334 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003335 if (!cmd)
3336 return -ENOENT;
3337
Johan Hedbergca69b792011-11-11 18:10:00 +02003338 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003339 mgmt_pending_remove(cmd);
3340
3341 return err;
3342}
3343
Andre Guedese6d465c2011-11-09 17:14:26 -03003344int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3345{
3346 struct pending_cmd *cmd;
3347 int err;
3348
3349 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3350 if (!cmd)
3351 return -ENOENT;
3352
Andre Guedese75a8b0c2012-01-02 16:50:53 -03003353 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02003354 mgmt_pending_remove(cmd);
3355
3356 return err;
3357}
Johan Hedberg314b2382011-04-27 10:29:57 -04003358
Johan Hedberg744cf192011-11-08 20:40:14 +02003359int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003360{
Johan Hedberg164a6e72011-11-01 17:06:44 +02003361 struct pending_cmd *cmd;
3362
Andre Guedes343fb142011-11-22 17:14:19 -03003363 BT_DBG("%s discovering %u", hdev->name, discovering);
3364
Johan Hedberg164a6e72011-11-01 17:06:44 +02003365 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003366 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003367 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003368 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003369
3370 if (cmd != NULL) {
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003371 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003372 mgmt_pending_remove(cmd);
3373 }
3374
Johan Hedberg744cf192011-11-08 20:40:14 +02003375 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04003376 sizeof(discovering), NULL);
3377}
Antti Julku5e762442011-08-25 16:48:02 +03003378
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003379int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003380{
3381 struct pending_cmd *cmd;
3382 struct mgmt_ev_device_blocked ev;
3383
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003384 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003385
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003386 bacpy(&ev.addr.bdaddr, bdaddr);
3387 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003388
Johan Hedberg744cf192011-11-08 20:40:14 +02003389 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3390 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003391}
3392
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003393int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003394{
3395 struct pending_cmd *cmd;
3396 struct mgmt_ev_device_unblocked ev;
3397
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003398 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003399
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003400 bacpy(&ev.addr.bdaddr, bdaddr);
3401 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003402
Johan Hedberg744cf192011-11-08 20:40:14 +02003403 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3404 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003405}