blob: 966f6bcfbcb97dd3cb085c64450335c3cac70940 [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
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010037bool enable_hs;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010038
Johan Hedberg2da9c552012-02-17 14:39:28 +020039#define MGMT_VERSION 1
Marcel Holtmann053262d2012-03-27 18:49:02 +020040#define MGMT_REVISION 1
Johan Hedberg02d98122010-12-13 21:07:04 +020041
Johan Hedberge70bb2e2012-02-13 16:59:33 +020042static const u16 mgmt_commands[] = {
43 MGMT_OP_READ_INDEX_LIST,
44 MGMT_OP_READ_INFO,
45 MGMT_OP_SET_POWERED,
46 MGMT_OP_SET_DISCOVERABLE,
47 MGMT_OP_SET_CONNECTABLE,
48 MGMT_OP_SET_FAST_CONNECTABLE,
49 MGMT_OP_SET_PAIRABLE,
50 MGMT_OP_SET_LINK_SECURITY,
51 MGMT_OP_SET_SSP,
52 MGMT_OP_SET_HS,
53 MGMT_OP_SET_LE,
54 MGMT_OP_SET_DEV_CLASS,
55 MGMT_OP_SET_LOCAL_NAME,
56 MGMT_OP_ADD_UUID,
57 MGMT_OP_REMOVE_UUID,
58 MGMT_OP_LOAD_LINK_KEYS,
59 MGMT_OP_LOAD_LONG_TERM_KEYS,
60 MGMT_OP_DISCONNECT,
61 MGMT_OP_GET_CONNECTIONS,
62 MGMT_OP_PIN_CODE_REPLY,
63 MGMT_OP_PIN_CODE_NEG_REPLY,
64 MGMT_OP_SET_IO_CAPABILITY,
65 MGMT_OP_PAIR_DEVICE,
66 MGMT_OP_CANCEL_PAIR_DEVICE,
67 MGMT_OP_UNPAIR_DEVICE,
68 MGMT_OP_USER_CONFIRM_REPLY,
69 MGMT_OP_USER_CONFIRM_NEG_REPLY,
70 MGMT_OP_USER_PASSKEY_REPLY,
71 MGMT_OP_USER_PASSKEY_NEG_REPLY,
72 MGMT_OP_READ_LOCAL_OOB_DATA,
73 MGMT_OP_ADD_REMOTE_OOB_DATA,
74 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
75 MGMT_OP_START_DISCOVERY,
76 MGMT_OP_STOP_DISCOVERY,
77 MGMT_OP_CONFIRM_NAME,
78 MGMT_OP_BLOCK_DEVICE,
79 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070080 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020081};
82
83static const u16 mgmt_events[] = {
84 MGMT_EV_CONTROLLER_ERROR,
85 MGMT_EV_INDEX_ADDED,
86 MGMT_EV_INDEX_REMOVED,
87 MGMT_EV_NEW_SETTINGS,
88 MGMT_EV_CLASS_OF_DEV_CHANGED,
89 MGMT_EV_LOCAL_NAME_CHANGED,
90 MGMT_EV_NEW_LINK_KEY,
91 MGMT_EV_NEW_LONG_TERM_KEY,
92 MGMT_EV_DEVICE_CONNECTED,
93 MGMT_EV_DEVICE_DISCONNECTED,
94 MGMT_EV_CONNECT_FAILED,
95 MGMT_EV_PIN_CODE_REQUEST,
96 MGMT_EV_USER_CONFIRM_REQUEST,
97 MGMT_EV_USER_PASSKEY_REQUEST,
98 MGMT_EV_AUTH_FAILED,
99 MGMT_EV_DEVICE_FOUND,
100 MGMT_EV_DISCOVERING,
101 MGMT_EV_DEVICE_BLOCKED,
102 MGMT_EV_DEVICE_UNBLOCKED,
103 MGMT_EV_DEVICE_UNPAIRED,
104};
105
Andre Guedes3fd24152012-02-03 17:48:01 -0300106/*
107 * These LE scan and inquiry parameters were chosen according to LE General
108 * Discovery Procedure specification.
109 */
110#define LE_SCAN_TYPE 0x01
111#define LE_SCAN_WIN 0x12
112#define LE_SCAN_INT 0x12
113#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300114#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300115
Andre Guedese8777522012-02-03 17:48:02 -0300116#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300117#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300118
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800119#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200120
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200121#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
122 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
123
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200124struct pending_cmd {
125 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200126 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100128 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300130 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200131};
132
Johan Hedbergca69b792011-11-11 18:10:00 +0200133/* HCI to MGMT error code conversion table */
134static u8 mgmt_status_table[] = {
135 MGMT_STATUS_SUCCESS,
136 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
137 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
138 MGMT_STATUS_FAILED, /* Hardware Failure */
139 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
140 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
141 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
142 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
143 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
144 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
145 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
146 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
147 MGMT_STATUS_BUSY, /* Command Disallowed */
148 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
149 MGMT_STATUS_REJECTED, /* Rejected Security */
150 MGMT_STATUS_REJECTED, /* Rejected Personal */
151 MGMT_STATUS_TIMEOUT, /* Host Timeout */
152 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
153 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
154 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
155 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
156 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
157 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
158 MGMT_STATUS_BUSY, /* Repeated Attempts */
159 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
160 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
161 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
162 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
163 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
164 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
165 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
166 MGMT_STATUS_FAILED, /* Unspecified Error */
167 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
168 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
169 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
170 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
171 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
172 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
173 MGMT_STATUS_FAILED, /* Unit Link Key Used */
174 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
175 MGMT_STATUS_TIMEOUT, /* Instant Passed */
176 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
177 MGMT_STATUS_FAILED, /* Transaction Collision */
178 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
179 MGMT_STATUS_REJECTED, /* QoS Rejected */
180 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
181 MGMT_STATUS_REJECTED, /* Insufficient Security */
182 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
183 MGMT_STATUS_BUSY, /* Role Switch Pending */
184 MGMT_STATUS_FAILED, /* Slot Violation */
185 MGMT_STATUS_FAILED, /* Role Switch Failed */
186 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
187 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
188 MGMT_STATUS_BUSY, /* Host Busy Pairing */
189 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
190 MGMT_STATUS_BUSY, /* Controller Busy */
191 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
192 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
193 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
194 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
195 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
196};
197
198static u8 mgmt_status(u8 hci_status)
199{
200 if (hci_status < ARRAY_SIZE(mgmt_status_table))
201 return mgmt_status_table[hci_status];
202
203 return MGMT_STATUS_FAILED;
204}
205
Szymon Janc4e51eae2011-02-25 19:05:48 +0100206static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200207{
208 struct sk_buff *skb;
209 struct mgmt_hdr *hdr;
210 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300211 int err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200212
Szymon Janc34eb5252011-02-28 14:10:08 +0100213 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200214
215 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
216 if (!skb)
217 return -ENOMEM;
218
219 hdr = (void *) skb_put(skb, sizeof(*hdr));
220
221 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100222 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200223 hdr->len = cpu_to_le16(sizeof(*ev));
224
225 ev = (void *) skb_put(skb, sizeof(*ev));
226 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200227 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200228
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300229 err = sock_queue_rcv_skb(sk, skb);
230 if (err < 0)
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200231 kfree_skb(skb);
232
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300233 return err;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200234}
235
Johan Hedbergaee9b212012-02-18 15:07:59 +0200236static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300237 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200238{
239 struct sk_buff *skb;
240 struct mgmt_hdr *hdr;
241 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300242 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200243
244 BT_DBG("sock %p", sk);
245
Johan Hedberga38528f2011-01-22 06:46:43 +0200246 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200247 if (!skb)
248 return -ENOMEM;
249
250 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200251
Johan Hedberg02d98122010-12-13 21:07:04 +0200252 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200255
Johan Hedberga38528f2011-01-22 06:46:43 +0200256 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200257 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b212012-02-18 15:07:59 +0200258 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100259
260 if (rp)
261 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200262
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300263 err = sock_queue_rcv_skb(sk, skb);
264 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200265 kfree_skb(skb);
266
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100267 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200268}
269
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300270static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
271 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200272{
273 struct mgmt_rp_read_version rp;
274
275 BT_DBG("sock %p", sk);
276
277 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200278 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200279
Johan Hedbergaee9b212012-02-18 15:07:59 +0200280 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300281 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200282}
283
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300284static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
285 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200286{
287 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200288 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
289 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200290 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200291 size_t rp_size;
292 int i, err;
293
294 BT_DBG("sock %p", sk);
295
296 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
297
298 rp = kmalloc(rp_size, GFP_KERNEL);
299 if (!rp)
300 return -ENOMEM;
301
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200302 rp->num_commands = __constant_cpu_to_le16(num_commands);
303 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200304
305 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
306 put_unaligned_le16(mgmt_commands[i], opcode);
307
308 for (i = 0; i < num_events; i++, opcode++)
309 put_unaligned_le16(mgmt_events[i], opcode);
310
Johan Hedbergaee9b212012-02-18 15:07:59 +0200311 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300312 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200313 kfree(rp);
314
315 return err;
316}
317
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300318static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
319 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200320{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200321 struct mgmt_rp_read_index_list *rp;
322 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200323 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200324 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200325 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200327
328 BT_DBG("sock %p", sk);
329
330 read_lock(&hci_dev_list_lock);
331
332 count = 0;
333 list_for_each(p, &hci_dev_list) {
334 count++;
335 }
336
Johan Hedberga38528f2011-01-22 06:46:43 +0200337 rp_len = sizeof(*rp) + (2 * count);
338 rp = kmalloc(rp_len, GFP_ATOMIC);
339 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100340 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100342 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200343
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200344 rp->num_controllers = cpu_to_le16(count);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200345
346 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200347 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200348 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200349 continue;
350
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200351 rp->index[i++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200352 BT_DBG("Added hci%u", d->id);
353 }
354
355 read_unlock(&hci_dev_list_lock);
356
Johan Hedbergaee9b212012-02-18 15:07:59 +0200357 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300358 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200359
Johan Hedberga38528f2011-01-22 06:46:43 +0200360 kfree(rp);
361
362 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200363}
364
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200366{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200368
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200369 settings |= MGMT_SETTING_POWERED;
370 settings |= MGMT_SETTING_CONNECTABLE;
371 settings |= MGMT_SETTING_FAST_CONNECTABLE;
372 settings |= MGMT_SETTING_DISCOVERABLE;
373 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200374
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200375 if (hdev->features[6] & LMP_SIMPLE_PAIR)
376 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200377
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200378 if (!(hdev->features[4] & LMP_NO_BREDR)) {
379 settings |= MGMT_SETTING_BREDR;
380 settings |= MGMT_SETTING_LINK_SECURITY;
381 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200382
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100383 if (enable_hs)
384 settings |= MGMT_SETTING_HS;
385
Marcel Holtmann9d428202012-05-03 07:12:31 +0200386 if (hdev->features[4] & LMP_LE)
387 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200388
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200389 return settings;
390}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200391
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200392static u32 get_current_settings(struct hci_dev *hdev)
393{
394 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200395
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200396 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100397 settings |= MGMT_SETTING_POWERED;
398
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200399 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200400 settings |= MGMT_SETTING_CONNECTABLE;
401
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200402 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200403 settings |= MGMT_SETTING_DISCOVERABLE;
404
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200405 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200406 settings |= MGMT_SETTING_PAIRABLE;
407
408 if (!(hdev->features[4] & LMP_NO_BREDR))
409 settings |= MGMT_SETTING_BREDR;
410
Johan Hedberg06199cf2012-02-22 16:37:11 +0200411 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200412 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200413
Johan Hedberg47990ea2012-02-22 11:58:37 +0200414 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200415 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200416
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200417 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200419
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200420 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
421 settings |= MGMT_SETTING_HS;
422
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200423 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200424}
425
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300426#define PNP_INFO_SVCLASS_ID 0x1200
427
428static u8 bluetooth_base_uuid[] = {
429 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
430 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
431};
432
433static u16 get_uuid16(u8 *uuid128)
434{
435 u32 val;
436 int i;
437
438 for (i = 0; i < 12; i++) {
439 if (bluetooth_base_uuid[i] != uuid128[i])
440 return 0;
441 }
442
Andrei Emeltchenko3e9fb6d2012-03-20 10:32:25 +0200443 val = get_unaligned_le32(&uuid128[12]);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300444 if (val > 0xffff)
445 return 0;
446
447 return (u16) val;
448}
449
450static void create_eir(struct hci_dev *hdev, u8 *data)
451{
452 u8 *ptr = data;
453 u16 eir_len = 0;
454 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
455 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200456 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300457 size_t name_len;
458
459 name_len = strlen(hdev->dev_name);
460
461 if (name_len > 0) {
462 /* EIR Data type */
463 if (name_len > 48) {
464 name_len = 48;
465 ptr[1] = EIR_NAME_SHORT;
466 } else
467 ptr[1] = EIR_NAME_COMPLETE;
468
469 /* EIR Data length */
470 ptr[0] = name_len + 1;
471
472 memcpy(ptr + 2, hdev->dev_name, name_len);
473
474 eir_len += (name_len + 2);
475 ptr += (name_len + 2);
476 }
477
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700478 if (hdev->inq_tx_power) {
479 ptr[0] = 2;
480 ptr[1] = EIR_TX_POWER;
481 ptr[2] = (u8) hdev->inq_tx_power;
482
483 eir_len += 3;
484 ptr += 3;
485 }
486
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700487 if (hdev->devid_source > 0) {
488 ptr[0] = 9;
489 ptr[1] = EIR_DEVICE_ID;
490
491 put_unaligned_le16(hdev->devid_source, ptr + 2);
492 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
493 put_unaligned_le16(hdev->devid_product, ptr + 6);
494 put_unaligned_le16(hdev->devid_version, ptr + 8);
495
496 eir_len += 10;
497 ptr += 10;
498 }
499
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300500 memset(uuid16_list, 0, sizeof(uuid16_list));
501
502 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200503 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300504 u16 uuid16;
505
506 uuid16 = get_uuid16(uuid->uuid);
507 if (uuid16 == 0)
508 return;
509
510 if (uuid16 < 0x1100)
511 continue;
512
513 if (uuid16 == PNP_INFO_SVCLASS_ID)
514 continue;
515
516 /* Stop if not enough space to put next UUID */
517 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
518 truncated = 1;
519 break;
520 }
521
522 /* Check for duplicates */
523 for (i = 0; uuid16_list[i] != 0; i++)
524 if (uuid16_list[i] == uuid16)
525 break;
526
527 if (uuid16_list[i] == 0) {
528 uuid16_list[i] = uuid16;
529 eir_len += sizeof(u16);
530 }
531 }
532
533 if (uuid16_list[0] != 0) {
534 u8 *length = ptr;
535
536 /* EIR Data type */
537 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
538
539 ptr += 2;
540 eir_len += 2;
541
542 for (i = 0; uuid16_list[i] != 0; i++) {
543 *ptr++ = (uuid16_list[i] & 0x00ff);
544 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
545 }
546
547 /* EIR Data length */
548 *length = (i * sizeof(u16)) + 1;
549 }
550}
551
552static int update_eir(struct hci_dev *hdev)
553{
554 struct hci_cp_write_eir cp;
555
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200556 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200557 return 0;
558
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300559 if (!(hdev->features[6] & LMP_EXT_INQ))
560 return 0;
561
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200562 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300563 return 0;
564
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200565 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300566 return 0;
567
568 memset(&cp, 0, sizeof(cp));
569
570 create_eir(hdev, cp.data);
571
572 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
573 return 0;
574
575 memcpy(hdev->eir, cp.data, sizeof(cp.data));
576
577 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
578}
579
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200580static u8 get_service_classes(struct hci_dev *hdev)
581{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300582 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200583 u8 val = 0;
584
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300585 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200586 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200587
588 return val;
589}
590
591static int update_class(struct hci_dev *hdev)
592{
593 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200594 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200595
596 BT_DBG("%s", hdev->name);
597
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200598 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200599 return 0;
600
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200601 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200602 return 0;
603
604 cod[0] = hdev->minor_class;
605 cod[1] = hdev->major_class;
606 cod[2] = get_service_classes(hdev);
607
608 if (memcmp(cod, hdev->dev_class, 3) == 0)
609 return 0;
610
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200611 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
612 if (err == 0)
613 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
614
615 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200616}
617
Johan Hedberg7d785252011-12-15 00:47:39 +0200618static void service_cache_off(struct work_struct *work)
619{
620 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300621 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200622
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200623 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200624 return;
625
626 hci_dev_lock(hdev);
627
628 update_eir(hdev);
629 update_class(hdev);
630
631 hci_dev_unlock(hdev);
632}
633
Johan Hedberg6a919082012-02-28 06:17:26 +0200634static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200635{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200636 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200637 return;
638
Johan Hedberg4f87da82012-03-02 19:55:56 +0200639 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200640
Johan Hedberg4f87da82012-03-02 19:55:56 +0200641 /* Non-mgmt controlled devices get this bit set
642 * implicitly so that pairing works for them, however
643 * for mgmt we require user-space to explicitly enable
644 * it
645 */
646 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200647}
648
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200649static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300650 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200651{
652 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200653
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200654 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200655
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300656 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200657
Johan Hedberg03811012010-12-08 00:21:06 +0200658 memset(&rp, 0, sizeof(rp));
659
Johan Hedberg03811012010-12-08 00:21:06 +0200660 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200661
662 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200663 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200664
665 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
666 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
667
668 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200669
670 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200671 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200672
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300673 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200674
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200675 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300676 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200677}
678
679static void mgmt_pending_free(struct pending_cmd *cmd)
680{
681 sock_put(cmd->sk);
682 kfree(cmd->param);
683 kfree(cmd);
684}
685
686static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300687 struct hci_dev *hdev, void *data,
688 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200689{
690 struct pending_cmd *cmd;
691
692 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
693 if (!cmd)
694 return NULL;
695
696 cmd->opcode = opcode;
697 cmd->index = hdev->id;
698
699 cmd->param = kmalloc(len, GFP_ATOMIC);
700 if (!cmd->param) {
701 kfree(cmd);
702 return NULL;
703 }
704
705 if (data)
706 memcpy(cmd->param, data, len);
707
708 cmd->sk = sk;
709 sock_hold(sk);
710
711 list_add(&cmd->list, &hdev->mgmt_pending);
712
713 return cmd;
714}
715
716static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300717 void (*cb)(struct pending_cmd *cmd, void *data),
718 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200719{
720 struct list_head *p, *n;
721
722 list_for_each_safe(p, n, &hdev->mgmt_pending) {
723 struct pending_cmd *cmd;
724
725 cmd = list_entry(p, struct pending_cmd, list);
726
727 if (opcode > 0 && cmd->opcode != opcode)
728 continue;
729
730 cb(cmd, data);
731 }
732}
733
734static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
735{
736 struct pending_cmd *cmd;
737
738 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
739 if (cmd->opcode == opcode)
740 return cmd;
741 }
742
743 return NULL;
744}
745
746static void mgmt_pending_remove(struct pending_cmd *cmd)
747{
748 list_del(&cmd->list);
749 mgmt_pending_free(cmd);
750}
751
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200752static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200753{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200754 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200755
Johan Hedbergaee9b212012-02-18 15:07:59 +0200756 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300757 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200758}
759
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200760static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300761 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200762{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300763 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200764 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200765 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200766
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200767 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200768
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300769 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200770
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100771 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
772 cancel_delayed_work(&hdev->power_off);
773
774 if (cp->val) {
775 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
776 mgmt_powered(hdev, 1);
777 goto failed;
778 }
779 }
780
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200781 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200782 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200783 goto failed;
784 }
785
786 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200787 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300788 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200789 goto failed;
790 }
791
792 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
793 if (!cmd) {
794 err = -ENOMEM;
795 goto failed;
796 }
797
798 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200799 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200800 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200801 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200802
803 err = 0;
804
805failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300806 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200807 return err;
808}
809
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300810static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
811 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200812{
813 struct sk_buff *skb;
814 struct mgmt_hdr *hdr;
815
816 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
817 if (!skb)
818 return -ENOMEM;
819
820 hdr = (void *) skb_put(skb, sizeof(*hdr));
821 hdr->opcode = cpu_to_le16(event);
822 if (hdev)
823 hdr->index = cpu_to_le16(hdev->id);
824 else
825 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
826 hdr->len = cpu_to_le16(data_len);
827
828 if (data)
829 memcpy(skb_put(skb, data_len), data, data_len);
830
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100831 /* Time stamp */
832 __net_timestamp(skb);
833
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200834 hci_send_to_control(skb, skip_sk);
835 kfree_skb(skb);
836
837 return 0;
838}
839
840static int new_settings(struct hci_dev *hdev, struct sock *skip)
841{
842 __le32 ev;
843
844 ev = cpu_to_le32(get_current_settings(hdev));
845
846 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
847}
848
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200849static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300850 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200851{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300852 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200853 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200854 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200855 u8 scan;
856 int err;
857
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200858 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200859
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700860 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100861 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200862 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300863 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200864
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300865 hci_dev_lock(hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200866
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200867 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200868 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300869 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200870 goto failed;
871 }
872
873 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
874 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200875 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300876 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200877 goto failed;
878 }
879
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200880 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200881 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300882 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200883 goto failed;
884 }
885
886 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200887 bool changed = false;
888
889 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
890 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
891 changed = true;
892 }
893
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200894 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200895 if (err < 0)
896 goto failed;
897
898 if (changed)
899 err = new_settings(hdev, sk);
900
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200901 goto failed;
902 }
903
904 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100905 if (hdev->discov_timeout > 0) {
906 cancel_delayed_work(&hdev->discov_off);
907 hdev->discov_timeout = 0;
908 }
909
910 if (cp->val && timeout > 0) {
911 hdev->discov_timeout = timeout;
912 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
913 msecs_to_jiffies(hdev->discov_timeout * 1000));
914 }
915
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200916 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e692010-12-13 21:07:06 +0200917 goto failed;
918 }
919
920 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
921 if (!cmd) {
922 err = -ENOMEM;
923 goto failed;
924 }
925
926 scan = SCAN_PAGE;
927
928 if (cp->val)
929 scan |= SCAN_INQUIRY;
930 else
931 cancel_delayed_work(&hdev->discov_off);
932
933 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
934 if (err < 0)
935 mgmt_pending_remove(cmd);
936
Johan Hedberg03811012010-12-08 00:21:06 +0200937 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200938 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200939
940failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300941 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200942 return err;
943}
944
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200945static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300946 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200947{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300948 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200949 struct pending_cmd *cmd;
950 u8 scan;
951 int err;
952
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200953 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200954
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300955 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200956
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200957 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200958 bool changed = false;
959
960 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
961 changed = true;
962
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200963 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200964 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200965 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200966 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
967 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
968 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200969
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200970 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200971 if (err < 0)
972 goto failed;
973
974 if (changed)
975 err = new_settings(hdev, sk);
976
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200977 goto failed;
978 }
979
980 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
981 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200982 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300983 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200984 goto failed;
985 }
986
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200987 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200988 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200989 goto failed;
990 }
991
992 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
993 if (!cmd) {
994 err = -ENOMEM;
995 goto failed;
996 }
997
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200998 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200999 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +02001000 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001001 scan = 0;
1002
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001003 if (test_bit(HCI_ISCAN, &hdev->flags) &&
1004 hdev->discov_timeout > 0)
1005 cancel_delayed_work(&hdev->discov_off);
1006 }
1007
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001008 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1009 if (err < 0)
1010 mgmt_pending_remove(cmd);
1011
1012failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001013 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001014 return err;
1015}
1016
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001017static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001018 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001019{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001020 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001021 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001022
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001023 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001024
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001025 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001026
1027 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001028 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001029 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001030 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001031
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001032 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001033 if (err < 0)
1034 goto failed;
1035
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001036 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001037
1038failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001039 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001040 return err;
1041}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001042
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001043static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1044 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001045{
1046 struct mgmt_mode *cp = data;
1047 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001048 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001049 int err;
1050
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001051 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001052
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001053 hci_dev_lock(hdev);
1054
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001055 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001056 bool changed = false;
1057
1058 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
1059 &hdev->dev_flags)) {
1060 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1061 changed = true;
1062 }
1063
1064 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1065 if (err < 0)
1066 goto failed;
1067
1068 if (changed)
1069 err = new_settings(hdev, sk);
1070
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001071 goto failed;
1072 }
1073
1074 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001075 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001076 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001077 goto failed;
1078 }
1079
1080 val = !!cp->val;
1081
1082 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1083 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1084 goto failed;
1085 }
1086
1087 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1088 if (!cmd) {
1089 err = -ENOMEM;
1090 goto failed;
1091 }
1092
1093 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1094 if (err < 0) {
1095 mgmt_pending_remove(cmd);
1096 goto failed;
1097 }
1098
1099failed:
1100 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001101 return err;
1102}
1103
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001104static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001105{
1106 struct mgmt_mode *cp = data;
1107 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001108 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001109 int err;
1110
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001111 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001112
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001113 hci_dev_lock(hdev);
1114
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001115 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001116 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001117 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001118 goto failed;
1119 }
1120
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001121 val = !!cp->val;
1122
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001123 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001124 bool changed = false;
1125
1126 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1127 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1128 changed = true;
1129 }
1130
1131 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1132 if (err < 0)
1133 goto failed;
1134
1135 if (changed)
1136 err = new_settings(hdev, sk);
1137
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001138 goto failed;
1139 }
1140
1141 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001142 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1143 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001144 goto failed;
1145 }
1146
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001147 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1148 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1149 goto failed;
1150 }
1151
1152 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1153 if (!cmd) {
1154 err = -ENOMEM;
1155 goto failed;
1156 }
1157
1158 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1159 if (err < 0) {
1160 mgmt_pending_remove(cmd);
1161 goto failed;
1162 }
1163
1164failed:
1165 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001166 return err;
1167}
1168
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001169static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001170{
1171 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001172
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001173 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001174
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001175 if (!enable_hs)
1176 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001177 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001178
1179 if (cp->val)
1180 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1181 else
1182 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1183
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001184 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001185}
1186
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001187static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001188{
1189 struct mgmt_mode *cp = data;
1190 struct hci_cp_write_le_host_supported hci_cp;
1191 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001192 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001193 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001195 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001196
Johan Hedberg1de028c2012-02-29 19:55:35 -08001197 hci_dev_lock(hdev);
1198
Marcel Holtmann9d428202012-05-03 07:12:31 +02001199 if (!(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001200 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001201 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001202 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001203 }
1204
1205 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001206 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001207
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001208 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001209 bool changed = false;
1210
1211 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1212 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1213 changed = true;
1214 }
1215
1216 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1217 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001218 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001219
1220 if (changed)
1221 err = new_settings(hdev, sk);
1222
Johan Hedberg1de028c2012-02-29 19:55:35 -08001223 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001224 }
1225
1226 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001227 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001228 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001229 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001230 }
1231
1232 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1233 if (!cmd) {
1234 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001235 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001236 }
1237
1238 memset(&hci_cp, 0, sizeof(hci_cp));
1239
1240 if (val) {
1241 hci_cp.le = val;
1242 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1243 }
1244
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001245 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1246 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301247 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001248 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001249
Johan Hedberg1de028c2012-02-29 19:55:35 -08001250unlock:
1251 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001252 return err;
1253}
1254
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001255static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001256{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001257 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001258 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001259 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001260 int err;
1261
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001262 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001263
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001264 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001265
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001266 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001267 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001268 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001269 goto failed;
1270 }
1271
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001272 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
1273 if (!uuid) {
1274 err = -ENOMEM;
1275 goto failed;
1276 }
1277
1278 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001279 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001280
1281 list_add(&uuid->list, &hdev->uuids);
1282
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001283 err = update_class(hdev);
1284 if (err < 0)
1285 goto failed;
1286
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001287 err = update_eir(hdev);
1288 if (err < 0)
1289 goto failed;
1290
Johan Hedberg90e70452012-02-23 23:09:40 +02001291 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001292 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001293 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001294 goto failed;
1295 }
1296
1297 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301298 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001299 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001300
1301failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001302 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001303 return err;
1304}
1305
Johan Hedberg24b78d02012-02-23 23:24:30 +02001306static bool enable_service_cache(struct hci_dev *hdev)
1307{
1308 if (!hdev_is_powered(hdev))
1309 return false;
1310
1311 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001312 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001313 return true;
1314 }
1315
1316 return false;
1317}
1318
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001319static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
1320 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001321{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001322 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001323 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001324 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001325 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 +02001326 int err, found;
1327
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001328 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001329
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001330 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001331
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001332 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001333 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001334 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001335 goto unlock;
1336 }
1337
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001338 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1339 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001340
Johan Hedberg24b78d02012-02-23 23:24:30 +02001341 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001342 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001343 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001344 goto unlock;
1345 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001346
Johan Hedberg9246a862012-02-23 21:33:16 +02001347 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001348 }
1349
1350 found = 0;
1351
1352 list_for_each_safe(p, n, &hdev->uuids) {
1353 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1354
1355 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1356 continue;
1357
1358 list_del(&match->list);
1359 found++;
1360 }
1361
1362 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001363 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001364 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001365 goto unlock;
1366 }
1367
Johan Hedberg9246a862012-02-23 21:33:16 +02001368update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001369 err = update_class(hdev);
1370 if (err < 0)
1371 goto unlock;
1372
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001373 err = update_eir(hdev);
1374 if (err < 0)
1375 goto unlock;
1376
Johan Hedberg90e70452012-02-23 23:09:40 +02001377 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001378 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001379 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001380 goto unlock;
1381 }
1382
1383 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301384 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001385 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001386
1387unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001388 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001389 return err;
1390}
1391
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001392static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001393 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001394{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001395 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001396 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001397 int err;
1398
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001399 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001400
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001401 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001402
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001403 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001404 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001405 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001406 goto unlock;
1407 }
1408
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001409 hdev->major_class = cp->major;
1410 hdev->minor_class = cp->minor;
1411
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001412 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001413 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001414 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001415 goto unlock;
1416 }
1417
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001418 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001419 hci_dev_unlock(hdev);
1420 cancel_delayed_work_sync(&hdev->service_cache);
1421 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001422 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001423 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001424
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001425 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001426 if (err < 0)
1427 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001428
Johan Hedberg90e70452012-02-23 23:09:40 +02001429 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001430 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001431 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001432 goto unlock;
1433 }
1434
1435 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301436 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001437 err = -ENOMEM;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001438
Johan Hedbergb5235a62012-02-21 14:32:24 +02001439unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001440 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001441 return err;
1442}
1443
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001444static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
1445 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001446{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001447 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001448 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001449 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001450
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001451 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001452
Johan Hedberg86742e12011-11-07 23:13:38 +02001453 expected_len = sizeof(*cp) + key_count *
1454 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001455 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001456 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001457 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001458 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001459 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001460 }
1461
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001462 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001463 key_count);
1464
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001465 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001466
1467 hci_link_keys_clear(hdev);
1468
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001469 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001470
1471 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001472 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001473 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001474 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001475
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001476 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001477 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001478
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001479 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001480 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001481 }
1482
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001483 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001484
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001485 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001486
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001487 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001488}
1489
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001490static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001491 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001492{
1493 struct mgmt_ev_device_unpaired ev;
1494
1495 bacpy(&ev.addr.bdaddr, bdaddr);
1496 ev.addr.type = addr_type;
1497
1498 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001499 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001500}
1501
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001502static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001503 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001504{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001505 struct mgmt_cp_unpair_device *cp = data;
1506 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001507 struct hci_cp_disconnect dc;
1508 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001509 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001510 int err;
1511
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001512 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001513
Johan Hedberga8a1d192011-11-10 15:54:38 +02001514 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001515 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1516 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001517
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001518 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001519 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001520 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001521 goto unlock;
1522 }
1523
Andre Guedes591f47f2012-04-24 21:02:49 -03001524 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001525 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1526 else
1527 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001528
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001529 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001530 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001531 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001532 goto unlock;
1533 }
1534
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001535 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001536 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001537 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1538 &cp->addr.bdaddr);
1539 else
1540 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
1541 &cp->addr.bdaddr);
1542 } else {
1543 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001544 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001545
Johan Hedberga8a1d192011-11-10 15:54:38 +02001546 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001547 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001548 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001549 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001550 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001551 }
1552
Johan Hedberg124f6e32012-02-09 13:50:12 +02001553 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001554 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001555 if (!cmd) {
1556 err = -ENOMEM;
1557 goto unlock;
1558 }
1559
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001560 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001561 dc.reason = 0x13; /* Remote User Terminated Connection */
1562 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1563 if (err < 0)
1564 mgmt_pending_remove(cmd);
1565
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001566unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001567 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001568 return err;
1569}
1570
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001571static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001572 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001573{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001574 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001575 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001576 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001577 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001578 int err;
1579
1580 BT_DBG("");
1581
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001582 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001583
1584 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001585 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001586 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001587 goto failed;
1588 }
1589
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001590 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001591 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001592 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001593 goto failed;
1594 }
1595
Andre Guedes591f47f2012-04-24 21:02:49 -03001596 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg88c3df12012-02-09 14:27:38 +02001597 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
1598 else
1599 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->addr.bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001600
Johan Hedberg8962ee72011-01-20 12:40:27 +02001601 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001602 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001603 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001604 goto failed;
1605 }
1606
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001607 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001608 if (!cmd) {
1609 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001610 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001611 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001612
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001613 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001614 dc.reason = 0x13; /* Remote User Terminated Connection */
1615
1616 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1617 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001618 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001619
1620failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001621 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001622 return err;
1623}
1624
Andre Guedes57c14772012-04-24 21:02:50 -03001625static u8 link_to_bdaddr(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001626{
1627 switch (link_type) {
1628 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001629 switch (addr_type) {
1630 case ADDR_LE_DEV_PUBLIC:
Andre Guedes591f47f2012-04-24 21:02:49 -03001631 return BDADDR_LE_PUBLIC;
Andre Guedes0ed09142012-04-03 08:46:54 -03001632
Johan Hedberg48264f02011-11-09 13:58:58 +02001633 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001634 /* Fallback to LE Random address type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001635 return BDADDR_LE_RANDOM;
Johan Hedberg48264f02011-11-09 13:58:58 +02001636 }
Andre Guedes0ed09142012-04-03 08:46:54 -03001637
Johan Hedberg4c659c32011-11-07 23:13:39 +02001638 default:
Andre Guedes0ed09142012-04-03 08:46:54 -03001639 /* Fallback to BR/EDR type */
Andre Guedes591f47f2012-04-24 21:02:49 -03001640 return BDADDR_BREDR;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001641 }
1642}
1643
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001644static int get_connections(struct sock *sk, struct hci_dev *hdev, void *data,
1645 u16 data_len)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001646{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001647 struct mgmt_rp_get_connections *rp;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001648 struct hci_conn *c;
Johan Hedberga38528f2011-01-22 06:46:43 +02001649 size_t rp_len;
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001650 int err;
1651 u16 i;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001652
1653 BT_DBG("");
1654
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001655 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001656
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001657 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001658 err = cmd_status(sk, hdev->id, MGMT_OP_GET_CONNECTIONS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001659 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001660 goto unlock;
1661 }
1662
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001663 i = 0;
Johan Hedbergb644ba32012-01-17 21:48:47 +02001664 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1665 if (test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001666 i++;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001667 }
1668
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001669 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001670 rp = kmalloc(rp_len, GFP_ATOMIC);
1671 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001672 err = -ENOMEM;
1673 goto unlock;
1674 }
1675
Johan Hedberg2784eb42011-01-21 13:56:35 +02001676 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001677 list_for_each_entry(c, &hdev->conn_hash.list, list) {
Johan Hedbergb644ba32012-01-17 21:48:47 +02001678 if (!test_bit(HCI_CONN_MGMT_CONNECTED, &c->flags))
1679 continue;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001680 bacpy(&rp->addr[i].bdaddr, &c->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001681 rp->addr[i].type = link_to_bdaddr(c->type, c->dst_type);
Andre Guedes0ed09142012-04-03 08:46:54 -03001682 if (c->type == SCO_LINK || c->type == ESCO_LINK)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001683 continue;
1684 i++;
1685 }
1686
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001687 rp->conn_count = cpu_to_le16(i);
Johan Hedberg60fc5fb62012-02-23 09:52:28 +02001688
Johan Hedberg4c659c32011-11-07 23:13:39 +02001689 /* Recalculate length in case of filtered SCO connections, etc */
1690 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001691
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001692 err = cmd_complete(sk, hdev->id, MGMT_OP_GET_CONNECTIONS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001693 rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001694
Johan Hedberga38528f2011-01-22 06:46:43 +02001695 kfree(rp);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001696
1697unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001698 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001699 return err;
1700}
1701
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001702static int send_pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001703 struct mgmt_cp_pin_code_neg_reply *cp)
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001704{
1705 struct pending_cmd *cmd;
1706 int err;
1707
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001708 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001709 sizeof(*cp));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001710 if (!cmd)
1711 return -ENOMEM;
1712
Johan Hedbergd8457692012-02-17 14:24:57 +02001713 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001714 sizeof(cp->addr.bdaddr), &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001715 if (err < 0)
1716 mgmt_pending_remove(cmd);
1717
1718 return err;
1719}
1720
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001721static int pin_code_reply(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001722 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001723{
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001724 struct hci_conn *conn;
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001725 struct mgmt_cp_pin_code_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001726 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001727 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001728 int err;
1729
1730 BT_DBG("");
1731
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001732 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001733
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001734 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001735 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001736 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001737 goto failed;
1738 }
1739
Johan Hedbergd8457692012-02-17 14:24:57 +02001740 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->addr.bdaddr);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001741 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001742 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001743 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001744 goto failed;
1745 }
1746
1747 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
Johan Hedbergd8457692012-02-17 14:24:57 +02001748 struct mgmt_cp_pin_code_neg_reply ncp;
1749
1750 memcpy(&ncp.addr, &cp->addr, sizeof(ncp.addr));
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001751
1752 BT_ERR("PIN code is not 16 bytes long");
1753
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001754 err = send_pin_code_neg_reply(sk, hdev, &ncp);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001755 if (err >= 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001756 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001757 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001758
1759 goto failed;
1760 }
1761
Gustavo F. Padovan00abfe42012-03-01 00:37:10 -03001762 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001763 if (!cmd) {
1764 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001765 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001766 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001767
Johan Hedbergd8457692012-02-17 14:24:57 +02001768 bacpy(&reply.bdaddr, &cp->addr.bdaddr);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001769 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001770 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001771
1772 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1773 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001774 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001775
1776failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001777 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001778 return err;
1779}
1780
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001781static int pin_code_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001782 void *data, u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001783{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001784 struct mgmt_cp_pin_code_neg_reply *cp = data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001785 int err;
1786
1787 BT_DBG("");
1788
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001789 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001790
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001791 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001792 err = cmd_status(sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001793 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001794 goto failed;
1795 }
1796
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001797 err = send_pin_code_neg_reply(sk, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001798
1799failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001800 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001801 return err;
1802}
1803
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001804static int set_io_capability(struct sock *sk, struct hci_dev *hdev, void *data,
1805 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001806{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001807 struct mgmt_cp_set_io_capability *cp = data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001808
1809 BT_DBG("");
1810
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001811 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001812
1813 hdev->io_capability = cp->io_capability;
1814
1815 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001816 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001817
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001818 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001819
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001820 return cmd_complete(sk, hdev->id, MGMT_OP_SET_IO_CAPABILITY, 0, NULL,
1821 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001822}
1823
Johan Hedberge9a416b2011-02-19 12:05:56 -03001824static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1825{
1826 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001827 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001828
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001829 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001830 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1831 continue;
1832
Johan Hedberge9a416b2011-02-19 12:05:56 -03001833 if (cmd->user_data != conn)
1834 continue;
1835
1836 return cmd;
1837 }
1838
1839 return NULL;
1840}
1841
1842static void pairing_complete(struct pending_cmd *cmd, u8 status)
1843{
1844 struct mgmt_rp_pair_device rp;
1845 struct hci_conn *conn = cmd->user_data;
1846
Johan Hedbergba4e5642011-11-11 00:07:34 +02001847 bacpy(&rp.addr.bdaddr, &conn->dst);
Andre Guedes57c14772012-04-24 21:02:50 -03001848 rp.addr.type = link_to_bdaddr(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001849
Johan Hedbergaee9b212012-02-18 15:07:59 +02001850 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001851 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001852
1853 /* So we don't get further callbacks for this connection */
1854 conn->connect_cfm_cb = NULL;
1855 conn->security_cfm_cb = NULL;
1856 conn->disconn_cfm_cb = NULL;
1857
1858 hci_conn_put(conn);
1859
Johan Hedberga664b5b2011-02-19 12:06:02 -03001860 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001861}
1862
1863static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1864{
1865 struct pending_cmd *cmd;
1866
1867 BT_DBG("status %u", status);
1868
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001869 cmd = find_pairing(conn);
1870 if (!cmd)
1871 BT_DBG("Unable to find a pending command");
1872 else
Johan Hedberge2113262012-02-18 15:20:03 +02001873 pairing_complete(cmd, mgmt_status(status));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001874}
1875
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001876static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001877 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001878{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001879 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001880 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001881 struct pending_cmd *cmd;
1882 u8 sec_level, auth_type;
1883 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001884 int err;
1885
1886 BT_DBG("");
1887
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001888 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001889
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001890 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001891 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001892 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001893 goto unlock;
1894 }
1895
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001896 sec_level = BT_SECURITY_MEDIUM;
1897 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001898 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001899 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001900 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001901
Andre Guedes591f47f2012-04-24 21:02:49 -03001902 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03001903 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
1904 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001905 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03001906 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
1907 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001908
Johan Hedberg1425acb2011-11-11 00:07:35 +02001909 memset(&rp, 0, sizeof(rp));
1910 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1911 rp.addr.type = cp->addr.type;
1912
Ville Tervo30e76272011-02-22 16:10:53 -03001913 if (IS_ERR(conn)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001914 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001915 MGMT_STATUS_CONNECT_FAILED, &rp,
1916 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001917 goto unlock;
1918 }
1919
1920 if (conn->connect_cfm_cb) {
1921 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001922 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001923 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001924 goto unlock;
1925 }
1926
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001927 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001928 if (!cmd) {
1929 err = -ENOMEM;
1930 hci_conn_put(conn);
1931 goto unlock;
1932 }
1933
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001934 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03001935 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001936 conn->connect_cfm_cb = pairing_complete_cb;
1937
Johan Hedberge9a416b2011-02-19 12:05:56 -03001938 conn->security_cfm_cb = pairing_complete_cb;
1939 conn->disconn_cfm_cb = pairing_complete_cb;
1940 conn->io_capability = cp->io_cap;
1941 cmd->user_data = conn;
1942
1943 if (conn->state == BT_CONNECTED &&
1944 hci_conn_security(conn, sec_level, auth_type))
1945 pairing_complete(cmd, 0);
1946
1947 err = 0;
1948
1949unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001950 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001951 return err;
1952}
1953
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001954static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1955 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001956{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001957 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001958 struct pending_cmd *cmd;
1959 struct hci_conn *conn;
1960 int err;
1961
1962 BT_DBG("");
1963
Johan Hedberg28424702012-02-02 04:02:29 +02001964 hci_dev_lock(hdev);
1965
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001966 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001967 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001968 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001969 goto unlock;
1970 }
1971
Johan Hedberg28424702012-02-02 04:02:29 +02001972 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1973 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001974 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001975 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001976 goto unlock;
1977 }
1978
1979 conn = cmd->user_data;
1980
1981 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001982 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001983 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02001984 goto unlock;
1985 }
1986
1987 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
1988
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001989 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001990 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02001991unlock:
1992 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02001993 return err;
1994}
1995
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001996static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001997 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
1998 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001999{
Johan Hedberga5c29682011-02-19 12:05:57 -03002000 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002001 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002002 int err;
2003
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002004 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002005
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002006 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002007 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002008 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002009 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002010 }
2011
Andre Guedes591f47f2012-04-24 21:02:49 -03002012 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002013 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2014 else
Brian Gix47c15e22011-11-16 13:53:14 -08002015 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002016
Johan Hedberg272d90d2012-02-09 15:26:12 +02002017 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002018 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002019 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002020 goto done;
2021 }
2022
Andre Guedes591f47f2012-04-24 21:02:49 -03002023 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002024 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002025 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002026
Brian Gix5fe57d92011-12-21 16:12:13 -08002027 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002028 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002029 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002030 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002031 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002032 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002033
Brian Gix47c15e22011-11-16 13:53:14 -08002034 goto done;
2035 }
2036
Brian Gix0df4c182011-11-16 13:53:13 -08002037 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002038 if (!cmd) {
2039 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002040 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002041 }
2042
Brian Gix0df4c182011-11-16 13:53:13 -08002043 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002044 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2045 struct hci_cp_user_passkey_reply cp;
2046
2047 bacpy(&cp.bdaddr, bdaddr);
2048 cp.passkey = passkey;
2049 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2050 } else
2051 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2052
Johan Hedberga664b5b2011-02-19 12:06:02 -03002053 if (err < 0)
2054 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002055
Brian Gix0df4c182011-11-16 13:53:13 -08002056done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002057 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002058 return err;
2059}
2060
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002061static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2062 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002063{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002064 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002065
2066 BT_DBG("");
2067
2068 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002069 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002070 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002071
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002072 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002073 MGMT_OP_USER_CONFIRM_REPLY,
2074 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002075}
2076
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002077static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002078 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002079{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002080 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002081
2082 BT_DBG("");
2083
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002084 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002085 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2086 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002087}
2088
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002089static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2090 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002091{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002092 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002093
2094 BT_DBG("");
2095
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002096 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002097 MGMT_OP_USER_PASSKEY_REPLY,
2098 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002099}
2100
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002101static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002102 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002103{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002104 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002105
2106 BT_DBG("");
2107
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002108 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002109 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2110 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002111}
2112
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002113static int update_name(struct hci_dev *hdev, const char *name)
2114{
2115 struct hci_cp_write_local_name cp;
2116
2117 memcpy(cp.name, name, sizeof(cp.name));
2118
2119 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2120}
2121
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002122static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002123 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002124{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002125 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002126 struct pending_cmd *cmd;
2127 int err;
2128
2129 BT_DBG("");
2130
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002131 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002132
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002133 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002134
Johan Hedbergb5235a62012-02-21 14:32:24 +02002135 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002136 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002137
2138 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002139 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002140 if (err < 0)
2141 goto failed;
2142
2143 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002144 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002145
Johan Hedbergb5235a62012-02-21 14:32:24 +02002146 goto failed;
2147 }
2148
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002149 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002150 if (!cmd) {
2151 err = -ENOMEM;
2152 goto failed;
2153 }
2154
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002155 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002156 if (err < 0)
2157 mgmt_pending_remove(cmd);
2158
2159failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002160 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002161 return err;
2162}
2163
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002164static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002165 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002166{
Szymon Jancc35938b2011-03-22 13:12:21 +01002167 struct pending_cmd *cmd;
2168 int err;
2169
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002170 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002171
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002172 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002173
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002174 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002175 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002176 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002177 goto unlock;
2178 }
2179
2180 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002181 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002182 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002183 goto unlock;
2184 }
2185
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002186 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002187 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002188 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002189 goto unlock;
2190 }
2191
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002192 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002193 if (!cmd) {
2194 err = -ENOMEM;
2195 goto unlock;
2196 }
2197
2198 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2199 if (err < 0)
2200 mgmt_pending_remove(cmd);
2201
2202unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002203 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002204 return err;
2205}
2206
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002207static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002208 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002209{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002210 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002211 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002212 int err;
2213
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002214 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002215
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002216 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002217
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002218 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002219 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002220 MGMT_STATUS_NOT_POWERED, &cp->addr,
2221 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002222 goto unlock;
2223 }
2224
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002225 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002226 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002227 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002228 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002229 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002230 status = 0;
2231
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002232 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002233 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002234
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002235unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002236 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002237 return err;
2238}
2239
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002240static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002241 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002242{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002243 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002244 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002245 int err;
2246
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002247 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002248
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002249 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002250
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002251 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002252 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002253 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2254 MGMT_STATUS_NOT_POWERED, &cp->addr,
2255 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002256 goto unlock;
2257 }
2258
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002259 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002260 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002261 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002262 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002263 status = 0;
2264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002266 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002267
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002268unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002269 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002270 return err;
2271}
2272
Andre Guedes5e0452c2012-02-17 20:39:38 -03002273int mgmt_interleaved_discovery(struct hci_dev *hdev)
2274{
2275 int err;
2276
2277 BT_DBG("%s", hdev->name);
2278
2279 hci_dev_lock(hdev);
2280
2281 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2282 if (err < 0)
2283 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2284
2285 hci_dev_unlock(hdev);
2286
2287 return err;
2288}
2289
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002290static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002291 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002292{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002293 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002294 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002295 int err;
2296
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002297 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002298
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002299 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002300
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002301 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002302 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002303 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002304 goto failed;
2305 }
2306
Andre Guedes642be6c2012-03-21 00:03:37 -03002307 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2308 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2309 MGMT_STATUS_BUSY);
2310 goto failed;
2311 }
2312
Johan Hedbergff9ef572012-01-04 14:23:45 +02002313 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002314 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002315 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002316 goto failed;
2317 }
2318
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002319 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002320 if (!cmd) {
2321 err = -ENOMEM;
2322 goto failed;
2323 }
2324
Andre Guedes4aab14e2012-02-17 20:39:36 -03002325 hdev->discovery.type = cp->type;
2326
2327 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002328 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002329 if (lmp_bredr_capable(hdev))
2330 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2331 else
2332 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002333 break;
2334
2335 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002336 if (lmp_host_le_capable(hdev))
2337 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002338 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002339 else
2340 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002341 break;
2342
Andre Guedes5e0452c2012-02-17 20:39:38 -03002343 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002344 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2345 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002346 LE_SCAN_WIN,
2347 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002348 else
2349 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002350 break;
2351
Andre Guedesf39799f2012-02-17 20:39:35 -03002352 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002353 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002354 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002355
Johan Hedberg14a53662011-04-27 10:29:56 -04002356 if (err < 0)
2357 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002358 else
2359 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002360
2361failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002362 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002363 return err;
2364}
2365
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002366static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002367 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002368{
Johan Hedbergd9306502012-02-20 23:25:18 +02002369 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002370 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002371 struct hci_cp_remote_name_req_cancel cp;
2372 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002373 int err;
2374
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002375 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002376
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002377 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002378
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002379 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002380 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002381 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2382 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002383 goto unlock;
2384 }
2385
2386 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002387 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002388 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2389 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002390 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002391 }
2392
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002393 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002394 if (!cmd) {
2395 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002396 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002397 }
2398
Andre Guedese0d9727e2012-03-20 15:15:36 -03002399 switch (hdev->discovery.state) {
2400 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002401 if (test_bit(HCI_INQUIRY, &hdev->flags))
2402 err = hci_cancel_inquiry(hdev);
2403 else
2404 err = hci_cancel_le_scan(hdev);
2405
Andre Guedese0d9727e2012-03-20 15:15:36 -03002406 break;
2407
2408 case DISCOVERY_RESOLVING:
2409 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
2410 NAME_PENDING);
2411 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002412 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002413 err = cmd_complete(sk, hdev->id,
2414 MGMT_OP_STOP_DISCOVERY, 0,
2415 &mgmt_cp->type,
2416 sizeof(mgmt_cp->type));
2417 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2418 goto unlock;
2419 }
2420
2421 bacpy(&cp.bdaddr, &e->data.bdaddr);
2422 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2423 sizeof(cp), &cp);
2424
2425 break;
2426
2427 default:
2428 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2429 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002430 }
2431
Johan Hedberg14a53662011-04-27 10:29:56 -04002432 if (err < 0)
2433 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002434 else
2435 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002436
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002437unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002438 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002439 return err;
2440}
2441
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002442static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002443 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002444{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002445 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002446 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002447 int err;
2448
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002449 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002450
Johan Hedberg561aafb2012-01-04 13:31:59 +02002451 hci_dev_lock(hdev);
2452
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002453 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002454 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002455 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002456 goto failed;
2457 }
2458
Johan Hedberga198e7b2012-02-17 14:27:06 +02002459 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002460 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002461 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002462 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002463 goto failed;
2464 }
2465
2466 if (cp->name_known) {
2467 e->name_state = NAME_KNOWN;
2468 list_del(&e->list);
2469 } else {
2470 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e20a2012-01-09 00:53:02 +02002471 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002472 }
2473
2474 err = 0;
2475
2476failed:
2477 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002478 return err;
2479}
2480
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002481static int block_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002482 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002483{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002484 struct mgmt_cp_block_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002485 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002486 int err;
2487
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002488 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002489
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002490 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002491
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002492 err = hci_blacklist_add(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002493 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002494 status = MGMT_STATUS_FAILED;
Antti Julku7fbec222011-06-15 12:01:15 +03002495 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002496 status = 0;
2497
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002498 err = cmd_complete(sk, hdev->id, MGMT_OP_BLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002499 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002500
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002501 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002502
2503 return err;
2504}
2505
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002506static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002507 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002508{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002509 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002510 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002511 int err;
2512
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002513 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002514
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002515 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002516
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002517 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002518 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002519 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002520 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002521 status = 0;
2522
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002523 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002524 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002525
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002526 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002527
2528 return err;
2529}
2530
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002531static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2532 u16 len)
2533{
2534 struct mgmt_cp_set_device_id *cp = data;
2535 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002536 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002537
2538 BT_DBG("%s", hdev->name);
2539
Szymon Jancc72d4b82012-03-16 16:02:57 +01002540 source = __le16_to_cpu(cp->source);
2541
2542 if (source > 0x0002)
2543 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2544 MGMT_STATUS_INVALID_PARAMS);
2545
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002546 hci_dev_lock(hdev);
2547
Szymon Jancc72d4b82012-03-16 16:02:57 +01002548 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002549 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2550 hdev->devid_product = __le16_to_cpu(cp->product);
2551 hdev->devid_version = __le16_to_cpu(cp->version);
2552
2553 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2554
2555 update_eir(hdev);
2556
2557 hci_dev_unlock(hdev);
2558
2559 return err;
2560}
2561
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002562static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002563 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002564{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002565 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002566 struct hci_cp_write_page_scan_activity acp;
2567 u8 type;
2568 int err;
2569
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002570 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002571
Johan Hedberg5400c042012-02-21 16:40:33 +02002572 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002573 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002574 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002575
2576 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002577 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002578 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002579
2580 hci_dev_lock(hdev);
2581
Johan Hedbergf7c6869ce2011-12-15 00:47:36 +02002582 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002583 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002584
2585 /* 22.5 msec page scan interval */
2586 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002587 } else {
2588 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002589
2590 /* default 1.28 sec page scan */
2591 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002592 }
2593
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002594 /* default 11.25 msec page scan window */
2595 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002596
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002597 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2598 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002599 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002600 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002601 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002602 goto done;
2603 }
2604
2605 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2606 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002607 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002608 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002609 goto done;
2610 }
2611
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002612 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002613 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002614done:
2615 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002616 return err;
2617}
2618
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002619static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002620 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002621{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002622 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2623 u16 key_count, expected_len;
2624 int i;
2625
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002626 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002627
2628 expected_len = sizeof(*cp) + key_count *
2629 sizeof(struct mgmt_ltk_info);
2630 if (expected_len != len) {
2631 BT_ERR("load_keys: expected %u bytes, got %u bytes",
2632 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002633 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002634 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002635 }
2636
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002637 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002638
2639 hci_dev_lock(hdev);
2640
2641 hci_smp_ltks_clear(hdev);
2642
2643 for (i = 0; i < key_count; i++) {
2644 struct mgmt_ltk_info *key = &cp->keys[i];
2645 u8 type;
2646
2647 if (key->master)
2648 type = HCI_SMP_LTK;
2649 else
2650 type = HCI_SMP_LTK_SLAVE;
2651
Hemant Gupta4596fde2012-04-16 14:57:40 +05302652 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03002653 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002654 type, 0, key->authenticated, key->val,
2655 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002656 }
2657
2658 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002659
2660 return 0;
2661}
2662
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002663static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002664 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2665 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002666 bool var_len;
2667 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002668} mgmt_handlers[] = {
2669 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002670 { read_version, false, MGMT_READ_VERSION_SIZE },
2671 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2672 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2673 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2674 { set_powered, false, MGMT_SETTING_SIZE },
2675 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2676 { set_connectable, false, MGMT_SETTING_SIZE },
2677 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2678 { set_pairable, false, MGMT_SETTING_SIZE },
2679 { set_link_security, false, MGMT_SETTING_SIZE },
2680 { set_ssp, false, MGMT_SETTING_SIZE },
2681 { set_hs, false, MGMT_SETTING_SIZE },
2682 { set_le, false, MGMT_SETTING_SIZE },
2683 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2684 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2685 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2686 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2687 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2688 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2689 { disconnect, false, MGMT_DISCONNECT_SIZE },
2690 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2691 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2692 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2693 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2694 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2695 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2696 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2697 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2698 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2699 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2700 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2701 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2702 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2703 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2704 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2705 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2706 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2707 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2708 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002709 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002710};
2711
2712
Johan Hedberg03811012010-12-08 00:21:06 +02002713int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2714{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002715 void *buf;
2716 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002717 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002718 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002719 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002720 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002721 int err;
2722
2723 BT_DBG("got %zu bytes", msglen);
2724
2725 if (msglen < sizeof(*hdr))
2726 return -EINVAL;
2727
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002728 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002729 if (!buf)
2730 return -ENOMEM;
2731
2732 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2733 err = -EFAULT;
2734 goto done;
2735 }
2736
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002737 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002738 opcode = __le16_to_cpu(hdr->opcode);
2739 index = __le16_to_cpu(hdr->index);
2740 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002741
2742 if (len != msglen - sizeof(*hdr)) {
2743 err = -EINVAL;
2744 goto done;
2745 }
2746
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002747 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002748 hdev = hci_dev_get(index);
2749 if (!hdev) {
2750 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002751 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002752 goto done;
2753 }
2754 }
2755
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002756 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
2757 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002758 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002759 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002760 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002761 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002762 }
2763
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002764 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
2765 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
2766 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002767 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002768 goto done;
2769 }
2770
Johan Hedbergbe22b542012-03-01 22:24:41 +02002771 handler = &mgmt_handlers[opcode];
2772
2773 if ((handler->var_len && len < handler->data_len) ||
2774 (!handler->var_len && len != handler->data_len)) {
2775 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002776 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002777 goto done;
2778 }
2779
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002780 if (hdev)
2781 mgmt_init_hdev(sk, hdev);
2782
2783 cp = buf + sizeof(*hdr);
2784
Johan Hedbergbe22b542012-03-01 22:24:41 +02002785 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002786 if (err < 0)
2787 goto done;
2788
Johan Hedberg03811012010-12-08 00:21:06 +02002789 err = msglen;
2790
2791done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002792 if (hdev)
2793 hci_dev_put(hdev);
2794
Johan Hedberg03811012010-12-08 00:21:06 +02002795 kfree(buf);
2796 return err;
2797}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002798
Johan Hedbergb24752f2011-11-03 14:40:33 +02002799static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2800{
2801 u8 *status = data;
2802
2803 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2804 mgmt_pending_remove(cmd);
2805}
2806
Johan Hedberg744cf192011-11-08 20:40:14 +02002807int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002808{
Johan Hedberg744cf192011-11-08 20:40:14 +02002809 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002810}
2811
Johan Hedberg744cf192011-11-08 20:40:14 +02002812int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002813{
Johan Hedberg5f159032012-03-02 03:13:19 +02002814 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002815
Johan Hedberg744cf192011-11-08 20:40:14 +02002816 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002817
Johan Hedberg744cf192011-11-08 20:40:14 +02002818 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002819}
2820
Johan Hedberg73f22f62010-12-29 16:00:25 +02002821struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002822 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002823 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002824 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002825};
2826
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002827static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002828{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002829 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002830
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002831 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002832
2833 list_del(&cmd->list);
2834
2835 if (match->sk == NULL) {
2836 match->sk = cmd->sk;
2837 sock_hold(match->sk);
2838 }
2839
2840 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002841}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002842
Johan Hedberg744cf192011-11-08 20:40:14 +02002843int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002844{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002845 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002846 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002847
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002848 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2849 return 0;
2850
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002851 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002852
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002853 if (powered) {
2854 u8 scan = 0;
2855
2856 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2857 scan |= SCAN_PAGE;
2858 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2859 scan |= SCAN_INQUIRY;
2860
2861 if (scan)
2862 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002863
2864 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002865 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002866 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002867 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002868 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002869 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002870 }
2871
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002872 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002873
2874 if (match.sk)
2875 sock_put(match.sk);
2876
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002877 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002878}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002879
Johan Hedberg744cf192011-11-08 20:40:14 +02002880int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002881{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002882 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002883 bool changed = false;
2884 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002885
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002886 if (discoverable) {
2887 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2888 changed = true;
2889 } else {
2890 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2891 changed = true;
2892 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002893
Johan Hedberged9b5f22012-02-21 20:47:06 +02002894 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002895 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002896
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002897 if (changed)
2898 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002899
Johan Hedberg73f22f62010-12-29 16:00:25 +02002900 if (match.sk)
2901 sock_put(match.sk);
2902
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002903 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002904}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002905
Johan Hedberg744cf192011-11-08 20:40:14 +02002906int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002907{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002908 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002909 bool changed = false;
2910 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002911
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002912 if (connectable) {
2913 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2914 changed = true;
2915 } else {
2916 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2917 changed = true;
2918 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002919
Johan Hedberged9b5f22012-02-21 20:47:06 +02002920 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002921 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002922
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002923 if (changed)
2924 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002925
2926 if (match.sk)
2927 sock_put(match.sk);
2928
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002929 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002930}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002931
Johan Hedberg744cf192011-11-08 20:40:14 +02002932int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002933{
Johan Hedbergca69b792011-11-11 18:10:00 +02002934 u8 mgmt_err = mgmt_status(status);
2935
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002936 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002937 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002938 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002939
2940 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002941 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002942 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002943
2944 return 0;
2945}
2946
Vishal Agarwal745c0ce2012-04-13 17:43:22 +05302947int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key, bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002948{
Johan Hedberg86742e12011-11-07 23:13:38 +02002949 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002950
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002951 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002952
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002953 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002954 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03002955 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002956 ev.key.type = key->type;
2957 memcpy(ev.key.val, key->val, 16);
2958 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002959
Johan Hedberg744cf192011-11-08 20:40:14 +02002960 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002961}
Johan Hedbergf7520542011-01-20 12:34:39 +02002962
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002963int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2964{
2965 struct mgmt_ev_new_long_term_key ev;
2966
2967 memset(&ev, 0, sizeof(ev));
2968
2969 ev.store_hint = persistent;
2970 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03002971 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002972 ev.key.authenticated = key->authenticated;
2973 ev.key.enc_size = key->enc_size;
2974 ev.key.ediv = key->ediv;
2975
2976 if (key->type == HCI_SMP_LTK)
2977 ev.key.master = 1;
2978
2979 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
2980 memcpy(ev.key.val, key->val, sizeof(key->val));
2981
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002982 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
2983 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002984}
2985
Johan Hedbergafc747a2012-01-15 18:11:07 +02002986int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002987 u8 addr_type, u32 flags, u8 *name, u8 name_len,
2988 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02002989{
Johan Hedbergb644ba32012-01-17 21:48:47 +02002990 char buf[512];
2991 struct mgmt_ev_device_connected *ev = (void *) buf;
2992 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02002993
Johan Hedbergb644ba32012-01-17 21:48:47 +02002994 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03002995 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002996
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02002997 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02002998
Johan Hedbergb644ba32012-01-17 21:48:47 +02002999 if (name_len > 0)
3000 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003001 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003002
3003 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003004 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003005 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003006
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003007 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003008
3009 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003010 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003011}
3012
Johan Hedberg8962ee72011-01-20 12:40:27 +02003013static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3014{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003015 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003016 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003017 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003018
Johan Hedberg88c3df12012-02-09 14:27:38 +02003019 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3020 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003021
Johan Hedbergaee9b212012-02-18 15:07:59 +02003022 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003023 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003024
3025 *sk = cmd->sk;
3026 sock_hold(*sk);
3027
Johan Hedberga664b5b2011-02-19 12:06:02 -03003028 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003029}
3030
Johan Hedberg124f6e32012-02-09 13:50:12 +02003031static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003032{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003033 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003034 struct mgmt_cp_unpair_device *cp = cmd->param;
3035 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003036
3037 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003038 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3039 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003040
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003041 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3042
Johan Hedbergaee9b212012-02-18 15:07:59 +02003043 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003044
3045 mgmt_pending_remove(cmd);
3046}
3047
Johan Hedbergafc747a2012-01-15 18:11:07 +02003048int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003049 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003050{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003051 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003052 struct sock *sk = NULL;
3053 int err;
3054
Johan Hedberg744cf192011-11-08 20:40:14 +02003055 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003056
Johan Hedbergf7520542011-01-20 12:34:39 +02003057 bacpy(&ev.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003058 ev.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003059
Johan Hedbergafc747a2012-01-15 18:11:07 +02003060 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003061 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003062
3063 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003064 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003065
Johan Hedberg124f6e32012-02-09 13:50:12 +02003066 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003067 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003068
Johan Hedberg8962ee72011-01-20 12:40:27 +02003069 return err;
3070}
3071
Johan Hedberg88c3df12012-02-09 14:27:38 +02003072int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003073 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003074{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003075 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003076 struct pending_cmd *cmd;
3077 int err;
3078
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003079 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003080 if (!cmd)
3081 return -ENOENT;
3082
Johan Hedberg88c3df12012-02-09 14:27:38 +02003083 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003084 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003085
Johan Hedberg88c3df12012-02-09 14:27:38 +02003086 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003087 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003088
Johan Hedberga664b5b2011-02-19 12:06:02 -03003089 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003090
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003091 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
3092 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003093 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003094}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003095
Johan Hedberg48264f02011-11-09 13:58:58 +02003096int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003097 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003098{
3099 struct mgmt_ev_connect_failed ev;
3100
Johan Hedberg4c659c32011-11-07 23:13:39 +02003101 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003102 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003103 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003104
Johan Hedberg744cf192011-11-08 20:40:14 +02003105 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003106}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003107
Johan Hedberg744cf192011-11-08 20:40:14 +02003108int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003109{
3110 struct mgmt_ev_pin_code_request ev;
3111
Johan Hedbergd8457692012-02-17 14:24:57 +02003112 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003113 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003114 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003115
Johan Hedberg744cf192011-11-08 20:40:14 +02003116 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003117 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003118}
3119
Johan Hedberg744cf192011-11-08 20:40:14 +02003120int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003121 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003122{
3123 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003124 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003125 int err;
3126
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003127 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003128 if (!cmd)
3129 return -ENOENT;
3130
Johan Hedbergd8457692012-02-17 14:24:57 +02003131 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003132 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003133
Johan Hedbergaee9b212012-02-18 15:07:59 +02003134 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003135 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003136
Johan Hedberga664b5b2011-02-19 12:06:02 -03003137 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003138
3139 return err;
3140}
3141
Johan Hedberg744cf192011-11-08 20:40:14 +02003142int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003143 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003144{
3145 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003146 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003147 int err;
3148
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003149 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003150 if (!cmd)
3151 return -ENOENT;
3152
Johan Hedbergd8457692012-02-17 14:24:57 +02003153 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003154 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003155
Johan Hedbergaee9b212012-02-18 15:07:59 +02003156 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003157 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003158
Johan Hedberga664b5b2011-02-19 12:06:02 -03003159 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003160
3161 return err;
3162}
Johan Hedberga5c29682011-02-19 12:05:57 -03003163
Johan Hedberg744cf192011-11-08 20:40:14 +02003164int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003165 u8 link_type, u8 addr_type, __le32 value,
3166 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003167{
3168 struct mgmt_ev_user_confirm_request ev;
3169
Johan Hedberg744cf192011-11-08 20:40:14 +02003170 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003171
Johan Hedberg272d90d2012-02-09 15:26:12 +02003172 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003173 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003174 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e80982012-03-09 13:00:50 +02003175 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003176
Johan Hedberg744cf192011-11-08 20:40:14 +02003177 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003178 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003179}
3180
Johan Hedberg272d90d2012-02-09 15:26:12 +02003181int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
3182 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003183{
3184 struct mgmt_ev_user_passkey_request ev;
3185
3186 BT_DBG("%s", hdev->name);
3187
Johan Hedberg272d90d2012-02-09 15:26:12 +02003188 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003189 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003190
3191 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003192 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003193}
3194
Brian Gix0df4c182011-11-16 13:53:13 -08003195static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg272d90d2012-02-09 15:26:12 +02003196 u8 link_type, u8 addr_type, u8 status,
3197 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003198{
3199 struct pending_cmd *cmd;
3200 struct mgmt_rp_user_confirm_reply rp;
3201 int err;
3202
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003203 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003204 if (!cmd)
3205 return -ENOENT;
3206
Johan Hedberg272d90d2012-02-09 15:26:12 +02003207 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003208 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b212012-02-18 15:07:59 +02003209 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003210 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003211
Johan Hedberga664b5b2011-02-19 12:06:02 -03003212 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003213
3214 return err;
3215}
3216
Johan Hedberg744cf192011-11-08 20:40:14 +02003217int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003218 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003219{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003220 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003221 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003222}
3223
Johan Hedberg272d90d2012-02-09 15:26:12 +02003224int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003225 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003226{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003227 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003228 status, MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003229}
Johan Hedberg2a611692011-02-19 12:06:00 -03003230
Brian Gix604086b2011-11-23 08:28:33 -08003231int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003232 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003233{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003234 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003235 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003236}
3237
Johan Hedberg272d90d2012-02-09 15:26:12 +02003238int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003239 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003240{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003241 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003242 status, MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003243}
3244
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003245int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003246 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003247{
3248 struct mgmt_ev_auth_failed ev;
3249
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003250 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003251 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003252 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003253
Johan Hedberg744cf192011-11-08 20:40:14 +02003254 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003255}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003256
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003257int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3258{
3259 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003260 bool changed = false;
3261 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003262
3263 if (status) {
3264 u8 mgmt_err = mgmt_status(status);
3265 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003266 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003267 return 0;
3268 }
3269
Johan Hedberg47990ea2012-02-22 11:58:37 +02003270 if (test_bit(HCI_AUTH, &hdev->flags)) {
3271 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3272 changed = true;
3273 } else {
3274 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3275 changed = true;
3276 }
3277
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003278 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003279 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003280
Johan Hedberg47990ea2012-02-22 11:58:37 +02003281 if (changed)
3282 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003283
3284 if (match.sk)
3285 sock_put(match.sk);
3286
3287 return err;
3288}
3289
Johan Hedbergcacaf522012-02-21 00:52:42 +02003290static int clear_eir(struct hci_dev *hdev)
3291{
3292 struct hci_cp_write_eir cp;
3293
3294 if (!(hdev->features[6] & LMP_EXT_INQ))
3295 return 0;
3296
Johan Hedbergc80da272012-02-22 15:38:48 +02003297 memset(hdev->eir, 0, sizeof(hdev->eir));
3298
Johan Hedbergcacaf522012-02-21 00:52:42 +02003299 memset(&cp, 0, sizeof(cp));
3300
3301 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3302}
3303
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003304int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003305{
3306 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003307 bool changed = false;
3308 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003309
3310 if (status) {
3311 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003312
3313 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003314 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003315 err = new_settings(hdev, NULL);
3316
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003317 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3318 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003319
3320 return err;
3321 }
3322
3323 if (enable) {
3324 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3325 changed = true;
3326 } else {
3327 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3328 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003329 }
3330
3331 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3332
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003333 if (changed)
3334 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003335
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003336 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003337 sock_put(match.sk);
3338
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003339 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3340 update_eir(hdev);
3341 else
3342 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003343
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003344 return err;
3345}
3346
Johan Hedberg90e70452012-02-23 23:09:40 +02003347static void class_rsp(struct pending_cmd *cmd, void *data)
3348{
3349 struct cmd_lookup *match = data;
3350
3351 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003352 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003353
3354 list_del(&cmd->list);
3355
3356 if (match->sk == NULL) {
3357 match->sk = cmd->sk;
3358 sock_hold(match->sk);
3359 }
3360
3361 mgmt_pending_free(cmd);
3362}
3363
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003364int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003365 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003366{
Johan Hedberg90e70452012-02-23 23:09:40 +02003367 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3368 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003369
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003370 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3371
Johan Hedberg90e70452012-02-23 23:09:40 +02003372 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3373 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3374 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3375
3376 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003377 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3378 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003379
3380 if (match.sk)
3381 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003382
3383 return err;
3384}
3385
Johan Hedberg744cf192011-11-08 20:40:14 +02003386int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003387{
3388 struct pending_cmd *cmd;
3389 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003390 bool changed = false;
3391 int err = 0;
3392
3393 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3394 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3395 changed = true;
3396 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003397
3398 memset(&ev, 0, sizeof(ev));
3399 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003400 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003401
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003402 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003403 if (!cmd)
3404 goto send_event;
3405
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003406 /* Always assume that either the short or the complete name has
3407 * changed if there was a pending mgmt command */
3408 changed = true;
3409
Johan Hedbergb312b1612011-03-16 14:29:37 +02003410 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003411 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003412 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003413 goto failed;
3414 }
3415
Johan Hedbergaee9b212012-02-18 15:07:59 +02003416 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003417 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003418 if (err < 0)
3419 goto failed;
3420
3421send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003422 if (changed)
3423 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003424 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003425
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003426 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003427
3428failed:
3429 if (cmd)
3430 mgmt_pending_remove(cmd);
3431 return err;
3432}
Szymon Jancc35938b2011-03-22 13:12:21 +01003433
Johan Hedberg744cf192011-11-08 20:40:14 +02003434int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003435 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003436{
3437 struct pending_cmd *cmd;
3438 int err;
3439
Johan Hedberg744cf192011-11-08 20:40:14 +02003440 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003441
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003442 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003443 if (!cmd)
3444 return -ENOENT;
3445
3446 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003447 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3448 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003449 } else {
3450 struct mgmt_rp_read_local_oob_data rp;
3451
3452 memcpy(rp.hash, hash, sizeof(rp.hash));
3453 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3454
Johan Hedberg744cf192011-11-08 20:40:14 +02003455 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003456 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3457 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003458 }
3459
3460 mgmt_pending_remove(cmd);
3461
3462 return err;
3463}
Johan Hedberge17acd42011-03-30 23:57:16 +03003464
Johan Hedberg06199cf2012-02-22 16:37:11 +02003465int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3466{
3467 struct cmd_lookup match = { NULL, hdev };
3468 bool changed = false;
3469 int err = 0;
3470
3471 if (status) {
3472 u8 mgmt_err = mgmt_status(status);
3473
3474 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003475 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003476 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003477
Szymon Jancd97dcb62012-03-16 16:02:56 +01003478 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3479 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003480
3481 return err;
3482 }
3483
3484 if (enable) {
3485 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3486 changed = true;
3487 } else {
3488 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3489 changed = true;
3490 }
3491
3492 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3493
3494 if (changed)
3495 err = new_settings(hdev, match.sk);
3496
3497 if (match.sk)
3498 sock_put(match.sk);
3499
3500 return err;
3501}
3502
Johan Hedberg48264f02011-11-09 13:58:58 +02003503int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003504 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3505 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003506{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003507 char buf[512];
3508 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003509 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003510
Johan Hedberg1dc06092012-01-15 21:01:23 +02003511 /* Leave 5 bytes for a potential CoD field */
3512 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003513 return -EINVAL;
3514
Johan Hedberg1dc06092012-01-15 21:01:23 +02003515 memset(buf, 0, sizeof(buf));
3516
Johan Hedberge319d2e2012-01-15 19:51:59 +02003517 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003518 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003519 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003520 if (cfm_name)
3521 ev->flags[0] |= MGMT_DEV_FOUND_CONFIRM_NAME;
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003522 if (!ssp)
3523 ev->flags[0] |= MGMT_DEV_FOUND_LEGACY_PAIRING;
Johan Hedberge17acd42011-03-30 23:57:16 +03003524
Johan Hedberg1dc06092012-01-15 21:01:23 +02003525 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003526 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003527
Johan Hedberg1dc06092012-01-15 21:01:23 +02003528 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3529 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003530 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003531
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003532 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003533
3534 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003535
Johan Hedberge319d2e2012-01-15 19:51:59 +02003536 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003537}
Johan Hedberga88a9652011-03-30 13:18:12 +03003538
Johan Hedbergb644ba32012-01-17 21:48:47 +02003539int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003540 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003541{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003542 struct mgmt_ev_device_found *ev;
3543 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3544 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003545
Johan Hedbergb644ba32012-01-17 21:48:47 +02003546 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003547
Johan Hedbergb644ba32012-01-17 21:48:47 +02003548 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003549
Johan Hedbergb644ba32012-01-17 21:48:47 +02003550 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003551 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003552 ev->rssi = rssi;
3553
3554 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003555 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003556
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003557 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003558
Johan Hedberg053c7e02012-02-04 00:06:00 +02003559 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003560 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003561}
Johan Hedberg314b2382011-04-27 10:29:57 -04003562
Andre Guedes7a135102011-11-09 17:14:25 -03003563int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003564{
3565 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003566 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003567 int err;
3568
Andre Guedes203159d2012-02-13 15:41:01 -03003569 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3570
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003571 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003572 if (!cmd)
3573 return -ENOENT;
3574
Johan Hedbergf808e162012-02-19 12:52:07 +02003575 type = hdev->discovery.type;
3576
3577 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003578 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003579 mgmt_pending_remove(cmd);
3580
3581 return err;
3582}
3583
Andre Guedese6d465c2011-11-09 17:14:26 -03003584int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3585{
3586 struct pending_cmd *cmd;
3587 int err;
3588
3589 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3590 if (!cmd)
3591 return -ENOENT;
3592
Johan Hedbergd9306502012-02-20 23:25:18 +02003593 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003594 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003595 mgmt_pending_remove(cmd);
3596
3597 return err;
3598}
Johan Hedberg314b2382011-04-27 10:29:57 -04003599
Johan Hedberg744cf192011-11-08 20:40:14 +02003600int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003601{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003602 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003603 struct pending_cmd *cmd;
3604
Andre Guedes343fb142011-11-22 17:14:19 -03003605 BT_DBG("%s discovering %u", hdev->name, discovering);
3606
Johan Hedberg164a6e72011-11-01 17:06:44 +02003607 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003608 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003609 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003610 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003611
3612 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003613 u8 type = hdev->discovery.type;
3614
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003615 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3616 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003617 mgmt_pending_remove(cmd);
3618 }
3619
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003620 memset(&ev, 0, sizeof(ev));
3621 ev.type = hdev->discovery.type;
3622 ev.discovering = discovering;
3623
3624 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003625}
Antti Julku5e762442011-08-25 16:48:02 +03003626
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003627int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003628{
3629 struct pending_cmd *cmd;
3630 struct mgmt_ev_device_blocked ev;
3631
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003632 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003633
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003634 bacpy(&ev.addr.bdaddr, bdaddr);
3635 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003636
Johan Hedberg744cf192011-11-08 20:40:14 +02003637 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003638 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003639}
3640
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003641int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003642{
3643 struct pending_cmd *cmd;
3644 struct mgmt_ev_device_unblocked ev;
3645
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003646 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003647
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003648 bacpy(&ev.addr.bdaddr, bdaddr);
3649 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003650
Johan Hedberg744cf192011-11-08 20:40:14 +02003651 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003652 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003653}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003654
3655module_param(enable_hs, bool, 0644);
3656MODULE_PARM_DESC(enable_hs, "Enable High Speed support");