blob: 18d593f23934db7ca19e7c5fa31102dcec57ac27 [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 Hedberg2da9c552012-02-17 14:39:28 +020037#define MGMT_VERSION 1
38#define MGMT_REVISION 0
Johan Hedberg02d98122010-12-13 21:07:04 +020039
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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200225 kfree_skb(skb);
226
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300227 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200228}
229
Johan Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-12-13 21:07:06 +0200794
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300795 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergf7b64e692010-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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 Hedbergaee9b212012-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
Johan Hedberge2113262012-02-18 15:20:03 +02001731 pairing_complete(cmd, mgmt_status(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 Hedberge9a416b2011-02-19 12:05:56 -03001742 int err;
1743
1744 BT_DBG("");
1745
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001746 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001747 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1748 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001749
Szymon Janc4e51eae2011-02-25 19:05:48 +01001750 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001751 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001752 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1753 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001754
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001755 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001756
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001757 sec_level = BT_SECURITY_MEDIUM;
1758 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001759 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001760 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001761 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001762
Johan Hedbergba4e5642011-11-11 00:07:34 +02001763 if (cp->addr.type == MGMT_ADDR_BREDR)
1764 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001765 auth_type);
1766 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001767 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001768 auth_type);
1769
Johan Hedberg1425acb2011-11-11 00:07:35 +02001770 memset(&rp, 0, sizeof(rp));
1771 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1772 rp.addr.type = cp->addr.type;
1773
Ville Tervo30e76272011-02-22 16:10:53 -03001774 if (IS_ERR(conn)) {
Johan Hedberge2113262012-02-18 15:20:03 +02001775 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1776 MGMT_STATUS_CONNECT_FAILED,
1777 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001778 goto unlock;
1779 }
1780
1781 if (conn->connect_cfm_cb) {
1782 hci_conn_put(conn);
Johan Hedberge2113262012-02-18 15:20:03 +02001783 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1784 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001785 goto unlock;
1786 }
1787
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001788 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001789 if (!cmd) {
1790 err = -ENOMEM;
1791 hci_conn_put(conn);
1792 goto unlock;
1793 }
1794
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001795 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001796 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001797 conn->connect_cfm_cb = pairing_complete_cb;
1798
Johan Hedberge9a416b2011-02-19 12:05:56 -03001799 conn->security_cfm_cb = pairing_complete_cb;
1800 conn->disconn_cfm_cb = pairing_complete_cb;
1801 conn->io_capability = cp->io_cap;
1802 cmd->user_data = conn;
1803
1804 if (conn->state == BT_CONNECTED &&
1805 hci_conn_security(conn, sec_level, auth_type))
1806 pairing_complete(cmd, 0);
1807
1808 err = 0;
1809
1810unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001811 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001812 hci_dev_put(hdev);
1813
1814 return err;
1815}
1816
Johan Hedberg28424702012-02-02 04:02:29 +02001817static int cancel_pair_device(struct sock *sk, u16 index,
1818 unsigned char *data, u16 len)
1819{
1820 struct mgmt_addr_info *addr = (void *) data;
1821 struct hci_dev *hdev;
1822 struct pending_cmd *cmd;
1823 struct hci_conn *conn;
1824 int err;
1825
1826 BT_DBG("");
1827
1828 if (len != sizeof(*addr))
1829 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1830 MGMT_STATUS_INVALID_PARAMS);
1831
1832 hdev = hci_dev_get(index);
1833 if (!hdev)
1834 return cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1835 MGMT_STATUS_INVALID_PARAMS);
1836
1837 hci_dev_lock(hdev);
1838
1839 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1840 if (!cmd) {
1841 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1842 MGMT_STATUS_INVALID_PARAMS);
1843 goto unlock;
1844 }
1845
1846 conn = cmd->user_data;
1847
1848 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
1849 err = cmd_status(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE,
1850 MGMT_STATUS_INVALID_PARAMS);
1851 goto unlock;
1852 }
1853
1854 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1855
Johan Hedbergaee9b212012-02-18 15:07:59 +02001856 err = cmd_complete(sk, index, MGMT_OP_CANCEL_PAIR_DEVICE, 0, addr,
Johan Hedberg28424702012-02-02 04:02:29 +02001857 sizeof(*addr));
1858unlock:
1859 hci_dev_unlock(hdev);
1860 hci_dev_put(hdev);
1861
1862 return err;
1863}
1864
Brian Gix0df4c182011-11-16 13:53:13 -08001865static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02001866 u8 type, u16 mgmt_op, u16 hci_op,
1867 __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001868{
Johan Hedberga5c29682011-02-19 12:05:57 -03001869 struct pending_cmd *cmd;
1870 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001871 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001872 int err;
1873
Szymon Janc4e51eae2011-02-25 19:05:48 +01001874 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001875 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001876 return cmd_status(sk, index, mgmt_op,
1877 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001878
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001879 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001880
Johan Hedberga5c29682011-02-19 12:05:57 -03001881 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001882 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1883 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001884 }
1885
Johan Hedberg272d90d2012-02-09 15:26:12 +02001886 if (type == MGMT_ADDR_BREDR)
1887 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1888 else
Brian Gix47c15e22011-11-16 13:53:14 -08001889 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08001890
Johan Hedberg272d90d2012-02-09 15:26:12 +02001891 if (!conn) {
1892 err = cmd_status(sk, index, mgmt_op,
1893 MGMT_STATUS_NOT_CONNECTED);
1894 goto done;
1895 }
1896
1897 if (type == MGMT_ADDR_LE_PUBLIC || type == MGMT_ADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08001898 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08001899 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08001900
Brian Gix5fe57d92011-12-21 16:12:13 -08001901 if (!err)
1902 err = cmd_status(sk, index, mgmt_op,
1903 MGMT_STATUS_SUCCESS);
1904 else
1905 err = cmd_status(sk, index, mgmt_op,
1906 MGMT_STATUS_FAILED);
1907
Brian Gix47c15e22011-11-16 13:53:14 -08001908 goto done;
1909 }
1910
Brian Gix0df4c182011-11-16 13:53:13 -08001911 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001912 if (!cmd) {
1913 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001914 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001915 }
1916
Brian Gix0df4c182011-11-16 13:53:13 -08001917 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001918 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1919 struct hci_cp_user_passkey_reply cp;
1920
1921 bacpy(&cp.bdaddr, bdaddr);
1922 cp.passkey = passkey;
1923 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1924 } else
1925 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1926
Johan Hedberga664b5b2011-02-19 12:06:02 -03001927 if (err < 0)
1928 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001929
Brian Gix0df4c182011-11-16 13:53:13 -08001930done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001931 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001932 hci_dev_put(hdev);
1933
1934 return err;
1935}
1936
Brian Gix0df4c182011-11-16 13:53:13 -08001937static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1938{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001939 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001940
1941 BT_DBG("");
1942
1943 if (len != sizeof(*cp))
1944 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1945 MGMT_STATUS_INVALID_PARAMS);
1946
Johan Hedberg272d90d2012-02-09 15:26:12 +02001947 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1948 MGMT_OP_USER_CONFIRM_REPLY,
1949 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001950}
1951
1952static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1953 u16 len)
1954{
Johan Hedbergc9c26592011-12-15 00:47:41 +02001955 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08001956
1957 BT_DBG("");
1958
1959 if (len != sizeof(*cp))
1960 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1961 MGMT_STATUS_INVALID_PARAMS);
1962
Johan Hedberg272d90d2012-02-09 15:26:12 +02001963 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1964 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1965 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08001966}
1967
Brian Gix604086b2011-11-23 08:28:33 -08001968static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1969{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001970 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001971
1972 BT_DBG("");
1973
1974 if (len != sizeof(*cp))
1975 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1976 EINVAL);
1977
Johan Hedberg272d90d2012-02-09 15:26:12 +02001978 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1979 MGMT_OP_USER_PASSKEY_REPLY,
1980 HCI_OP_USER_PASSKEY_REPLY,
1981 cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08001982}
1983
1984static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1985 u16 len)
1986{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001987 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08001988
1989 BT_DBG("");
1990
1991 if (len != sizeof(*cp))
1992 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1993 EINVAL);
1994
Johan Hedberg272d90d2012-02-09 15:26:12 +02001995 return user_pairing_resp(sk, index, &cp->addr.bdaddr, cp->addr.type,
1996 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1997 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08001998}
1999
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002000static int set_local_name(struct sock *sk, u16 index, void *data,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002001 u16 len)
2002{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002003 struct mgmt_cp_set_local_name *mgmt_cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002004 struct hci_cp_write_local_name hci_cp;
2005 struct hci_dev *hdev;
2006 struct pending_cmd *cmd;
2007 int err;
2008
2009 BT_DBG("");
2010
2011 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02002012 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2013 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002014
2015 hdev = hci_dev_get(index);
2016 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002017 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
2018 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002019
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002020 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002021
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002022 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data,
2023 len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002024 if (!cmd) {
2025 err = -ENOMEM;
2026 goto failed;
2027 }
2028
2029 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
2030 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
2031 &hci_cp);
2032 if (err < 0)
2033 mgmt_pending_remove(cmd);
2034
2035failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002036 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002037 hci_dev_put(hdev);
2038
2039 return err;
2040}
2041
Szymon Jancc35938b2011-03-22 13:12:21 +01002042static int read_local_oob_data(struct sock *sk, u16 index)
2043{
2044 struct hci_dev *hdev;
2045 struct pending_cmd *cmd;
2046 int err;
2047
2048 BT_DBG("hci%u", index);
2049
2050 hdev = hci_dev_get(index);
2051 if (!hdev)
2052 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002053 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01002054
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002055 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002056
2057 if (!test_bit(HCI_UP, &hdev->flags)) {
2058 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002059 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002060 goto unlock;
2061 }
2062
2063 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
2064 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002065 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002066 goto unlock;
2067 }
2068
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002069 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002070 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
2071 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002072 goto unlock;
2073 }
2074
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002075 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002076 if (!cmd) {
2077 err = -ENOMEM;
2078 goto unlock;
2079 }
2080
2081 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2082 if (err < 0)
2083 mgmt_pending_remove(cmd);
2084
2085unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002086 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002087 hci_dev_put(hdev);
2088
2089 return err;
2090}
2091
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002092static int add_remote_oob_data(struct sock *sk, u16 index, void *data,
2093 u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002094{
2095 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002096 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002097 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002098 int err;
2099
2100 BT_DBG("hci%u ", index);
2101
2102 if (len != sizeof(*cp))
2103 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002104 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002105
2106 hdev = hci_dev_get(index);
2107 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002108 return cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
2109 MGMT_STATUS_INVALID_PARAMS,
2110 &cp->addr, sizeof(cp->addr));
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 Hedbergbf1e3542012-02-19 13:16:14 +02002117 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002118 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002119 status = 0;
2120
2121 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
2122 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002123
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002124 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002125 hci_dev_put(hdev);
2126
2127 return err;
2128}
2129
2130static int remove_remote_oob_data(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002131 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002132{
2133 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002134 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002135 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002136 int err;
2137
2138 BT_DBG("hci%u ", index);
2139
2140 if (len != sizeof(*cp))
2141 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02002142 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01002143
2144 hdev = hci_dev_get(index);
2145 if (!hdev)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002146 return cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2147 MGMT_STATUS_INVALID_PARAMS,
2148 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002149
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002150 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002151
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002152 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002153 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002154 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002155 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002156 status = 0;
2157
2158 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA, status,
2159 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002160
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002161 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002162 hci_dev_put(hdev);
2163
2164 return err;
2165}
2166
Andre Guedes5e0452c2012-02-17 20:39:38 -03002167static int discovery(struct hci_dev *hdev)
2168{
2169 int err;
2170
2171 if (lmp_host_le_capable(hdev)) {
2172 if (lmp_bredr_capable(hdev)) {
2173 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2174 LE_SCAN_INT, LE_SCAN_WIN,
2175 LE_SCAN_TIMEOUT_BREDR_LE);
2176 } else {
2177 hdev->discovery.type = DISCOV_TYPE_LE;
2178 err = hci_le_scan(hdev, LE_SCAN_TYPE,
2179 LE_SCAN_INT, LE_SCAN_WIN,
2180 LE_SCAN_TIMEOUT_LE_ONLY);
2181 }
2182 } else {
2183 hdev->discovery.type = DISCOV_TYPE_BREDR;
2184 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2185 }
2186
2187 return err;
2188}
2189
2190int mgmt_interleaved_discovery(struct hci_dev *hdev)
2191{
2192 int err;
2193
2194 BT_DBG("%s", hdev->name);
2195
2196 hci_dev_lock(hdev);
2197
2198 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2199 if (err < 0)
2200 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2201
2202 hci_dev_unlock(hdev);
2203
2204 return err;
2205}
2206
Johan Hedberg450dfda2011-11-12 11:58:22 +02002207static int start_discovery(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002208 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002209{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002210 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002211 struct pending_cmd *cmd;
2212 struct hci_dev *hdev;
2213 int err;
2214
2215 BT_DBG("hci%u", index);
2216
Johan Hedberg450dfda2011-11-12 11:58:22 +02002217 if (len != sizeof(*cp))
2218 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2219 MGMT_STATUS_INVALID_PARAMS);
2220
Johan Hedberg14a53662011-04-27 10:29:56 -04002221 hdev = hci_dev_get(index);
2222 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002223 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2224 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002225
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002226 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002227
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002228 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02002229 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2230 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002231 goto failed;
2232 }
2233
Johan Hedbergff9ef572012-01-04 14:23:45 +02002234 if (hdev->discovery.state != DISCOVERY_STOPPED) {
2235 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
2236 MGMT_STATUS_BUSY);
2237 goto failed;
2238 }
2239
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002240 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002241 if (!cmd) {
2242 err = -ENOMEM;
2243 goto failed;
2244 }
2245
Andre Guedes4aab14e2012-02-17 20:39:36 -03002246 hdev->discovery.type = cp->type;
2247
2248 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002249 case DISCOV_TYPE_BREDR:
Andre Guedes3fd24152012-02-03 17:48:01 -03002250 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Andre Guedesf39799f2012-02-17 20:39:35 -03002251 break;
2252
2253 case DISCOV_TYPE_LE:
Andre Guedes3fd24152012-02-03 17:48:01 -03002254 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
2255 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedesf39799f2012-02-17 20:39:35 -03002256 break;
2257
Andre Guedes5e0452c2012-02-17 20:39:38 -03002258 case DISCOV_TYPE_INTERLEAVED:
2259 err = discovery(hdev);
2260 break;
2261
Andre Guedesf39799f2012-02-17 20:39:35 -03002262 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002263 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002264 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002265
Johan Hedberg14a53662011-04-27 10:29:56 -04002266 if (err < 0)
2267 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002268 else
2269 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002270
2271failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002272 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002273 hci_dev_put(hdev);
2274
2275 return err;
2276}
2277
2278static int stop_discovery(struct sock *sk, u16 index)
2279{
2280 struct hci_dev *hdev;
2281 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002282 struct hci_cp_remote_name_req_cancel cp;
2283 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002284 int err;
2285
2286 BT_DBG("hci%u", index);
2287
2288 hdev = hci_dev_get(index);
2289 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02002290 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2291 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04002292
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002293 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002294
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002295 if (!hci_discovery_active(hdev)) {
Johan Hedbergff9ef572012-01-04 14:23:45 +02002296 err = cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
2297 MGMT_STATUS_REJECTED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002298 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002299 }
2300
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002301 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002302 if (!cmd) {
2303 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002304 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002305 }
2306
Andre Guedes343f9352012-02-17 20:39:37 -03002307 if (hdev->discovery.state == DISCOVERY_FINDING) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002308 err = hci_cancel_inquiry(hdev);
2309 if (err < 0)
2310 mgmt_pending_remove(cmd);
2311 else
2312 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
2313 goto unlock;
2314 }
2315
2316 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY, NAME_PENDING);
2317 if (!e) {
2318 mgmt_pending_remove(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +02002319 err = cmd_complete(sk, index, MGMT_OP_STOP_DISCOVERY, 0,
2320 NULL, 0);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002321 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2322 goto unlock;
2323 }
2324
2325 bacpy(&cp.bdaddr, &e->data.bdaddr);
2326 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2327 sizeof(cp), &cp);
Johan Hedberg14a53662011-04-27 10:29:56 -04002328 if (err < 0)
2329 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002330 else
2331 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002332
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002333unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002334 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002335 hci_dev_put(hdev);
2336
2337 return err;
2338}
2339
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002340static int confirm_name(struct sock *sk, u16 index, void *data, u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002341{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002342 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002343 struct inquiry_entry *e;
2344 struct hci_dev *hdev;
2345 int err;
2346
2347 BT_DBG("hci%u", index);
2348
2349 if (len != sizeof(*cp))
2350 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2351 MGMT_STATUS_INVALID_PARAMS);
2352
2353 hdev = hci_dev_get(index);
2354 if (!hdev)
2355 return cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2356 MGMT_STATUS_INVALID_PARAMS);
2357
2358 hci_dev_lock(hdev);
2359
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002360 if (!hci_discovery_active(hdev)) {
2361 err = cmd_status(sk, index, MGMT_OP_CONFIRM_NAME,
2362 MGMT_STATUS_FAILED);
2363 goto failed;
2364 }
2365
Johan Hedberga198e7b2012-02-17 14:27:06 +02002366 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002367 if (!e) {
2368 err = cmd_status (sk, index, MGMT_OP_CONFIRM_NAME,
2369 MGMT_STATUS_INVALID_PARAMS);
2370 goto failed;
2371 }
2372
2373 if (cp->name_known) {
2374 e->name_state = NAME_KNOWN;
2375 list_del(&e->list);
2376 } else {
2377 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002378 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002379 }
2380
2381 err = 0;
2382
2383failed:
2384 hci_dev_unlock(hdev);
2385
2386 return err;
2387}
2388
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002389static int block_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002390{
2391 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002392 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002393 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002394 int err;
2395
2396 BT_DBG("hci%u", index);
2397
Antti Julku7fbec222011-06-15 12:01:15 +03002398 if (len != sizeof(*cp))
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
2402 hdev = hci_dev_get(index);
2403 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002404 return cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
2405 MGMT_STATUS_INVALID_PARAMS,
2406 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002407
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002408 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002409
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002410 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002411 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002412 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002413 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002414 status = 0;
2415
2416 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE, status,
2417 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002418
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002419 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002420 hci_dev_put(hdev);
2421
2422 return err;
2423}
2424
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002425static int unblock_device(struct sock *sk, u16 index, void *data, u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002426{
2427 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002428 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002429 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002430 int err;
2431
2432 BT_DBG("hci%u", index);
2433
Antti Julku7fbec222011-06-15 12:01:15 +03002434 if (len != sizeof(*cp))
2435 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002436 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002437
2438 hdev = hci_dev_get(index);
2439 if (!hdev)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002440 return cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2441 MGMT_STATUS_INVALID_PARAMS,
2442 &cp->addr, sizeof(cp->addr));
Antti Julku7fbec222011-06-15 12:01:15 +03002443
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002444 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002445
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002446 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002447 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002448 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002449 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002450 status = 0;
2451
2452 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE, status,
2453 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002454
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002455 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002456 hci_dev_put(hdev);
2457
2458 return err;
2459}
2460
Antti Julkuf6422ec2011-06-22 13:11:56 +03002461static int set_fast_connectable(struct sock *sk, u16 index,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002462 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002463{
2464 struct hci_dev *hdev;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002465 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002466 struct hci_cp_write_page_scan_activity acp;
2467 u8 type;
2468 int err;
2469
2470 BT_DBG("hci%u", index);
2471
2472 if (len != sizeof(*cp))
2473 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002474 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002475
2476 hdev = hci_dev_get(index);
2477 if (!hdev)
2478 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002479 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002480
2481 hci_dev_lock(hdev);
2482
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002483 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002484 type = PAGE_SCAN_TYPE_INTERLACED;
2485 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2486 } else {
2487 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2488 acp.interval = 0x0800; /* default 1.28 sec page scan */
2489 }
2490
2491 acp.window = 0x0012; /* default 11.25 msec page scan window */
2492
2493 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2494 sizeof(acp), &acp);
2495 if (err < 0) {
2496 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002497 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002498 goto done;
2499 }
2500
2501 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2502 if (err < 0) {
2503 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002504 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002505 goto done;
2506 }
2507
Johan Hedbergaee9b212012-02-18 15:07:59 +02002508 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE, 0,
2509 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002510done:
2511 hci_dev_unlock(hdev);
2512 hci_dev_put(hdev);
2513
2514 return err;
2515}
2516
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002517static int load_long_term_keys(struct sock *sk, u16 index,
2518 void *cp_data, u16 len)
2519{
2520 struct hci_dev *hdev;
2521 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2522 u16 key_count, expected_len;
2523 int i;
2524
2525 if (len < sizeof(*cp))
2526 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2527 EINVAL);
2528
2529 key_count = get_unaligned_le16(&cp->key_count);
2530
2531 expected_len = sizeof(*cp) + key_count *
2532 sizeof(struct mgmt_ltk_info);
2533 if (expected_len != len) {
2534 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2535 len, expected_len);
2536 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2537 EINVAL);
2538 }
2539
2540 hdev = hci_dev_get(index);
2541 if (!hdev)
2542 return cmd_status(sk, index, MGMT_OP_LOAD_LONG_TERM_KEYS,
2543 ENODEV);
2544
2545 BT_DBG("hci%u key_count %u", index, key_count);
2546
2547 hci_dev_lock(hdev);
2548
2549 hci_smp_ltks_clear(hdev);
2550
2551 for (i = 0; i < key_count; i++) {
2552 struct mgmt_ltk_info *key = &cp->keys[i];
2553 u8 type;
2554
2555 if (key->master)
2556 type = HCI_SMP_LTK;
2557 else
2558 type = HCI_SMP_LTK_SLAVE;
2559
2560 hci_add_ltk(hdev, &key->addr.bdaddr, key->addr.type,
2561 type, 0, key->authenticated, key->val,
2562 key->enc_size, key->ediv, key->rand);
2563 }
2564
2565 hci_dev_unlock(hdev);
2566 hci_dev_put(hdev);
2567
2568 return 0;
2569}
2570
Johan Hedberg03811012010-12-08 00:21:06 +02002571int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2572{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002573 void *buf;
2574 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002575 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002576 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002577 int err;
2578
2579 BT_DBG("got %zu bytes", msglen);
2580
2581 if (msglen < sizeof(*hdr))
2582 return -EINVAL;
2583
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002584 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002585 if (!buf)
2586 return -ENOMEM;
2587
2588 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2589 err = -EFAULT;
2590 goto done;
2591 }
2592
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002593 hdr = buf;
Johan Hedberg03811012010-12-08 00:21:06 +02002594 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002595 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002596 len = get_unaligned_le16(&hdr->len);
2597
2598 if (len != msglen - sizeof(*hdr)) {
2599 err = -EINVAL;
2600 goto done;
2601 }
2602
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002603 cp = buf + sizeof(*hdr);
2604
Johan Hedberg03811012010-12-08 00:21:06 +02002605 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002606 case MGMT_OP_READ_VERSION:
2607 err = read_version(sk);
2608 break;
Johan Hedberge70bb2e2012-02-13 16:59:33 +02002609 case MGMT_OP_READ_COMMANDS:
2610 err = read_commands(sk);
2611 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002612 case MGMT_OP_READ_INDEX_LIST:
2613 err = read_index_list(sk);
2614 break;
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002615 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002616 err = read_controller_info(sk, index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +02002617 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002618 case MGMT_OP_SET_POWERED:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002619 err = set_powered(sk, index, cp, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002620 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002621 case MGMT_OP_SET_DISCOVERABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002622 err = set_discoverable(sk, index, cp, len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002623 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002624 case MGMT_OP_SET_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002625 err = set_connectable(sk, index, cp, len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002626 break;
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002627 case MGMT_OP_SET_FAST_CONNECTABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002628 err = set_fast_connectable(sk, index, cp, len);
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002629 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002630 case MGMT_OP_SET_PAIRABLE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002631 err = set_pairable(sk, index, cp, len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002632 break;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02002633 case MGMT_OP_SET_LINK_SECURITY:
2634 err = set_link_security(sk, index, cp, len);
2635 break;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02002636 case MGMT_OP_SET_SSP:
2637 err = set_ssp(sk, index, cp, len);
2638 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002639 case MGMT_OP_ADD_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002640 err = add_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002641 break;
2642 case MGMT_OP_REMOVE_UUID:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002643 err = remove_uuid(sk, index, cp, len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002644 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002645 case MGMT_OP_SET_DEV_CLASS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002646 err = set_dev_class(sk, index, cp, len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002647 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002648 case MGMT_OP_LOAD_LINK_KEYS:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002649 err = load_link_keys(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002650 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002651 case MGMT_OP_DISCONNECT:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002652 err = disconnect(sk, index, cp, len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002653 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002654 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002655 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002656 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002657 case MGMT_OP_PIN_CODE_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002658 err = pin_code_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002659 break;
2660 case MGMT_OP_PIN_CODE_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002661 err = pin_code_neg_reply(sk, index, cp, len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002662 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002663 case MGMT_OP_SET_IO_CAPABILITY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002664 err = set_io_capability(sk, index, cp, len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002665 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002666 case MGMT_OP_PAIR_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002667 err = pair_device(sk, index, cp, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002668 break;
Johan Hedberg28424702012-02-02 04:02:29 +02002669 case MGMT_OP_CANCEL_PAIR_DEVICE:
2670 err = cancel_pair_device(sk, index, buf + sizeof(*hdr), len);
2671 break;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002672 case MGMT_OP_UNPAIR_DEVICE:
2673 err = unpair_device(sk, index, cp, len);
2674 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002675 case MGMT_OP_USER_CONFIRM_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002676 err = user_confirm_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002677 break;
2678 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002679 err = user_confirm_neg_reply(sk, index, cp, len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002680 break;
Brian Gix604086b2011-11-23 08:28:33 -08002681 case MGMT_OP_USER_PASSKEY_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002682 err = user_passkey_reply(sk, index, cp, len);
Brian Gix604086b2011-11-23 08:28:33 -08002683 break;
2684 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002685 err = user_passkey_neg_reply(sk, index, cp, len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002686 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002687 case MGMT_OP_SET_LOCAL_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002688 err = set_local_name(sk, index, cp, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002689 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002690 case MGMT_OP_READ_LOCAL_OOB_DATA:
2691 err = read_local_oob_data(sk, index);
2692 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002693 case MGMT_OP_ADD_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002694 err = add_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002695 break;
2696 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002697 err = remove_remote_oob_data(sk, index, cp, len);
Szymon Janc2763eda2011-03-22 13:12:22 +01002698 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002699 case MGMT_OP_START_DISCOVERY:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002700 err = start_discovery(sk, index, cp, len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002701 break;
2702 case MGMT_OP_STOP_DISCOVERY:
2703 err = stop_discovery(sk, index);
2704 break;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002705 case MGMT_OP_CONFIRM_NAME:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002706 err = confirm_name(sk, index, cp, len);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002707 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002708 case MGMT_OP_BLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002709 err = block_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002710 break;
2711 case MGMT_OP_UNBLOCK_DEVICE:
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002712 err = unblock_device(sk, index, cp, len);
Antti Julku7fbec222011-06-15 12:01:15 +03002713 break;
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002714 case MGMT_OP_LOAD_LONG_TERM_KEYS:
2715 err = load_long_term_keys(sk, index, cp, len);
2716 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002717 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002718 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002719 err = cmd_status(sk, index, opcode,
2720 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002721 break;
2722 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002723
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002724 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002725 goto done;
2726
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002727 err = msglen;
2728
2729done:
2730 kfree(buf);
2731 return err;
2732}
2733
Johan Hedbergb24752f2011-11-03 14:40:33 +02002734static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2735{
2736 u8 *status = data;
2737
2738 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2739 mgmt_pending_remove(cmd);
2740}
2741
Johan Hedberg744cf192011-11-08 20:40:14 +02002742int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002743{
Johan Hedberg744cf192011-11-08 20:40:14 +02002744 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002745}
2746
Johan Hedberg744cf192011-11-08 20:40:14 +02002747int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002748{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002749 u8 status = ENODEV;
2750
Johan Hedberg744cf192011-11-08 20:40:14 +02002751 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002752
Johan Hedberg744cf192011-11-08 20:40:14 +02002753 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002754}
2755
2756struct cmd_lookup {
Johan Hedberg03811012010-12-08 00:21:06 +02002757 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002758 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +02002759};
2760
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002761static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberg03811012010-12-08 00:21:06 +02002762{
Johan Hedberg03811012010-12-08 00:21:06 +02002763 struct cmd_lookup *match = data;
2764
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002765 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedberg03811012010-12-08 00:21:06 +02002766
2767 list_del(&cmd->list);
2768
2769 if (match->sk == NULL) {
2770 match->sk = cmd->sk;
2771 sock_hold(match->sk);
2772 }
2773
2774 mgmt_pending_free(cmd);
2775}
2776
Johan Hedberg744cf192011-11-08 20:40:14 +02002777int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002778{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002779 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002780 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002781 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002782
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002783 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002784
Johan Hedbergb24752f2011-11-03 14:40:33 +02002785 if (!powered) {
2786 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002787 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002788 }
2789
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002790 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002791
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002792 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002793 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002794
2795 if (match.sk)
2796 sock_put(match.sk);
2797
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002798 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002799}
2800
Johan Hedberg744cf192011-11-08 20:40:14 +02002801int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002802{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002803 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002804 __le32 ev;
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002805 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002806
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002807 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002808
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002809 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002810
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002811 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002812 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002813 if (match.sk)
2814 sock_put(match.sk);
2815
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002816 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002817}
2818
Johan Hedberg744cf192011-11-08 20:40:14 +02002819int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002820{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002821 __le32 ev;
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002822 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002823 int err;
Johan Hedberg03811012010-12-08 00:21:06 +02002824
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002825 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2826 &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002827
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002828 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg03811012010-12-08 00:21:06 +02002829
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002830 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002831
2832 if (match.sk)
2833 sock_put(match.sk);
2834
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002835 return err;
Johan Hedberg03811012010-12-08 00:21:06 +02002836}
2837
Johan Hedberg744cf192011-11-08 20:40:14 +02002838int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002839{
Johan Hedbergca69b792011-11-11 18:10:00 +02002840 u8 mgmt_err = mgmt_status(status);
2841
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002842 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002843 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002844 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002845
2846 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002847 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002848 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002849
2850 return 0;
2851}
2852
Johan Hedberg744cf192011-11-08 20:40:14 +02002853int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2854 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002855{
Johan Hedberg86742e12011-11-07 23:13:38 +02002856 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002857
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002858 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002859
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002860 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002861 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2862 ev.key.addr.type = MGMT_ADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002863 ev.key.type = key->type;
2864 memcpy(ev.key.val, key->val, 16);
2865 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002866
Johan Hedberg744cf192011-11-08 20:40:14 +02002867 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002868}
Johan Hedbergf7520542011-01-20 12:34:39 +02002869
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002870int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2871{
2872 struct mgmt_ev_new_long_term_key ev;
2873
2874 memset(&ev, 0, sizeof(ev));
2875
2876 ev.store_hint = persistent;
2877 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
2878 ev.key.addr.type = key->bdaddr_type;
2879 ev.key.authenticated = key->authenticated;
2880 ev.key.enc_size = key->enc_size;
2881 ev.key.ediv = key->ediv;
2882
2883 if (key->type == HCI_SMP_LTK)
2884 ev.key.master = 1;
2885
2886 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2887 memcpy(ev.key.val, key->val, sizeof(key->val));
2888
2889 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev,
2890 &ev, sizeof(ev), NULL);
2891}
2892
Johan Hedbergafc747a2012-01-15 18:11:07 +02002893int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedbergb644ba32012-01-17 21:48:47 +02002894 u8 addr_type, u8 *name, u8 name_len,
2895 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002896{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002897 char buf[512];
2898 struct mgmt_ev_device_connected *ev = (void *) buf;
2899 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002900
Johan Hedbergb644ba32012-01-17 21:48:47 +02002901 bacpy(&ev->addr.bdaddr, bdaddr);
2902 ev->addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002903
Johan Hedbergb644ba32012-01-17 21:48:47 +02002904 if (name_len > 0)
2905 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
2906 name, name_len);
2907
2908 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
2909 eir_len = eir_append_data(&ev->eir[eir_len], eir_len,
2910 EIR_CLASS_OF_DEV, dev_class, 3);
2911
2912 put_unaligned_le16(eir_len, &ev->eir_len);
2913
2914 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
2915 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002916}
2917
Johan Hedberg8962ee72011-01-20 12:40:27 +02002918static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2919{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002920 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002921 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002922 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002923
Johan Hedberg88c3df12012-02-09 14:27:38 +02002924 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2925 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002926
Johan Hedbergaee9b212012-02-18 15:07:59 +02002927 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
2928 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002929
2930 *sk = cmd->sk;
2931 sock_hold(*sk);
2932
Johan Hedberga664b5b2011-02-19 12:06:02 -03002933 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002934}
2935
Johan Hedberg124f6e32012-02-09 13:50:12 +02002936static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02002937{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002938 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02002939 struct mgmt_cp_unpair_device *cp = cmd->param;
2940 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002941
2942 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02002943 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
2944 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02002945
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002946 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
2947
Johan Hedbergaee9b212012-02-18 15:07:59 +02002948 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02002949
2950 mgmt_pending_remove(cmd);
2951}
2952
Johan Hedbergafc747a2012-01-15 18:11:07 +02002953int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
2954 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002955{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002956 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002957 struct sock *sk = NULL;
2958 int err;
2959
Johan Hedberg744cf192011-11-08 20:40:14 +02002960 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002961
Johan Hedbergf7520542011-01-20 12:34:39 +02002962 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002963 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002964
Johan Hedbergafc747a2012-01-15 18:11:07 +02002965 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
2966 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002967
2968 if (sk)
2969 sock_put(sk);
2970
Johan Hedberg124f6e32012-02-09 13:50:12 +02002971 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002972 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02002973
Johan Hedberg8962ee72011-01-20 12:40:27 +02002974 return err;
2975}
2976
Johan Hedberg88c3df12012-02-09 14:27:38 +02002977int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
2978 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002979{
Johan Hedberg88c3df12012-02-09 14:27:38 +02002980 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002981 struct pending_cmd *cmd;
2982 int err;
2983
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002984 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002985 if (!cmd)
2986 return -ENOENT;
2987
Johan Hedberg88c3df12012-02-09 14:27:38 +02002988 bacpy(&rp.addr.bdaddr, bdaddr);
2989 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002990
Johan Hedberg88c3df12012-02-09 14:27:38 +02002991 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Johan Hedbergaee9b212012-02-18 15:07:59 +02002992 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002993
Johan Hedberga664b5b2011-02-19 12:06:02 -03002994 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002995
Johan Hedbergb1078ad2012-02-09 17:21:16 +02002996 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
2997 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002998 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002999}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003000
Johan Hedberg48264f02011-11-09 13:58:58 +02003001int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3002 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003003{
3004 struct mgmt_ev_connect_failed ev;
3005
Johan Hedberg4c659c32011-11-07 23:13:39 +02003006 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02003007 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003008 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003009
Johan Hedberg744cf192011-11-08 20:40:14 +02003010 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003011}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003012
Johan Hedberg744cf192011-11-08 20:40:14 +02003013int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003014{
3015 struct mgmt_ev_pin_code_request ev;
3016
Johan Hedbergd8457692012-02-17 14:24:57 +02003017 bacpy(&ev.addr.bdaddr, bdaddr);
3018 ev.addr.type = MGMT_ADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003019 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003020
Johan Hedberg744cf192011-11-08 20:40:14 +02003021 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003022 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003023}
3024
Johan Hedberg744cf192011-11-08 20:40:14 +02003025int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3026 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003027{
3028 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003029 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003030 int err;
3031
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003032 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003033 if (!cmd)
3034 return -ENOENT;
3035
Johan Hedbergd8457692012-02-17 14:24:57 +02003036 bacpy(&rp.addr.bdaddr, bdaddr);
3037 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003038
Johan Hedbergaee9b212012-02-18 15:07:59 +02003039 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
3040 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003041
Johan Hedberga664b5b2011-02-19 12:06:02 -03003042 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003043
3044 return err;
3045}
3046
Johan Hedberg744cf192011-11-08 20:40:14 +02003047int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3048 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003049{
3050 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003051 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003052 int err;
3053
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003054 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003055 if (!cmd)
3056 return -ENOENT;
3057
Johan Hedbergd8457692012-02-17 14:24:57 +02003058 bacpy(&rp.addr.bdaddr, bdaddr);
3059 rp.addr.type = MGMT_ADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003060
Johan Hedbergaee9b212012-02-18 15:07:59 +02003061 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
3062 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003063
Johan Hedberga664b5b2011-02-19 12:06:02 -03003064 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003065
3066 return err;
3067}
Johan Hedberga5c29682011-02-19 12:05:57 -03003068
Johan Hedberg744cf192011-11-08 20:40:14 +02003069int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003070 u8 link_type, u8 addr_type, __le32 value,
3071 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003072{
3073 struct mgmt_ev_user_confirm_request ev;
3074
Johan Hedberg744cf192011-11-08 20:40:14 +02003075 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003076
Johan Hedberg272d90d2012-02-09 15:26:12 +02003077 bacpy(&ev.addr.bdaddr, bdaddr);
3078 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003079 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03003080 put_unaligned_le32(value, &ev.value);
3081
Johan Hedberg744cf192011-11-08 20:40:14 +02003082 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01003083 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003084}
3085
Johan Hedberg272d90d2012-02-09 15:26:12 +02003086int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3087 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003088{
3089 struct mgmt_ev_user_passkey_request ev;
3090
3091 BT_DBG("%s", hdev->name);
3092
Johan Hedberg272d90d2012-02-09 15:26:12 +02003093 bacpy(&ev.addr.bdaddr, bdaddr);
3094 ev.addr.type = link_to_mgmt(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003095
3096 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
3097 NULL);
3098}
3099
Brian Gix0df4c182011-11-16 13:53:13 -08003100static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003101 u8 link_type, u8 addr_type, u8 status,
3102 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003103{
3104 struct pending_cmd *cmd;
3105 struct mgmt_rp_user_confirm_reply rp;
3106 int err;
3107
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003108 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003109 if (!cmd)
3110 return -ENOENT;
3111
Johan Hedberg272d90d2012-02-09 15:26:12 +02003112 bacpy(&rp.addr.bdaddr, bdaddr);
3113 rp.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003114 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
3115 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003116
Johan Hedberga664b5b2011-02-19 12:06:02 -03003117 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003118
3119 return err;
3120}
3121
Johan Hedberg744cf192011-11-08 20:40:14 +02003122int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003123 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003124{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003125 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3126 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003127}
3128
Johan Hedberg272d90d2012-02-09 15:26:12 +02003129int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3130 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003131{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003132 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3133 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003134}
Johan Hedberg2a611692011-02-19 12:06:00 -03003135
Brian Gix604086b2011-11-23 08:28:33 -08003136int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003137 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003138{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003139 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3140 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003141}
3142
Johan Hedberg272d90d2012-02-09 15:26:12 +02003143int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
3144 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003145{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003146 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
3147 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003148}
3149
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003150int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3151 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003152{
3153 struct mgmt_ev_auth_failed ev;
3154
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003155 bacpy(&ev.addr.bdaddr, bdaddr);
3156 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003157 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003158
Johan Hedberg744cf192011-11-08 20:40:14 +02003159 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003160}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003161
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003162int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3163{
3164 struct cmd_lookup match = { NULL, hdev };
3165 __le32 ev;
3166 int err;
3167
3168 if (status) {
3169 u8 mgmt_err = mgmt_status(status);
3170 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
3171 cmd_status_rsp, &mgmt_err);
3172 return 0;
3173 }
3174
3175 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
3176 &match);
3177
3178 ev = cpu_to_le32(get_current_settings(hdev));
3179 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3180
3181 if (match.sk)
3182 sock_put(match.sk);
3183
3184 return err;
3185}
3186
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003187int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 status)
3188{
3189 struct cmd_lookup match = { NULL, hdev };
3190 __le32 ev;
3191 int err;
3192
3193 if (status) {
3194 u8 mgmt_err = mgmt_status(status);
3195 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev,
3196 cmd_status_rsp, &mgmt_err);
3197 return 0;
3198 }
3199
3200 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3201
3202 ev = cpu_to_le32(get_current_settings(hdev));
3203 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
3204
3205 if (match.sk)
3206 sock_put(match.sk);
3207
3208 return err;
3209}
3210
Johan Hedberg744cf192011-11-08 20:40:14 +02003211int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003212{
3213 struct pending_cmd *cmd;
3214 struct mgmt_cp_set_local_name ev;
3215 int err;
3216
3217 memset(&ev, 0, sizeof(ev));
3218 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
3219
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003220 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003221 if (!cmd)
3222 goto send_event;
3223
3224 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003225 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02003226 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003227 goto failed;
3228 }
3229
Johan Hedberg744cf192011-11-08 20:40:14 +02003230 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03003231
Johan Hedbergaee9b212012-02-18 15:07:59 +02003232 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02003233 sizeof(ev));
3234 if (err < 0)
3235 goto failed;
3236
3237send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02003238 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02003239 cmd ? cmd->sk : NULL);
3240
3241failed:
3242 if (cmd)
3243 mgmt_pending_remove(cmd);
3244 return err;
3245}
Szymon Jancc35938b2011-03-22 13:12:21 +01003246
Johan Hedberg744cf192011-11-08 20:40:14 +02003247int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
3248 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003249{
3250 struct pending_cmd *cmd;
3251 int err;
3252
Johan Hedberg744cf192011-11-08 20:40:14 +02003253 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003254
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003255 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003256 if (!cmd)
3257 return -ENOENT;
3258
3259 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003260 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02003261 MGMT_OP_READ_LOCAL_OOB_DATA,
3262 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003263 } else {
3264 struct mgmt_rp_read_local_oob_data rp;
3265
3266 memcpy(rp.hash, hash, sizeof(rp.hash));
3267 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3268
Johan Hedberg744cf192011-11-08 20:40:14 +02003269 err = cmd_complete(cmd->sk, hdev->id,
3270 MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergaee9b212012-02-18 15:07:59 +02003271 0, &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003272 }
3273
3274 mgmt_pending_remove(cmd);
3275
3276 return err;
3277}
Johan Hedberge17acd42011-03-30 23:57:16 +03003278
Johan Hedberg48264f02011-11-09 13:58:58 +02003279int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Johan Hedberg561aafb2012-01-04 13:31:59 +02003280 u8 addr_type, u8 *dev_class, s8 rssi,
Johan Hedberge319d2e2012-01-15 19:51:59 +02003281 u8 cfm_name, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003282{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003283 char buf[512];
3284 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003285 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003286
Johan Hedberg1dc06092012-01-15 21:01:23 +02003287 /* Leave 5 bytes for a potential CoD field */
3288 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003289 return -EINVAL;
3290
Johan Hedberg1dc06092012-01-15 21:01:23 +02003291 memset(buf, 0, sizeof(buf));
3292
Johan Hedberge319d2e2012-01-15 19:51:59 +02003293 bacpy(&ev->addr.bdaddr, bdaddr);
3294 ev->addr.type = link_to_mgmt(link_type, addr_type);
3295 ev->rssi = rssi;
3296 ev->confirm_name = cfm_name;
Johan Hedberge17acd42011-03-30 23:57:16 +03003297
Johan Hedberg1dc06092012-01-15 21:01:23 +02003298 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003299 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003300
Johan Hedberg1dc06092012-01-15 21:01:23 +02003301 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3302 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
3303 dev_class, 3);
3304
3305 put_unaligned_le16(eir_len, &ev->eir_len);
3306
3307 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003308
Johan Hedberge319d2e2012-01-15 19:51:59 +02003309 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003310}
Johan Hedberga88a9652011-03-30 13:18:12 +03003311
Johan Hedbergb644ba32012-01-17 21:48:47 +02003312int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
3313 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003314{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003315 struct mgmt_ev_device_found *ev;
3316 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3317 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003318
Johan Hedbergb644ba32012-01-17 21:48:47 +02003319 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003320
Johan Hedbergb644ba32012-01-17 21:48:47 +02003321 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003322
Johan Hedbergb644ba32012-01-17 21:48:47 +02003323 bacpy(&ev->addr.bdaddr, bdaddr);
3324 ev->addr.type = link_to_mgmt(link_type, addr_type);
3325 ev->rssi = rssi;
3326
3327 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
3328 name_len);
3329
3330 put_unaligned_le16(eir_len, &ev->eir_len);
3331
Johan Hedberg053c7e02012-02-04 00:06:00 +02003332 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
3333 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003334}
Johan Hedberg314b2382011-04-27 10:29:57 -04003335
Andre Guedes7a135102011-11-09 17:14:25 -03003336int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003337{
3338 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003339 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003340 int err;
3341
Andre Guedes203159d2012-02-13 15:41:01 -03003342 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3343
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003344 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003345 if (!cmd)
3346 return -ENOENT;
3347
Johan Hedbergf808e162012-02-19 12:52:07 +02003348 type = hdev->discovery.type;
3349
3350 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
3351 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003352 mgmt_pending_remove(cmd);
3353
3354 return err;
3355}
3356
Andre Guedese6d465c2011-11-09 17:14:26 -03003357int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3358{
3359 struct pending_cmd *cmd;
3360 int err;
3361
3362 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3363 if (!cmd)
3364 return -ENOENT;
3365
Andre Guedese75a8b0c2012-01-02 16:50:53 -03003366 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg03811012010-12-08 00:21:06 +02003367 mgmt_pending_remove(cmd);
3368
3369 return err;
3370}
Johan Hedberg314b2382011-04-27 10:29:57 -04003371
Johan Hedberg744cf192011-11-08 20:40:14 +02003372int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003373{
Johan Hedberg164a6e72011-11-01 17:06:44 +02003374 struct pending_cmd *cmd;
3375
Andre Guedes343fb142011-11-22 17:14:19 -03003376 BT_DBG("%s discovering %u", hdev->name, discovering);
3377
Johan Hedberg164a6e72011-11-01 17:06:44 +02003378 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003379 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003380 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003381 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003382
3383 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003384 u8 type = hdev->discovery.type;
3385
3386 if (discovering)
3387 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
3388 &type, sizeof(type));
3389 else
3390 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0,
3391 NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003392 mgmt_pending_remove(cmd);
3393 }
3394
Johan Hedberg744cf192011-11-08 20:40:14 +02003395 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04003396 sizeof(discovering), NULL);
3397}
Antti Julku5e762442011-08-25 16:48:02 +03003398
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003399int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003400{
3401 struct pending_cmd *cmd;
3402 struct mgmt_ev_device_blocked ev;
3403
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003404 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003405
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003406 bacpy(&ev.addr.bdaddr, bdaddr);
3407 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003408
Johan Hedberg744cf192011-11-08 20:40:14 +02003409 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
3410 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003411}
3412
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003413int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003414{
3415 struct pending_cmd *cmd;
3416 struct mgmt_ev_device_unblocked ev;
3417
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003418 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003419
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003420 bacpy(&ev.addr.bdaddr, bdaddr);
3421 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003422
Johan Hedberg744cf192011-11-08 20:40:14 +02003423 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
3424 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003425}