blob: 86590c6532321c5b88053d241e5bb246e89c7dcb [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
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
Brian Gix5fe57d92011-12-21 16:12:13 -080033#include <net/bluetooth/smp.h>
Johan Hedberg03811012010-12-08 00:21:06 +020034
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010035bool enable_hs;
Marcel Holtmannd7b7e792012-02-20 21:47:49 +010036
Johan Hedberg2da9c552012-02-17 14:39:28 +020037#define MGMT_VERSION 1
Marcel Holtmann053262d2012-03-27 18:49:02 +020038#define MGMT_REVISION 1
Johan Hedberg02d98122010-12-13 21:07:04 +020039
Johan Hedberge70bb2e2012-02-13 16:59:33 +020040static const u16 mgmt_commands[] = {
41 MGMT_OP_READ_INDEX_LIST,
42 MGMT_OP_READ_INFO,
43 MGMT_OP_SET_POWERED,
44 MGMT_OP_SET_DISCOVERABLE,
45 MGMT_OP_SET_CONNECTABLE,
46 MGMT_OP_SET_FAST_CONNECTABLE,
47 MGMT_OP_SET_PAIRABLE,
48 MGMT_OP_SET_LINK_SECURITY,
49 MGMT_OP_SET_SSP,
50 MGMT_OP_SET_HS,
51 MGMT_OP_SET_LE,
52 MGMT_OP_SET_DEV_CLASS,
53 MGMT_OP_SET_LOCAL_NAME,
54 MGMT_OP_ADD_UUID,
55 MGMT_OP_REMOVE_UUID,
56 MGMT_OP_LOAD_LINK_KEYS,
57 MGMT_OP_LOAD_LONG_TERM_KEYS,
58 MGMT_OP_DISCONNECT,
59 MGMT_OP_GET_CONNECTIONS,
60 MGMT_OP_PIN_CODE_REPLY,
61 MGMT_OP_PIN_CODE_NEG_REPLY,
62 MGMT_OP_SET_IO_CAPABILITY,
63 MGMT_OP_PAIR_DEVICE,
64 MGMT_OP_CANCEL_PAIR_DEVICE,
65 MGMT_OP_UNPAIR_DEVICE,
66 MGMT_OP_USER_CONFIRM_REPLY,
67 MGMT_OP_USER_CONFIRM_NEG_REPLY,
68 MGMT_OP_USER_PASSKEY_REPLY,
69 MGMT_OP_USER_PASSKEY_NEG_REPLY,
70 MGMT_OP_READ_LOCAL_OOB_DATA,
71 MGMT_OP_ADD_REMOTE_OOB_DATA,
72 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
73 MGMT_OP_START_DISCOVERY,
74 MGMT_OP_STOP_DISCOVERY,
75 MGMT_OP_CONFIRM_NAME,
76 MGMT_OP_BLOCK_DEVICE,
77 MGMT_OP_UNBLOCK_DEVICE,
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -070078 MGMT_OP_SET_DEVICE_ID,
Johan Hedberge70bb2e2012-02-13 16:59:33 +020079};
80
81static const u16 mgmt_events[] = {
82 MGMT_EV_CONTROLLER_ERROR,
83 MGMT_EV_INDEX_ADDED,
84 MGMT_EV_INDEX_REMOVED,
85 MGMT_EV_NEW_SETTINGS,
86 MGMT_EV_CLASS_OF_DEV_CHANGED,
87 MGMT_EV_LOCAL_NAME_CHANGED,
88 MGMT_EV_NEW_LINK_KEY,
89 MGMT_EV_NEW_LONG_TERM_KEY,
90 MGMT_EV_DEVICE_CONNECTED,
91 MGMT_EV_DEVICE_DISCONNECTED,
92 MGMT_EV_CONNECT_FAILED,
93 MGMT_EV_PIN_CODE_REQUEST,
94 MGMT_EV_USER_CONFIRM_REQUEST,
95 MGMT_EV_USER_PASSKEY_REQUEST,
96 MGMT_EV_AUTH_FAILED,
97 MGMT_EV_DEVICE_FOUND,
98 MGMT_EV_DISCOVERING,
99 MGMT_EV_DEVICE_BLOCKED,
100 MGMT_EV_DEVICE_UNBLOCKED,
101 MGMT_EV_DEVICE_UNPAIRED,
102};
103
Andre Guedes3fd24152012-02-03 17:48:01 -0300104/*
105 * These LE scan and inquiry parameters were chosen according to LE General
106 * Discovery Procedure specification.
107 */
108#define LE_SCAN_TYPE 0x01
109#define LE_SCAN_WIN 0x12
110#define LE_SCAN_INT 0x12
111#define LE_SCAN_TIMEOUT_LE_ONLY 10240 /* TGAP(gen_disc_scan_min) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300112#define LE_SCAN_TIMEOUT_BREDR_LE 5120 /* TGAP(100)/2 */
Andre Guedes3fd24152012-02-03 17:48:01 -0300113
Andre Guedese8777522012-02-03 17:48:02 -0300114#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
Andre Guedes5e0452c2012-02-17 20:39:38 -0300115#define INQUIRY_LEN_BREDR_LE 0x04 /* TGAP(100)/2 */
Andre Guedes2519a1f2011-11-07 11:45:24 -0300116
Marcel Holtmann17b02e62012-03-01 14:32:37 -0800117#define CACHE_TIMEOUT msecs_to_jiffies(2 * 1000)
Johan Hedberg7d785252011-12-15 00:47:39 +0200118
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200119#define hdev_is_powered(hdev) (test_bit(HCI_UP, &hdev->flags) && \
120 !test_bit(HCI_AUTO_OFF, &hdev->dev_flags))
121
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200122struct pending_cmd {
123 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +0200124 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200125 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100126 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200127 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -0300128 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200129};
130
Johan Hedbergca69b792011-11-11 18:10:00 +0200131/* HCI to MGMT error code conversion table */
132static u8 mgmt_status_table[] = {
133 MGMT_STATUS_SUCCESS,
134 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
135 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
136 MGMT_STATUS_FAILED, /* Hardware Failure */
137 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
138 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
139 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
140 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
141 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
142 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
143 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
144 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
145 MGMT_STATUS_BUSY, /* Command Disallowed */
146 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
147 MGMT_STATUS_REJECTED, /* Rejected Security */
148 MGMT_STATUS_REJECTED, /* Rejected Personal */
149 MGMT_STATUS_TIMEOUT, /* Host Timeout */
150 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
151 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
152 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
153 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
154 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
155 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
156 MGMT_STATUS_BUSY, /* Repeated Attempts */
157 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
158 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
159 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
160 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
161 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
162 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
163 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
164 MGMT_STATUS_FAILED, /* Unspecified Error */
165 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
166 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
167 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
168 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
169 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
170 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
171 MGMT_STATUS_FAILED, /* Unit Link Key Used */
172 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
173 MGMT_STATUS_TIMEOUT, /* Instant Passed */
174 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
175 MGMT_STATUS_FAILED, /* Transaction Collision */
176 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
177 MGMT_STATUS_REJECTED, /* QoS Rejected */
178 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
179 MGMT_STATUS_REJECTED, /* Insufficient Security */
180 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
181 MGMT_STATUS_BUSY, /* Role Switch Pending */
182 MGMT_STATUS_FAILED, /* Slot Violation */
183 MGMT_STATUS_FAILED, /* Role Switch Failed */
184 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
185 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
186 MGMT_STATUS_BUSY, /* Host Busy Pairing */
187 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
188 MGMT_STATUS_BUSY, /* Controller Busy */
189 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
190 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
191 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
192 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
193 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
194};
195
196static u8 mgmt_status(u8 hci_status)
197{
198 if (hci_status < ARRAY_SIZE(mgmt_status_table))
199 return mgmt_status_table[hci_status];
200
201 return MGMT_STATUS_FAILED;
202}
203
Szymon Janc4e51eae2011-02-25 19:05:48 +0100204static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200205{
206 struct sk_buff *skb;
207 struct mgmt_hdr *hdr;
208 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300209 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200210
Szymon Janc34eb5252011-02-28 14:10:08 +0100211 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200212
213 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
214 if (!skb)
215 return -ENOMEM;
216
217 hdr = (void *) skb_put(skb, sizeof(*hdr));
218
219 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100220 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200221 hdr->len = cpu_to_le16(sizeof(*ev));
222
223 ev = (void *) skb_put(skb, sizeof(*ev));
224 ev->status = status;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200225 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200226
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300227 err = sock_queue_rcv_skb(sk, skb);
228 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200229 kfree_skb(skb);
230
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300231 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200232}
233
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200234static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300235 void *rp, size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200236{
237 struct sk_buff *skb;
238 struct mgmt_hdr *hdr;
239 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300240 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200241
242 BT_DBG("sock %p", sk);
243
Johan Hedberga38528f2011-01-22 06:46:43 +0200244 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200245 if (!skb)
246 return -ENOMEM;
247
248 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200249
Johan Hedberg02d98122010-12-13 21:07:04 +0200250 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100251 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200252 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200253
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200255 ev->opcode = cpu_to_le16(cmd);
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200256 ev->status = status;
Szymon Janc8020c162011-02-28 14:09:50 +0100257
258 if (rp)
259 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200260
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300261 err = sock_queue_rcv_skb(sk, skb);
262 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200263 kfree_skb(skb);
264
Marcel Holtmanne5f0e152012-02-22 11:59:01 +0100265 return err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200266}
267
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300268static int read_version(struct sock *sk, struct hci_dev *hdev, void *data,
269 u16 data_len)
Johan Hedberga38528f2011-01-22 06:46:43 +0200270{
271 struct mgmt_rp_read_version rp;
272
273 BT_DBG("sock %p", sk);
274
275 rp.version = MGMT_VERSION;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200276 rp.revision = __constant_cpu_to_le16(MGMT_REVISION);
Johan Hedberga38528f2011-01-22 06:46:43 +0200277
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200278 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300279 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200280}
281
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300282static int read_commands(struct sock *sk, struct hci_dev *hdev, void *data,
283 u16 data_len)
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200284{
285 struct mgmt_rp_read_commands *rp;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200286 const u16 num_commands = ARRAY_SIZE(mgmt_commands);
287 const u16 num_events = ARRAY_SIZE(mgmt_events);
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +0200288 __le16 *opcode;
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200289 size_t rp_size;
290 int i, err;
291
292 BT_DBG("sock %p", sk);
293
294 rp_size = sizeof(*rp) + ((num_commands + num_events) * sizeof(u16));
295
296 rp = kmalloc(rp_size, GFP_KERNEL);
297 if (!rp)
298 return -ENOMEM;
299
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200300 rp->num_commands = __constant_cpu_to_le16(num_commands);
301 rp->num_events = __constant_cpu_to_le16(num_events);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200302
303 for (i = 0, opcode = rp->opcodes; i < num_commands; i++, opcode++)
304 put_unaligned_le16(mgmt_commands[i], opcode);
305
306 for (i = 0; i < num_events; i++, opcode++)
307 put_unaligned_le16(mgmt_events[i], opcode);
308
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200309 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_COMMANDS, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300310 rp_size);
Johan Hedberge70bb2e2012-02-13 16:59:33 +0200311 kfree(rp);
312
313 return err;
314}
315
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300316static int read_index_list(struct sock *sk, struct hci_dev *hdev, void *data,
317 u16 data_len)
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200318{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200319 struct mgmt_rp_read_index_list *rp;
320 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200321 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200322 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200323 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200324 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200325
326 BT_DBG("sock %p", sk);
327
328 read_lock(&hci_dev_list_lock);
329
330 count = 0;
331 list_for_each(p, &hci_dev_list) {
332 count++;
333 }
334
Johan Hedberga38528f2011-01-22 06:46:43 +0200335 rp_len = sizeof(*rp) + (2 * count);
336 rp = kmalloc(rp_len, GFP_ATOMIC);
337 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100338 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200339 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100340 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200341
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200342 rp->num_controllers = cpu_to_le16(count);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200343
344 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200345 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200346 if (test_bit(HCI_SETUP, &d->dev_flags))
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200347 continue;
348
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200349 rp->index[i++] = cpu_to_le16(d->id);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200350 BT_DBG("Added hci%u", d->id);
351 }
352
353 read_unlock(&hci_dev_list_lock);
354
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200355 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, 0, rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300356 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200357
Johan Hedberga38528f2011-01-22 06:46:43 +0200358 kfree(rp);
359
360 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200361}
362
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200363static u32 get_supported_settings(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +0200364{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200365 u32 settings = 0;
Johan Hedberg03811012010-12-08 00:21:06 +0200366
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200367 settings |= MGMT_SETTING_POWERED;
368 settings |= MGMT_SETTING_CONNECTABLE;
369 settings |= MGMT_SETTING_FAST_CONNECTABLE;
370 settings |= MGMT_SETTING_DISCOVERABLE;
371 settings |= MGMT_SETTING_PAIRABLE;
Johan Hedberg03811012010-12-08 00:21:06 +0200372
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200373 if (hdev->features[6] & LMP_SIMPLE_PAIR)
374 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200375
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200376 if (!(hdev->features[4] & LMP_NO_BREDR)) {
377 settings |= MGMT_SETTING_BREDR;
378 settings |= MGMT_SETTING_LINK_SECURITY;
379 }
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200380
Marcel Holtmannd7b7e792012-02-20 21:47:49 +0100381 if (enable_hs)
382 settings |= MGMT_SETTING_HS;
383
Marcel Holtmann9d428202012-05-03 07:12:31 +0200384 if (hdev->features[4] & LMP_LE)
385 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200386
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200387 return settings;
388}
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200389
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200390static u32 get_current_settings(struct hci_dev *hdev)
391{
392 u32 settings = 0;
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200393
Johan Hedbergf1f0eb02012-02-21 17:15:41 +0200394 if (hdev_is_powered(hdev))
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100395 settings |= MGMT_SETTING_POWERED;
396
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200397 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200398 settings |= MGMT_SETTING_CONNECTABLE;
399
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200400 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200401 settings |= MGMT_SETTING_DISCOVERABLE;
402
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200403 if (test_bit(HCI_PAIRABLE, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200404 settings |= MGMT_SETTING_PAIRABLE;
405
406 if (!(hdev->features[4] & LMP_NO_BREDR))
407 settings |= MGMT_SETTING_BREDR;
408
Johan Hedberg06199cf2012-02-22 16:37:11 +0200409 if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200410 settings |= MGMT_SETTING_LE;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200411
Johan Hedberg47990ea2012-02-22 11:58:37 +0200412 if (test_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200413 settings |= MGMT_SETTING_LINK_SECURITY;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200414
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200415 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200416 settings |= MGMT_SETTING_SSP;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200417
Johan Hedberg6d80dfd2012-02-20 23:50:38 +0200418 if (test_bit(HCI_HS_ENABLED, &hdev->dev_flags))
419 settings |= MGMT_SETTING_HS;
420
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200421 return settings;
Johan Hedbergc542a062011-01-26 13:11:03 +0200422}
423
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300424#define PNP_INFO_SVCLASS_ID 0x1200
425
426static u8 bluetooth_base_uuid[] = {
427 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
428 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
429};
430
431static u16 get_uuid16(u8 *uuid128)
432{
433 u32 val;
434 int i;
435
436 for (i = 0; i < 12; i++) {
437 if (bluetooth_base_uuid[i] != uuid128[i])
438 return 0;
439 }
440
Andrei Emeltchenko3e9fb6d2012-03-20 10:32:25 +0200441 val = get_unaligned_le32(&uuid128[12]);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300442 if (val > 0xffff)
443 return 0;
444
445 return (u16) val;
446}
447
448static void create_eir(struct hci_dev *hdev, u8 *data)
449{
450 u8 *ptr = data;
451 u16 eir_len = 0;
452 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
453 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200454 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300455 size_t name_len;
456
457 name_len = strlen(hdev->dev_name);
458
459 if (name_len > 0) {
460 /* EIR Data type */
461 if (name_len > 48) {
462 name_len = 48;
463 ptr[1] = EIR_NAME_SHORT;
464 } else
465 ptr[1] = EIR_NAME_COMPLETE;
466
467 /* EIR Data length */
468 ptr[0] = name_len + 1;
469
470 memcpy(ptr + 2, hdev->dev_name, name_len);
471
472 eir_len += (name_len + 2);
473 ptr += (name_len + 2);
474 }
475
Marcel Holtmann91c4e9b2012-03-11 19:27:21 -0700476 if (hdev->inq_tx_power) {
477 ptr[0] = 2;
478 ptr[1] = EIR_TX_POWER;
479 ptr[2] = (u8) hdev->inq_tx_power;
480
481 eir_len += 3;
482 ptr += 3;
483 }
484
Marcel Holtmann2b9be132012-03-11 19:32:12 -0700485 if (hdev->devid_source > 0) {
486 ptr[0] = 9;
487 ptr[1] = EIR_DEVICE_ID;
488
489 put_unaligned_le16(hdev->devid_source, ptr + 2);
490 put_unaligned_le16(hdev->devid_vendor, ptr + 4);
491 put_unaligned_le16(hdev->devid_product, ptr + 6);
492 put_unaligned_le16(hdev->devid_version, ptr + 8);
493
494 eir_len += 10;
495 ptr += 10;
496 }
497
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300498 memset(uuid16_list, 0, sizeof(uuid16_list));
499
500 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200501 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300502 u16 uuid16;
503
504 uuid16 = get_uuid16(uuid->uuid);
505 if (uuid16 == 0)
506 return;
507
508 if (uuid16 < 0x1100)
509 continue;
510
511 if (uuid16 == PNP_INFO_SVCLASS_ID)
512 continue;
513
514 /* Stop if not enough space to put next UUID */
515 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
516 truncated = 1;
517 break;
518 }
519
520 /* Check for duplicates */
521 for (i = 0; uuid16_list[i] != 0; i++)
522 if (uuid16_list[i] == uuid16)
523 break;
524
525 if (uuid16_list[i] == 0) {
526 uuid16_list[i] = uuid16;
527 eir_len += sizeof(u16);
528 }
529 }
530
531 if (uuid16_list[0] != 0) {
532 u8 *length = ptr;
533
534 /* EIR Data type */
535 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
536
537 ptr += 2;
538 eir_len += 2;
539
540 for (i = 0; uuid16_list[i] != 0; i++) {
541 *ptr++ = (uuid16_list[i] & 0x00ff);
542 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
543 }
544
545 /* EIR Data length */
546 *length = (i * sizeof(u16)) + 1;
547 }
548}
549
550static int update_eir(struct hci_dev *hdev)
551{
552 struct hci_cp_write_eir cp;
553
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200554 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200555 return 0;
556
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300557 if (!(hdev->features[6] & LMP_EXT_INQ))
558 return 0;
559
Johan Hedberg84bde9d2012-01-25 14:21:06 +0200560 if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300561 return 0;
562
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200563 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300564 return 0;
565
566 memset(&cp, 0, sizeof(cp));
567
568 create_eir(hdev, cp.data);
569
570 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
571 return 0;
572
573 memcpy(hdev->eir, cp.data, sizeof(cp.data));
574
575 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
576}
577
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200578static u8 get_service_classes(struct hci_dev *hdev)
579{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300580 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200581 u8 val = 0;
582
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300583 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200584 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200585
586 return val;
587}
588
589static int update_class(struct hci_dev *hdev)
590{
591 u8 cod[3];
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200592 int err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200593
594 BT_DBG("%s", hdev->name);
595
Johan Hedberg504c8dc2012-02-23 13:30:41 +0200596 if (!hdev_is_powered(hdev))
Johan Hedberg7770c4a2012-02-22 22:06:38 +0200597 return 0;
598
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200599 if (test_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200600 return 0;
601
602 cod[0] = hdev->minor_class;
603 cod[1] = hdev->major_class;
604 cod[2] = get_service_classes(hdev);
605
606 if (memcmp(cod, hdev->dev_class, 3) == 0)
607 return 0;
608
Johan Hedbergc95f0ba2012-02-23 22:54:38 +0200609 err = hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
610 if (err == 0)
611 set_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
612
613 return err;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200614}
615
Johan Hedberg7d785252011-12-15 00:47:39 +0200616static void service_cache_off(struct work_struct *work)
617{
618 struct hci_dev *hdev = container_of(work, struct hci_dev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300619 service_cache.work);
Johan Hedberg7d785252011-12-15 00:47:39 +0200620
Johan Hedberga8b2d5c2012-01-08 23:11:15 +0200621 if (!test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags))
Johan Hedberg7d785252011-12-15 00:47:39 +0200622 return;
623
624 hci_dev_lock(hdev);
625
626 update_eir(hdev);
627 update_class(hdev);
628
629 hci_dev_unlock(hdev);
630}
631
Johan Hedberg6a919082012-02-28 06:17:26 +0200632static void mgmt_init_hdev(struct sock *sk, struct hci_dev *hdev)
Johan Hedberg7d785252011-12-15 00:47:39 +0200633{
Johan Hedberg4f87da82012-03-02 19:55:56 +0200634 if (test_and_set_bit(HCI_MGMT, &hdev->dev_flags))
Johan Hedberg6a919082012-02-28 06:17:26 +0200635 return;
636
Johan Hedberg4f87da82012-03-02 19:55:56 +0200637 INIT_DELAYED_WORK(&hdev->service_cache, service_cache_off);
Johan Hedberg7d785252011-12-15 00:47:39 +0200638
Johan Hedberg4f87da82012-03-02 19:55:56 +0200639 /* Non-mgmt controlled devices get this bit set
640 * implicitly so that pairing works for them, however
641 * for mgmt we require user-space to explicitly enable
642 * it
643 */
644 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedberg7d785252011-12-15 00:47:39 +0200645}
646
Johan Hedberg0f4e68c2012-02-28 17:18:30 +0200647static int read_controller_info(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300648 void *data, u16 data_len)
Johan Hedberg03811012010-12-08 00:21:06 +0200649{
650 struct mgmt_rp_read_info rp;
Johan Hedberg03811012010-12-08 00:21:06 +0200651
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200652 BT_DBG("sock %p %s", sk, hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200653
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300654 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200655
Johan Hedberg03811012010-12-08 00:21:06 +0200656 memset(&rp, 0, sizeof(rp));
657
Johan Hedberg03811012010-12-08 00:21:06 +0200658 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200659
660 rp.version = hdev->hci_ver;
Marcel Holtmanneb55ef02012-03-14 18:08:46 +0200661 rp.manufacturer = cpu_to_le16(hdev->manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200662
663 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
664 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
665
666 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedberg03811012010-12-08 00:21:06 +0200667
668 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
Johan Hedberg27fcc362012-02-22 21:46:22 +0200669 memcpy(rp.short_name, hdev->short_name, sizeof(hdev->short_name));
Johan Hedberg03811012010-12-08 00:21:06 +0200670
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300671 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200672
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200673 return cmd_complete(sk, hdev->id, MGMT_OP_READ_INFO, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300674 sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200675}
676
677static void mgmt_pending_free(struct pending_cmd *cmd)
678{
679 sock_put(cmd->sk);
680 kfree(cmd->param);
681 kfree(cmd);
682}
683
684static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300685 struct hci_dev *hdev, void *data,
686 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200687{
688 struct pending_cmd *cmd;
689
690 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
691 if (!cmd)
692 return NULL;
693
694 cmd->opcode = opcode;
695 cmd->index = hdev->id;
696
697 cmd->param = kmalloc(len, GFP_ATOMIC);
698 if (!cmd->param) {
699 kfree(cmd);
700 return NULL;
701 }
702
703 if (data)
704 memcpy(cmd->param, data, len);
705
706 cmd->sk = sk;
707 sock_hold(sk);
708
709 list_add(&cmd->list, &hdev->mgmt_pending);
710
711 return cmd;
712}
713
714static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -0300715 void (*cb)(struct pending_cmd *cmd,
716 void *data),
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300717 void *data)
Johan Hedberg03811012010-12-08 00:21:06 +0200718{
719 struct list_head *p, *n;
720
721 list_for_each_safe(p, n, &hdev->mgmt_pending) {
722 struct pending_cmd *cmd;
723
724 cmd = list_entry(p, struct pending_cmd, list);
725
726 if (opcode > 0 && cmd->opcode != opcode)
727 continue;
728
729 cb(cmd, data);
730 }
731}
732
733static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
734{
735 struct pending_cmd *cmd;
736
737 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
738 if (cmd->opcode == opcode)
739 return cmd;
740 }
741
742 return NULL;
743}
744
745static void mgmt_pending_remove(struct pending_cmd *cmd)
746{
747 list_del(&cmd->list);
748 mgmt_pending_free(cmd);
749}
750
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200751static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200752{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200753 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200754
Johan Hedbergaee9b2182012-02-18 15:07:59 +0200755 return cmd_complete(sk, hdev->id, opcode, 0, &settings,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300756 sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200757}
758
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200759static int set_powered(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300760 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200761{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300762 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200763 struct pending_cmd *cmd;
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200764 int err;
Johan Hedberg03811012010-12-08 00:21:06 +0200765
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200766 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200767
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300768 hci_dev_lock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200769
Marcel Holtmannf0d4b782012-02-21 12:14:25 +0100770 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->dev_flags)) {
771 cancel_delayed_work(&hdev->power_off);
772
773 if (cp->val) {
774 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
775 mgmt_powered(hdev, 1);
776 goto failed;
777 }
778 }
779
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200780 if (!!cp->val == hdev_is_powered(hdev)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200781 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200782 goto failed;
783 }
784
785 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200786 err = cmd_status(sk, hdev->id, MGMT_OP_SET_POWERED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300787 MGMT_STATUS_BUSY);
Johan Hedberg03811012010-12-08 00:21:06 +0200788 goto failed;
789 }
790
791 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
792 if (!cmd) {
793 err = -ENOMEM;
794 goto failed;
795 }
796
797 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200798 schedule_work(&hdev->power_on);
Johan Hedberg03811012010-12-08 00:21:06 +0200799 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200800 schedule_work(&hdev->power_off.work);
Johan Hedberg03811012010-12-08 00:21:06 +0200801
802 err = 0;
803
804failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300805 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200806 return err;
807}
808
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300809static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
810 struct sock *skip_sk)
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200811{
812 struct sk_buff *skb;
813 struct mgmt_hdr *hdr;
814
815 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
816 if (!skb)
817 return -ENOMEM;
818
819 hdr = (void *) skb_put(skb, sizeof(*hdr));
820 hdr->opcode = cpu_to_le16(event);
821 if (hdev)
822 hdr->index = cpu_to_le16(hdev->id);
823 else
824 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
825 hdr->len = cpu_to_le16(data_len);
826
827 if (data)
828 memcpy(skb_put(skb, data_len), data, data_len);
829
Marcel Holtmann97e0bde2012-02-22 13:49:28 +0100830 /* Time stamp */
831 __net_timestamp(skb);
832
Johan Hedbergbeadb2b2012-02-21 16:55:31 +0200833 hci_send_to_control(skb, skip_sk);
834 kfree_skb(skb);
835
836 return 0;
837}
838
839static int new_settings(struct hci_dev *hdev, struct sock *skip)
840{
841 __le32 ev;
842
843 ev = cpu_to_le32(get_current_settings(hdev));
844
845 return mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), skip);
846}
847
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200848static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300849 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200850{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300851 struct mgmt_cp_set_discoverable *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200852 struct pending_cmd *cmd;
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200853 u16 timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200854 u8 scan;
855 int err;
856
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200857 BT_DBG("request for %s", hdev->name);
Johan Hedberg03811012010-12-08 00:21:06 +0200858
Marcel Holtmann1f350c82012-03-12 20:31:08 -0700859 timeout = __le16_to_cpu(cp->timeout);
Marcel Holtmann24c54a92012-02-22 18:06:34 +0100860 if (!cp->val && timeout > 0)
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200861 return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300862 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200863
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300864 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200865
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200866 if (!hdev_is_powered(hdev) && timeout > 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200867 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300868 MGMT_STATUS_NOT_POWERED);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200869 goto failed;
870 }
871
872 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300873 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200874 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300875 MGMT_STATUS_BUSY);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200876 goto failed;
877 }
878
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200879 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200880 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300881 MGMT_STATUS_REJECTED);
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200882 goto failed;
883 }
884
885 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200886 bool changed = false;
887
888 if (!!cp->val != test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
889 change_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
890 changed = true;
891 }
892
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200893 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200894 if (err < 0)
895 goto failed;
896
897 if (changed)
898 err = new_settings(hdev, sk);
899
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200900 goto failed;
901 }
902
903 if (!!cp->val == test_bit(HCI_DISCOVERABLE, &hdev->dev_flags)) {
Marcel Holtmann955638e2012-02-22 18:21:00 +0100904 if (hdev->discov_timeout > 0) {
905 cancel_delayed_work(&hdev->discov_off);
906 hdev->discov_timeout = 0;
907 }
908
909 if (cp->val && timeout > 0) {
910 hdev->discov_timeout = timeout;
911 queue_delayed_work(hdev->workqueue, &hdev->discov_off,
912 msecs_to_jiffies(hdev->discov_timeout * 1000));
913 }
914
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200915 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200916 goto failed;
917 }
918
919 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
920 if (!cmd) {
921 err = -ENOMEM;
922 goto failed;
923 }
924
925 scan = SCAN_PAGE;
926
927 if (cp->val)
928 scan |= SCAN_INQUIRY;
929 else
930 cancel_delayed_work(&hdev->discov_off);
931
932 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
933 if (err < 0)
934 mgmt_pending_remove(cmd);
935
Johan Hedberg03811012010-12-08 00:21:06 +0200936 if (cp->val)
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200937 hdev->discov_timeout = timeout;
Johan Hedberg03811012010-12-08 00:21:06 +0200938
939failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300940 hci_dev_unlock(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200941 return err;
942}
943
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200944static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300945 u16 len)
Johan Hedberg03811012010-12-08 00:21:06 +0200946{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -0300947 struct mgmt_mode *cp = data;
Johan Hedberg03811012010-12-08 00:21:06 +0200948 struct pending_cmd *cmd;
949 u8 scan;
950 int err;
951
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200952 BT_DBG("request for %s", hdev->name);
Johan Hedberge41d8b42010-12-13 21:07:03 +0200953
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300954 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200955
Johan Hedberg4b34ee782012-02-21 14:13:02 +0200956 if (!hdev_is_powered(hdev)) {
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200957 bool changed = false;
958
959 if (!!cp->val != test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
960 changed = true;
961
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200962 if (cp->val) {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200963 set_bit(HCI_CONNECTABLE, &hdev->dev_flags);
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200964 } else {
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200965 clear_bit(HCI_CONNECTABLE, &hdev->dev_flags);
966 clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags);
967 }
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200968
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200969 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg0224d2f2012-02-21 19:40:05 +0200970 if (err < 0)
971 goto failed;
972
973 if (changed)
974 err = new_settings(hdev, sk);
975
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200976 goto failed;
977 }
978
979 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -0300980 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +0200981 err = cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -0300982 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200983 goto failed;
984 }
985
Johan Hedberg5e5282b2012-02-21 16:01:30 +0200986 if (!!cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200987 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200988 goto failed;
989 }
990
991 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
992 if (!cmd) {
993 err = -ENOMEM;
994 goto failed;
995 }
996
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200997 if (cp->val) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200998 scan = SCAN_PAGE;
Andrei Emeltchenko6bf0e462012-02-22 13:21:16 +0200999 } else {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001000 scan = 0;
1001
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001002 if (test_bit(HCI_ISCAN, &hdev->flags) &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001003 hdev->discov_timeout > 0)
Johan Hedbergdf2c6c52012-02-21 19:15:49 +02001004 cancel_delayed_work(&hdev->discov_off);
1005 }
1006
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001007 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
1008 if (err < 0)
1009 mgmt_pending_remove(cmd);
1010
1011failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001012 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001013 return err;
1014}
1015
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001016static int set_pairable(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001017 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +02001018{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001019 struct mgmt_mode *cp = data;
Johan Hedberg73f22f62010-12-29 16:00:25 +02001020 int err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001021
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001022 BT_DBG("request for %s", hdev->name);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001023
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001024 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001025
1026 if (cp->val)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001027 set_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001028 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001029 clear_bit(HCI_PAIRABLE, &hdev->dev_flags);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001030
Johan Hedberg69ab39e2011-12-15 00:47:35 +02001031 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001032 if (err < 0)
1033 goto failed;
1034
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02001035 err = new_settings(hdev, sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001036
1037failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001038 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02001039 return err;
1040}
Johan Hedberg72a734e2010-12-30 00:38:22 +02001041
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001042static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
1043 u16 len)
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001044{
1045 struct mgmt_mode *cp = data;
1046 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001047 u8 val;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001048 int err;
1049
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001050 BT_DBG("request for %s", hdev->name);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001051
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001052 hci_dev_lock(hdev);
1053
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001054 if (!hdev_is_powered(hdev)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001055 bool changed = false;
1056
1057 if (!!cp->val != test_bit(HCI_LINK_SECURITY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001058 &hdev->dev_flags)) {
Johan Hedberg47990ea2012-02-22 11:58:37 +02001059 change_bit(HCI_LINK_SECURITY, &hdev->dev_flags);
1060 changed = true;
1061 }
1062
1063 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1064 if (err < 0)
1065 goto failed;
1066
1067 if (changed)
1068 err = new_settings(hdev, sk);
1069
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001070 goto failed;
1071 }
1072
1073 if (mgmt_pending_find(MGMT_OP_SET_LINK_SECURITY, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001074 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001075 MGMT_STATUS_BUSY);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001076 goto failed;
1077 }
1078
1079 val = !!cp->val;
1080
1081 if (test_bit(HCI_AUTH, &hdev->flags) == val) {
1082 err = send_settings_rsp(sk, MGMT_OP_SET_LINK_SECURITY, hdev);
1083 goto failed;
1084 }
1085
1086 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LINK_SECURITY, hdev, data, len);
1087 if (!cmd) {
1088 err = -ENOMEM;
1089 goto failed;
1090 }
1091
1092 err = hci_send_cmd(hdev, HCI_OP_WRITE_AUTH_ENABLE, sizeof(val), &val);
1093 if (err < 0) {
1094 mgmt_pending_remove(cmd);
1095 goto failed;
1096 }
1097
1098failed:
1099 hci_dev_unlock(hdev);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02001100 return err;
1101}
1102
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001103static int set_ssp(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001104{
1105 struct mgmt_mode *cp = data;
1106 struct pending_cmd *cmd;
Johan Hedberg816a11d2012-02-26 13:04:52 +02001107 u8 val;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001108 int err;
1109
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001110 BT_DBG("request for %s", hdev->name);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001111
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001112 hci_dev_lock(hdev);
1113
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001114 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001115 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001116 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6c8f12c2012-02-22 16:35:26 +02001117 goto failed;
1118 }
1119
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001120 val = !!cp->val;
1121
Johan Hedberg4b34ee782012-02-21 14:13:02 +02001122 if (!hdev_is_powered(hdev)) {
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02001123 bool changed = false;
1124
1125 if (val != test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
1126 change_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
1127 changed = true;
1128 }
1129
1130 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1131 if (err < 0)
1132 goto failed;
1133
1134 if (changed)
1135 err = new_settings(hdev, sk);
1136
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001137 goto failed;
1138 }
1139
1140 if (mgmt_pending_find(MGMT_OP_SET_SSP, hdev)) {
Szymon Jancd97dcb62012-03-16 16:02:56 +01001141 err = cmd_status(sk, hdev->id, MGMT_OP_SET_SSP,
1142 MGMT_STATUS_BUSY);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001143 goto failed;
1144 }
1145
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001146 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) == val) {
1147 err = send_settings_rsp(sk, MGMT_OP_SET_SSP, hdev);
1148 goto failed;
1149 }
1150
1151 cmd = mgmt_pending_add(sk, MGMT_OP_SET_SSP, hdev, data, len);
1152 if (!cmd) {
1153 err = -ENOMEM;
1154 goto failed;
1155 }
1156
1157 err = hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, sizeof(val), &val);
1158 if (err < 0) {
1159 mgmt_pending_remove(cmd);
1160 goto failed;
1161 }
1162
1163failed:
1164 hci_dev_unlock(hdev);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02001165 return err;
1166}
1167
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001168static int set_hs(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001169{
1170 struct mgmt_mode *cp = data;
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001171
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001172 BT_DBG("request for %s", hdev->name);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001173
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001174 if (!enable_hs)
1175 return cmd_status(sk, hdev->id, MGMT_OP_SET_HS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001176 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001177
1178 if (cp->val)
1179 set_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1180 else
1181 clear_bit(HCI_HS_ENABLED, &hdev->dev_flags);
1182
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001183 return send_settings_rsp(sk, MGMT_OP_SET_HS, hdev);
Johan Hedberg6d80dfd2012-02-20 23:50:38 +02001184}
1185
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001186static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001187{
1188 struct mgmt_mode *cp = data;
1189 struct hci_cp_write_le_host_supported hci_cp;
1190 struct pending_cmd *cmd;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001191 int err;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001192 u8 val, enabled;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001193
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001194 BT_DBG("request for %s", hdev->name);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001195
Johan Hedberg1de028c2012-02-29 19:55:35 -08001196 hci_dev_lock(hdev);
1197
Marcel Holtmann9d428202012-05-03 07:12:31 +02001198 if (!(hdev->features[4] & LMP_LE)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001199 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001200 MGMT_STATUS_NOT_SUPPORTED);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001201 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001202 }
1203
1204 val = !!cp->val;
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001205 enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001206
Johan Hedberg0b60eba2012-02-28 00:57:24 +02001207 if (!hdev_is_powered(hdev) || val == enabled) {
Johan Hedberg06199cf2012-02-22 16:37:11 +02001208 bool changed = false;
1209
1210 if (val != test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
1211 change_bit(HCI_LE_ENABLED, &hdev->dev_flags);
1212 changed = true;
1213 }
1214
1215 err = send_settings_rsp(sk, MGMT_OP_SET_LE, hdev);
1216 if (err < 0)
Johan Hedberg1de028c2012-02-29 19:55:35 -08001217 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001218
1219 if (changed)
1220 err = new_settings(hdev, sk);
1221
Johan Hedberg1de028c2012-02-29 19:55:35 -08001222 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001223 }
1224
1225 if (mgmt_pending_find(MGMT_OP_SET_LE, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001226 err = cmd_status(sk, hdev->id, MGMT_OP_SET_LE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001227 MGMT_STATUS_BUSY);
Johan Hedberg1de028c2012-02-29 19:55:35 -08001228 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001229 }
1230
1231 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LE, hdev, data, len);
1232 if (!cmd) {
1233 err = -ENOMEM;
Johan Hedberg1de028c2012-02-29 19:55:35 -08001234 goto unlock;
Johan Hedberg06199cf2012-02-22 16:37:11 +02001235 }
1236
1237 memset(&hci_cp, 0, sizeof(hci_cp));
1238
1239 if (val) {
1240 hci_cp.le = val;
1241 hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
1242 }
1243
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001244 err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
1245 &hci_cp);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301246 if (err < 0)
Johan Hedberg06199cf2012-02-22 16:37:11 +02001247 mgmt_pending_remove(cmd);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001248
Johan Hedberg1de028c2012-02-29 19:55:35 -08001249unlock:
1250 hci_dev_unlock(hdev);
Johan Hedberg06199cf2012-02-22 16:37:11 +02001251 return err;
1252}
1253
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001254static int add_uuid(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001255{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001256 struct mgmt_cp_add_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001257 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001258 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001259 int err;
1260
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001261 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001262
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001263 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001264
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001265 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001266 err = cmd_status(sk, hdev->id, MGMT_OP_ADD_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001267 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001268 goto failed;
1269 }
1270
Andre Guedes92c4c202012-06-07 19:05:44 -03001271 uuid = kmalloc(sizeof(*uuid), GFP_KERNEL);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001272 if (!uuid) {
1273 err = -ENOMEM;
1274 goto failed;
1275 }
1276
1277 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001278 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001279
1280 list_add(&uuid->list, &hdev->uuids);
1281
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001282 err = update_class(hdev);
1283 if (err < 0)
1284 goto failed;
1285
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001286 err = update_eir(hdev);
1287 if (err < 0)
1288 goto failed;
1289
Johan Hedberg90e70452012-02-23 23:09:40 +02001290 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001291 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001292 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001293 goto failed;
1294 }
1295
1296 cmd = mgmt_pending_add(sk, MGMT_OP_ADD_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301297 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001298 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001299
1300failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001301 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001302 return err;
1303}
1304
Johan Hedberg24b78d02012-02-23 23:24:30 +02001305static bool enable_service_cache(struct hci_dev *hdev)
1306{
1307 if (!hdev_is_powered(hdev))
1308 return false;
1309
1310 if (!test_and_set_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Marcel Holtmann17b02e62012-03-01 14:32:37 -08001311 schedule_delayed_work(&hdev->service_cache, CACHE_TIMEOUT);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001312 return true;
1313 }
1314
1315 return false;
1316}
1317
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001318static int remove_uuid(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001319 u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001320{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001321 struct mgmt_cp_remove_uuid *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001322 struct pending_cmd *cmd;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001323 struct list_head *p, *n;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001324 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 +02001325 int err, found;
1326
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001327 BT_DBG("request for %s", hdev->name);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001328
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001329 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001330
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001331 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001332 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001333 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001334 goto unlock;
1335 }
1336
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001337 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
1338 err = hci_uuids_clear(hdev);
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001339
Johan Hedberg24b78d02012-02-23 23:24:30 +02001340 if (enable_service_cache(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001341 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001342 0, hdev->dev_class, 3);
Johan Hedberg24b78d02012-02-23 23:24:30 +02001343 goto unlock;
1344 }
Johan Hedberg4004b6d2012-02-23 21:30:12 +02001345
Johan Hedberg9246a862012-02-23 21:33:16 +02001346 goto update_class;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001347 }
1348
1349 found = 0;
1350
1351 list_for_each_safe(p, n, &hdev->uuids) {
1352 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
1353
1354 if (memcmp(match->uuid, cp->uuid, 16) != 0)
1355 continue;
1356
1357 list_del(&match->list);
1358 found++;
1359 }
1360
1361 if (found == 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001362 err = cmd_status(sk, hdev->id, MGMT_OP_REMOVE_UUID,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001363 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001364 goto unlock;
1365 }
1366
Johan Hedberg9246a862012-02-23 21:33:16 +02001367update_class:
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001368 err = update_class(hdev);
1369 if (err < 0)
1370 goto unlock;
1371
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03001372 err = update_eir(hdev);
1373 if (err < 0)
1374 goto unlock;
1375
Johan Hedberg90e70452012-02-23 23:09:40 +02001376 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001377 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_UUID, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001378 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001379 goto unlock;
1380 }
1381
1382 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_UUID, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301383 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001384 err = -ENOMEM;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001385
1386unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001387 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02001388 return err;
1389}
1390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001391static int set_dev_class(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001392 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001393{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001394 struct mgmt_cp_set_dev_class *cp = data;
Johan Hedberg90e70452012-02-23 23:09:40 +02001395 struct pending_cmd *cmd;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001396 int err;
1397
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001398 BT_DBG("request for %s", hdev->name);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001399
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001400 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001401
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001402 if (test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001403 err = cmd_status(sk, hdev->id, MGMT_OP_SET_DEV_CLASS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001404 MGMT_STATUS_BUSY);
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02001405 goto unlock;
1406 }
1407
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001408 hdev->major_class = cp->major;
1409 hdev->minor_class = cp->minor;
1410
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001411 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001412 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001413 hdev->dev_class, 3);
Johan Hedberg932f5ff2012-02-22 22:11:32 +02001414 goto unlock;
1415 }
1416
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001417 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->dev_flags)) {
Johan Hedberg7d785252011-12-15 00:47:39 +02001418 hci_dev_unlock(hdev);
1419 cancel_delayed_work_sync(&hdev->service_cache);
1420 hci_dev_lock(hdev);
Johan Hedberg14c0b602011-12-15 00:47:37 +02001421 update_eir(hdev);
Johan Hedberg7d785252011-12-15 00:47:39 +02001422 }
Johan Hedberg14c0b602011-12-15 00:47:37 +02001423
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001424 err = update_class(hdev);
Johan Hedberg90e70452012-02-23 23:09:40 +02001425 if (err < 0)
1426 goto unlock;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001427
Johan Hedberg90e70452012-02-23 23:09:40 +02001428 if (!test_bit(HCI_PENDING_CLASS, &hdev->dev_flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001429 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEV_CLASS, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001430 hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02001431 goto unlock;
1432 }
1433
1434 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DEV_CLASS, hdev, data, len);
Syam Sidhardhan0c01bc42012-04-12 20:33:21 +05301435 if (!cmd)
Johan Hedberg90e70452012-02-23 23:09:40 +02001436 err = -ENOMEM;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001437
Johan Hedbergb5235a62012-02-21 14:32:24 +02001438unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001439 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001440 return err;
1441}
1442
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001443static int load_link_keys(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001444 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001445{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001446 struct mgmt_cp_load_link_keys *cp = data;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001447 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001448 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001449
Marcel Holtmann1f350c82012-03-12 20:31:08 -07001450 key_count = __le16_to_cpu(cp->key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001451
Johan Hedberg86742e12011-11-07 23:13:38 +02001452 expected_len = sizeof(*cp) + key_count *
1453 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001454 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001455 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001456 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001457 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001458 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001459 }
1460
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001461 BT_DBG("%s debug_keys %u key_count %u", hdev->name, cp->debug_keys,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001462 key_count);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001463
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001464 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001465
1466 hci_link_keys_clear(hdev);
1467
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001468 set_bit(HCI_LINK_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001469
1470 if (cp->debug_keys)
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001471 set_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001472 else
Johan Hedberga8b2d5c2012-01-08 23:11:15 +02001473 clear_bit(HCI_DEBUG_KEYS, &hdev->dev_flags);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001474
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001475 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001476 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001477
Johan Hedbergd753fdc2012-02-17 14:06:34 +02001478 hci_add_link_key(hdev, NULL, 0, &key->addr.bdaddr, key->val,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001479 key->type, key->pin_len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001480 }
1481
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001482 cmd_complete(sk, hdev->id, MGMT_OP_LOAD_LINK_KEYS, 0, NULL, 0);
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001483
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001484 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001485
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001486 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001487}
1488
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001489static int device_unpaired(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001490 u8 addr_type, struct sock *skip_sk)
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001491{
1492 struct mgmt_ev_device_unpaired ev;
1493
1494 bacpy(&ev.addr.bdaddr, bdaddr);
1495 ev.addr.type = addr_type;
1496
1497 return mgmt_event(MGMT_EV_DEVICE_UNPAIRED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001498 skip_sk);
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001499}
1500
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001501static int unpair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001502 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001503{
Johan Hedberg124f6e32012-02-09 13:50:12 +02001504 struct mgmt_cp_unpair_device *cp = data;
1505 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001506 struct hci_cp_disconnect dc;
1507 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001508 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001509 int err;
1510
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001511 hci_dev_lock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001512
Johan Hedberga8a1d192011-11-10 15:54:38 +02001513 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02001514 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1515 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001516
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001517 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001518 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001519 MGMT_STATUS_NOT_POWERED, &rp, sizeof(rp));
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001520 goto unlock;
1521 }
1522
Andre Guedes591f47f2012-04-24 21:02:49 -03001523 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg124f6e32012-02-09 13:50:12 +02001524 err = hci_remove_link_key(hdev, &cp->addr.bdaddr);
1525 else
1526 err = hci_remove_ltk(hdev, &cp->addr.bdaddr);
Vinicius Costa Gomesb0dbfb42012-02-02 21:08:03 -03001527
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001528 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001529 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001530 MGMT_STATUS_NOT_PAIRED, &rp, sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001531 goto unlock;
1532 }
1533
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001534 if (cp->disconnect) {
Andre Guedes591f47f2012-04-24 21:02:49 -03001535 if (cp->addr.type == BDADDR_BREDR)
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001536 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001537 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001538 else
1539 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001540 &cp->addr.bdaddr);
Johan Hedberg86a8cfc2012-02-22 22:53:34 +02001541 } else {
1542 conn = NULL;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001543 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001544
Johan Hedberga8a1d192011-11-10 15:54:38 +02001545 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001546 err = cmd_complete(sk, hdev->id, MGMT_OP_UNPAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001547 &rp, sizeof(rp));
Johan Hedbergb1078ad2012-02-09 17:21:16 +02001548 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, sk);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001549 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001550 }
1551
Johan Hedberg124f6e32012-02-09 13:50:12 +02001552 cmd = mgmt_pending_add(sk, MGMT_OP_UNPAIR_DEVICE, hdev, cp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001553 sizeof(*cp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02001554 if (!cmd) {
1555 err = -ENOMEM;
1556 goto unlock;
1557 }
1558
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02001559 dc.handle = cpu_to_le16(conn->handle);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001560 dc.reason = 0x13; /* Remote User Terminated Connection */
1561 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1562 if (err < 0)
1563 mgmt_pending_remove(cmd);
1564
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001565unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001566 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001567 return err;
1568}
1569
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001570static int disconnect(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001571 u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001572{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001573 struct mgmt_cp_disconnect *cp = data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001574 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001575 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001576 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001577 int err;
1578
1579 BT_DBG("");
1580
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001581 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001582
1583 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001584 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001585 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001586 goto failed;
1587 }
1588
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001589 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001590 err = cmd_status(sk, hdev->id, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001591 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001592 goto failed;
1593 }
1594
Andre Guedes591f47f2012-04-24 21:02:49 -03001595 if (cp->addr.type == BDADDR_BREDR)
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03001596 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK,
1597 &cp->addr.bdaddr);
Johan Hedberg88c3df12012-02-09 14:27:38 +02001598 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);
Andre Guedes3701f942012-06-11 18:41:12 -03001614 dc.reason = HCI_ERROR_REMOTE_USER_TERM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001615
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));
Andre Guedes92c4c202012-06-07 19:05:44 -03001670 rp = kmalloc(rp_len, GFP_KERNEL);
Johan Hedberga38528f2011-01-22 06:46:43 +02001671 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,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001816 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
Gustavo Padovan6039aa732012-05-23 04:04:18 -03001824static struct pending_cmd *find_pairing(struct hci_conn *conn)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001825{
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 Hedbergaee9b2182012-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
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301876static void le_connect_complete_cb(struct hci_conn *conn, u8 status)
1877{
1878 struct pending_cmd *cmd;
1879
1880 BT_DBG("status %u", status);
1881
1882 if (!status)
1883 return;
1884
1885 cmd = find_pairing(conn);
1886 if (!cmd)
1887 BT_DBG("Unable to find a pending command");
1888 else
1889 pairing_complete(cmd, mgmt_status(status));
1890}
1891
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001892static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001893 u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001894{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03001895 struct mgmt_cp_pair_device *cp = data;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001896 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001897 struct pending_cmd *cmd;
1898 u8 sec_level, auth_type;
1899 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001900 int err;
1901
1902 BT_DBG("");
1903
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001904 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001905
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001906 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001907 err = cmd_status(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001908 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001909 goto unlock;
1910 }
1911
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001912 sec_level = BT_SECURITY_MEDIUM;
1913 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001914 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001915 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001916 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001917
Andre Guedes591f47f2012-04-24 21:02:49 -03001918 if (cp->addr.type == BDADDR_BREDR)
Andre Guedesb12f62c2012-04-24 21:02:54 -03001919 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr,
1920 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001921 else
Andre Guedesb12f62c2012-04-24 21:02:54 -03001922 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr,
1923 cp->addr.type, sec_level, auth_type);
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001924
Johan Hedberg1425acb2011-11-11 00:07:35 +02001925 memset(&rp, 0, sizeof(rp));
1926 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1927 rp.addr.type = cp->addr.type;
1928
Ville Tervo30e76272011-02-22 16:10:53 -03001929 if (IS_ERR(conn)) {
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001930 int status;
1931
1932 if (PTR_ERR(conn) == -EBUSY)
1933 status = MGMT_STATUS_BUSY;
1934 else
1935 status = MGMT_STATUS_CONNECT_FAILED;
1936
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001937 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Andrzej Kaczmarek489dc482012-05-30 15:39:22 +02001938 status, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001939 sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001940 goto unlock;
1941 }
1942
1943 if (conn->connect_cfm_cb) {
1944 hci_conn_put(conn);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001945 err = cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001946 MGMT_STATUS_BUSY, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001947 goto unlock;
1948 }
1949
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001950 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001951 if (!cmd) {
1952 err = -ENOMEM;
1953 hci_conn_put(conn);
1954 goto unlock;
1955 }
1956
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001957 /* For LE, just connecting isn't a proof that the pairing finished */
Andre Guedes591f47f2012-04-24 21:02:49 -03001958 if (cp->addr.type == BDADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001959 conn->connect_cfm_cb = pairing_complete_cb;
Vishal Agarwal4c47d732012-06-07 20:27:35 +05301960 else
1961 conn->connect_cfm_cb = le_connect_complete_cb;
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001962
Johan Hedberge9a416b2011-02-19 12:05:56 -03001963 conn->security_cfm_cb = pairing_complete_cb;
1964 conn->disconn_cfm_cb = pairing_complete_cb;
1965 conn->io_capability = cp->io_cap;
1966 cmd->user_data = conn;
1967
1968 if (conn->state == BT_CONNECTED &&
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03001969 hci_conn_security(conn, sec_level, auth_type))
Johan Hedberge9a416b2011-02-19 12:05:56 -03001970 pairing_complete(cmd, 0);
1971
1972 err = 0;
1973
1974unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001975 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001976 return err;
1977}
1978
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001979static int cancel_pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
1980 u16 len)
Johan Hedberg28424702012-02-02 04:02:29 +02001981{
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02001982 struct mgmt_addr_info *addr = data;
Johan Hedberg28424702012-02-02 04:02:29 +02001983 struct pending_cmd *cmd;
1984 struct hci_conn *conn;
1985 int err;
1986
1987 BT_DBG("");
1988
Johan Hedberg28424702012-02-02 04:02:29 +02001989 hci_dev_lock(hdev);
1990
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001991 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001992 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03001993 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02001994 goto unlock;
1995 }
1996
Johan Hedberg28424702012-02-02 04:02:29 +02001997 cmd = mgmt_pending_find(MGMT_OP_PAIR_DEVICE, hdev);
1998 if (!cmd) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02001999 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002000 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002001 goto unlock;
2002 }
2003
2004 conn = cmd->user_data;
2005
2006 if (bacmp(&addr->bdaddr, &conn->dst) != 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002007 err = cmd_status(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002008 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg28424702012-02-02 04:02:29 +02002009 goto unlock;
2010 }
2011
2012 pairing_complete(cmd, MGMT_STATUS_CANCELLED);
2013
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002014 err = cmd_complete(sk, hdev->id, MGMT_OP_CANCEL_PAIR_DEVICE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002015 addr, sizeof(*addr));
Johan Hedberg28424702012-02-02 04:02:29 +02002016unlock:
2017 hci_dev_unlock(hdev);
Johan Hedberg28424702012-02-02 04:02:29 +02002018 return err;
2019}
2020
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002021static int user_pairing_resp(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002022 bdaddr_t *bdaddr, u8 type, u16 mgmt_op,
2023 u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03002024{
Johan Hedberga5c29682011-02-19 12:05:57 -03002025 struct pending_cmd *cmd;
Brian Gix0df4c182011-11-16 13:53:13 -08002026 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03002027 int err;
2028
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002029 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02002030
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002031 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002032 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002033 MGMT_STATUS_NOT_POWERED);
Brian Gix0df4c182011-11-16 13:53:13 -08002034 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002035 }
2036
Andre Guedes591f47f2012-04-24 21:02:49 -03002037 if (type == BDADDR_BREDR)
Johan Hedberg272d90d2012-02-09 15:26:12 +02002038 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
2039 else
Brian Gix47c15e22011-11-16 13:53:14 -08002040 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
Brian Gix47c15e22011-11-16 13:53:14 -08002041
Johan Hedberg272d90d2012-02-09 15:26:12 +02002042 if (!conn) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002043 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002044 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg272d90d2012-02-09 15:26:12 +02002045 goto done;
2046 }
2047
Andre Guedes591f47f2012-04-24 21:02:49 -03002048 if (type == BDADDR_LE_PUBLIC || type == BDADDR_LE_RANDOM) {
Brian Gix47c15e22011-11-16 13:53:14 -08002049 /* Continue with pairing via SMP */
Brian Gix5fe57d92011-12-21 16:12:13 -08002050 err = smp_user_confirm_reply(conn, mgmt_op, passkey);
Brian Gix47c15e22011-11-16 13:53:14 -08002051
Brian Gix5fe57d92011-12-21 16:12:13 -08002052 if (!err)
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002053 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002054 MGMT_STATUS_SUCCESS);
Brian Gix5fe57d92011-12-21 16:12:13 -08002055 else
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002056 err = cmd_status(sk, hdev->id, mgmt_op,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002057 MGMT_STATUS_FAILED);
Brian Gix5fe57d92011-12-21 16:12:13 -08002058
Brian Gix47c15e22011-11-16 13:53:14 -08002059 goto done;
2060 }
2061
Brian Gix0df4c182011-11-16 13:53:13 -08002062 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03002063 if (!cmd) {
2064 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08002065 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03002066 }
2067
Brian Gix0df4c182011-11-16 13:53:13 -08002068 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08002069 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
2070 struct hci_cp_user_passkey_reply cp;
2071
2072 bacpy(&cp.bdaddr, bdaddr);
2073 cp.passkey = passkey;
2074 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
2075 } else
2076 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
2077
Johan Hedberga664b5b2011-02-19 12:06:02 -03002078 if (err < 0)
2079 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002080
Brian Gix0df4c182011-11-16 13:53:13 -08002081done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002082 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002083 return err;
2084}
2085
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002086static int user_confirm_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2087 u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002088{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002089 struct mgmt_cp_user_confirm_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002090
2091 BT_DBG("");
2092
2093 if (len != sizeof(*cp))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002094 return cmd_status(sk, hdev->id, MGMT_OP_USER_CONFIRM_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002095 MGMT_STATUS_INVALID_PARAMS);
Brian Gix0df4c182011-11-16 13:53:13 -08002096
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002097 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002098 MGMT_OP_USER_CONFIRM_REPLY,
2099 HCI_OP_USER_CONFIRM_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002100}
2101
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002102static int user_confirm_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002103 void *data, u16 len)
Brian Gix0df4c182011-11-16 13:53:13 -08002104{
Johan Hedbergc9c26592011-12-15 00:47:41 +02002105 struct mgmt_cp_user_confirm_neg_reply *cp = data;
Brian Gix0df4c182011-11-16 13:53:13 -08002106
2107 BT_DBG("");
2108
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002109 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002110 MGMT_OP_USER_CONFIRM_NEG_REPLY,
2111 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
Brian Gix0df4c182011-11-16 13:53:13 -08002112}
2113
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002114static int user_passkey_reply(struct sock *sk, struct hci_dev *hdev, void *data,
2115 u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002116{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002117 struct mgmt_cp_user_passkey_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002118
2119 BT_DBG("");
2120
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002121 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002122 MGMT_OP_USER_PASSKEY_REPLY,
2123 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
Brian Gix604086b2011-11-23 08:28:33 -08002124}
2125
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002126static int user_passkey_neg_reply(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002127 void *data, u16 len)
Brian Gix604086b2011-11-23 08:28:33 -08002128{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002129 struct mgmt_cp_user_passkey_neg_reply *cp = data;
Brian Gix604086b2011-11-23 08:28:33 -08002130
2131 BT_DBG("");
2132
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002133 return user_pairing_resp(sk, hdev, &cp->addr.bdaddr, cp->addr.type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002134 MGMT_OP_USER_PASSKEY_NEG_REPLY,
2135 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
Brian Gix604086b2011-11-23 08:28:33 -08002136}
2137
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002138static int update_name(struct hci_dev *hdev, const char *name)
2139{
2140 struct hci_cp_write_local_name cp;
2141
2142 memcpy(cp.name, name, sizeof(cp.name));
2143
2144 return hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(cp), &cp);
2145}
2146
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002147static int set_local_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002148 u16 len)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002149{
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002150 struct mgmt_cp_set_local_name *cp = data;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002151 struct pending_cmd *cmd;
2152 int err;
2153
2154 BT_DBG("");
2155
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002156 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002157
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002158 memcpy(hdev->short_name, cp->short_name, sizeof(hdev->short_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002159
Johan Hedbergb5235a62012-02-21 14:32:24 +02002160 if (!hdev_is_powered(hdev)) {
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002161 memcpy(hdev->dev_name, cp->name, sizeof(hdev->dev_name));
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002162
2163 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002164 data, len);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002165 if (err < 0)
2166 goto failed;
2167
2168 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, data, len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002169 sk);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002170
Johan Hedbergb5235a62012-02-21 14:32:24 +02002171 goto failed;
2172 }
2173
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02002174 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002175 if (!cmd) {
2176 err = -ENOMEM;
2177 goto failed;
2178 }
2179
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002180 err = update_name(hdev, cp->name);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002181 if (err < 0)
2182 mgmt_pending_remove(cmd);
2183
2184failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002185 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002186 return err;
2187}
2188
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002189static int read_local_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002190 void *data, u16 data_len)
Szymon Jancc35938b2011-03-22 13:12:21 +01002191{
Szymon Jancc35938b2011-03-22 13:12:21 +01002192 struct pending_cmd *cmd;
2193 int err;
2194
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002195 BT_DBG("%s", hdev->name);
Szymon Jancc35938b2011-03-22 13:12:21 +01002196
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002197 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002198
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002199 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002200 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002201 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002202 goto unlock;
2203 }
2204
2205 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002206 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002207 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01002208 goto unlock;
2209 }
2210
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002211 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002212 err = cmd_status(sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002213 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01002214 goto unlock;
2215 }
2216
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002217 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01002218 if (!cmd) {
2219 err = -ENOMEM;
2220 goto unlock;
2221 }
2222
2223 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
2224 if (err < 0)
2225 mgmt_pending_remove(cmd);
2226
2227unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002228 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002229 return err;
2230}
2231
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002232static int add_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002233 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002234{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002235 struct mgmt_cp_add_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002236 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002237 int err;
2238
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002239 BT_DBG("%s ", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002240
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002241 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002242
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002243 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002244 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002245 MGMT_STATUS_NOT_POWERED, &cp->addr,
2246 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002247 goto unlock;
2248 }
2249
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002250 err = hci_add_remote_oob_data(hdev, &cp->addr.bdaddr, cp->hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002251 cp->randomizer);
Szymon Janc2763eda2011-03-22 13:12:22 +01002252 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002253 status = MGMT_STATUS_FAILED;
Szymon Janc2763eda2011-03-22 13:12:22 +01002254 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002255 status = 0;
2256
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002257 err = cmd_complete(sk, hdev->id, MGMT_OP_ADD_REMOTE_OOB_DATA, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002258 &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002259
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002260unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002261 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002262 return err;
2263}
2264
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002265static int remove_remote_oob_data(struct sock *sk, struct hci_dev *hdev,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002266 void *data, u16 len)
Szymon Janc2763eda2011-03-22 13:12:22 +01002267{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002268 struct mgmt_cp_remove_remote_oob_data *cp = data;
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002269 u8 status;
Szymon Janc2763eda2011-03-22 13:12:22 +01002270 int err;
2271
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002272 BT_DBG("%s", hdev->name);
Szymon Janc2763eda2011-03-22 13:12:22 +01002273
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002274 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002275
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002276 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002277 err = cmd_complete(sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002278 MGMT_OP_REMOVE_REMOTE_OOB_DATA,
2279 MGMT_STATUS_NOT_POWERED, &cp->addr,
2280 sizeof(cp->addr));
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002281 goto unlock;
2282 }
2283
Johan Hedberg664ce4c2012-02-09 15:44:09 +02002284 err = hci_remove_remote_oob_data(hdev, &cp->addr.bdaddr);
Szymon Janc2763eda2011-03-22 13:12:22 +01002285 if (err < 0)
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002286 status = MGMT_STATUS_INVALID_PARAMS;
Szymon Janc2763eda2011-03-22 13:12:22 +01002287 else
Johan Hedbergbf1e3542012-02-19 13:16:14 +02002288 status = 0;
2289
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002290 err = cmd_complete(sk, hdev->id, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002291 status, &cp->addr, sizeof(cp->addr));
Szymon Janc2763eda2011-03-22 13:12:22 +01002292
Johan Hedberg5f97c1d2012-02-22 22:41:18 +02002293unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002294 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01002295 return err;
2296}
2297
Andre Guedes5e0452c2012-02-17 20:39:38 -03002298int mgmt_interleaved_discovery(struct hci_dev *hdev)
2299{
2300 int err;
2301
2302 BT_DBG("%s", hdev->name);
2303
2304 hci_dev_lock(hdev);
2305
2306 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR_LE);
2307 if (err < 0)
2308 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2309
2310 hci_dev_unlock(hdev);
2311
2312 return err;
2313}
2314
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002315static int start_discovery(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002316 void *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002317{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002318 struct mgmt_cp_start_discovery *cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002319 struct pending_cmd *cmd;
Johan Hedberg14a53662011-04-27 10:29:56 -04002320 int err;
2321
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002322 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002323
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002324 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002325
Johan Hedberg4b34ee782012-02-21 14:13:02 +02002326 if (!hdev_is_powered(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002327 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002328 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02002329 goto failed;
2330 }
2331
Andre Guedes642be6c2012-03-21 00:03:37 -03002332 if (test_bit(HCI_PERIODIC_INQ, &hdev->dev_flags)) {
2333 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
2334 MGMT_STATUS_BUSY);
2335 goto failed;
2336 }
2337
Johan Hedbergff9ef572012-01-04 14:23:45 +02002338 if (hdev->discovery.state != DISCOVERY_STOPPED) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002339 err = cmd_status(sk, hdev->id, MGMT_OP_START_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002340 MGMT_STATUS_BUSY);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002341 goto failed;
2342 }
2343
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002344 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002345 if (!cmd) {
2346 err = -ENOMEM;
2347 goto failed;
2348 }
2349
Andre Guedes4aab14e2012-02-17 20:39:36 -03002350 hdev->discovery.type = cp->type;
2351
2352 switch (hdev->discovery.type) {
Andre Guedesf39799f2012-02-17 20:39:35 -03002353 case DISCOV_TYPE_BREDR:
Andre Guedes8b901292012-02-23 18:09:27 -03002354 if (lmp_bredr_capable(hdev))
2355 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
2356 else
2357 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002358 break;
2359
2360 case DISCOV_TYPE_LE:
Andre Guedes8b901292012-02-23 18:09:27 -03002361 if (lmp_host_le_capable(hdev))
2362 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002363 LE_SCAN_WIN, LE_SCAN_TIMEOUT_LE_ONLY);
Andre Guedes8b901292012-02-23 18:09:27 -03002364 else
2365 err = -ENOTSUPP;
Andre Guedesf39799f2012-02-17 20:39:35 -03002366 break;
2367
Andre Guedes5e0452c2012-02-17 20:39:38 -03002368 case DISCOV_TYPE_INTERLEAVED:
Andre Guedes426c1892012-02-24 11:41:04 -03002369 if (lmp_host_le_capable(hdev) && lmp_bredr_capable(hdev))
2370 err = hci_le_scan(hdev, LE_SCAN_TYPE, LE_SCAN_INT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002371 LE_SCAN_WIN,
2372 LE_SCAN_TIMEOUT_BREDR_LE);
Andre Guedes426c1892012-02-24 11:41:04 -03002373 else
2374 err = -ENOTSUPP;
Andre Guedes5e0452c2012-02-17 20:39:38 -03002375 break;
2376
Andre Guedesf39799f2012-02-17 20:39:35 -03002377 default:
Andre Guedes3fd24152012-02-03 17:48:01 -03002378 err = -EINVAL;
Andre Guedesf39799f2012-02-17 20:39:35 -03002379 }
Andre Guedes3fd24152012-02-03 17:48:01 -03002380
Johan Hedberg14a53662011-04-27 10:29:56 -04002381 if (err < 0)
2382 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002383 else
2384 hci_discovery_set_state(hdev, DISCOVERY_STARTING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002385
2386failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002387 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002388 return err;
2389}
2390
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002391static int stop_discovery(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002392 u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04002393{
Johan Hedbergd9306502012-02-20 23:25:18 +02002394 struct mgmt_cp_stop_discovery *mgmt_cp = data;
Johan Hedberg14a53662011-04-27 10:29:56 -04002395 struct pending_cmd *cmd;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002396 struct hci_cp_remote_name_req_cancel cp;
2397 struct inquiry_entry *e;
Johan Hedberg14a53662011-04-27 10:29:56 -04002398 int err;
2399
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002400 BT_DBG("%s", hdev->name);
Johan Hedberg14a53662011-04-27 10:29:56 -04002401
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002402 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002403
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002404 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002405 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002406 MGMT_STATUS_REJECTED, &mgmt_cp->type,
2407 sizeof(mgmt_cp->type));
Johan Hedbergd9306502012-02-20 23:25:18 +02002408 goto unlock;
2409 }
2410
2411 if (hdev->discovery.type != mgmt_cp->type) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002412 err = cmd_complete(sk, hdev->id, MGMT_OP_STOP_DISCOVERY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002413 MGMT_STATUS_INVALID_PARAMS, &mgmt_cp->type,
2414 sizeof(mgmt_cp->type));
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002415 goto unlock;
Johan Hedbergff9ef572012-01-04 14:23:45 +02002416 }
2417
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002418 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04002419 if (!cmd) {
2420 err = -ENOMEM;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002421 goto unlock;
Johan Hedberg14a53662011-04-27 10:29:56 -04002422 }
2423
Andre Guedese0d9727e2012-03-20 15:15:36 -03002424 switch (hdev->discovery.state) {
2425 case DISCOVERY_FINDING:
Andre Guedesc9ecc482012-03-15 16:52:08 -03002426 if (test_bit(HCI_INQUIRY, &hdev->flags))
2427 err = hci_cancel_inquiry(hdev);
2428 else
2429 err = hci_cancel_le_scan(hdev);
2430
Andre Guedese0d9727e2012-03-20 15:15:36 -03002431 break;
2432
2433 case DISCOVERY_RESOLVING:
2434 e = hci_inquiry_cache_lookup_resolve(hdev, BDADDR_ANY,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002435 NAME_PENDING);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002436 if (!e) {
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002437 mgmt_pending_remove(cmd);
Andre Guedese0d9727e2012-03-20 15:15:36 -03002438 err = cmd_complete(sk, hdev->id,
2439 MGMT_OP_STOP_DISCOVERY, 0,
2440 &mgmt_cp->type,
2441 sizeof(mgmt_cp->type));
2442 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
2443 goto unlock;
2444 }
2445
2446 bacpy(&cp.bdaddr, &e->data.bdaddr);
2447 err = hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ_CANCEL,
2448 sizeof(cp), &cp);
2449
2450 break;
2451
2452 default:
2453 BT_DBG("unknown discovery state %u", hdev->discovery.state);
2454 err = -EFAULT;
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002455 }
2456
Johan Hedberg14a53662011-04-27 10:29:56 -04002457 if (err < 0)
2458 mgmt_pending_remove(cmd);
Johan Hedbergff9ef572012-01-04 14:23:45 +02002459 else
2460 hci_discovery_set_state(hdev, DISCOVERY_STOPPING);
Johan Hedberg14a53662011-04-27 10:29:56 -04002461
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002462unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002463 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04002464 return err;
2465}
2466
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002467static int confirm_name(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002468 u16 len)
Johan Hedberg561aafb2012-01-04 13:31:59 +02002469{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002470 struct mgmt_cp_confirm_name *cp = data;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002471 struct inquiry_entry *e;
Johan Hedberg561aafb2012-01-04 13:31:59 +02002472 int err;
2473
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002474 BT_DBG("%s", hdev->name);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002475
Johan Hedberg561aafb2012-01-04 13:31:59 +02002476 hci_dev_lock(hdev);
2477
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002478 if (!hci_discovery_active(hdev)) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002479 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002480 MGMT_STATUS_FAILED);
Johan Hedberg30dc78e2012-01-04 15:44:20 +02002481 goto failed;
2482 }
2483
Johan Hedberga198e7b2012-02-17 14:27:06 +02002484 e = hci_inquiry_cache_lookup_unknown(hdev, &cp->addr.bdaddr);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002485 if (!e) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002486 err = cmd_status(sk, hdev->id, MGMT_OP_CONFIRM_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002487 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002488 goto failed;
2489 }
2490
2491 if (cp->name_known) {
2492 e->name_state = NAME_KNOWN;
2493 list_del(&e->list);
2494 } else {
2495 e->name_state = NAME_NEEDED;
Johan Hedberga3d4e202012-01-09 00:53:02 +02002496 hci_inquiry_cache_update_resolve(hdev, e);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002497 }
2498
2499 err = 0;
2500
2501failed:
2502 hci_dev_unlock(hdev);
Johan Hedberg561aafb2012-01-04 13:31:59 +02002503 return err;
2504}
2505
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002506static int block_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_block_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_add(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_FAILED;
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_BLOCK_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
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002531static int unblock_device(struct sock *sk, struct hci_dev *hdev, void *data,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002532 u16 len)
Antti Julku7fbec222011-06-15 12:01:15 +03002533{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002534 struct mgmt_cp_unblock_device *cp = data;
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002535 u8 status;
Antti Julku7fbec222011-06-15 12:01:15 +03002536 int err;
2537
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002538 BT_DBG("%s", hdev->name);
Antti Julku7fbec222011-06-15 12:01:15 +03002539
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002540 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002541
Johan Hedberg88c1fe42012-02-09 15:56:11 +02002542 err = hci_blacklist_del(hdev, &cp->addr.bdaddr, cp->addr.type);
Antti Julku7fbec222011-06-15 12:01:15 +03002543 if (err < 0)
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002544 status = MGMT_STATUS_INVALID_PARAMS;
Antti Julku7fbec222011-06-15 12:01:15 +03002545 else
Johan Hedbergf0eeea82012-02-19 12:58:54 +02002546 status = 0;
2547
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002548 err = cmd_complete(sk, hdev->id, MGMT_OP_UNBLOCK_DEVICE, status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002549 &cp->addr, sizeof(cp->addr));
Antti Julku5e762442011-08-25 16:48:02 +03002550
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002551 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002552
2553 return err;
2554}
2555
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002556static int set_device_id(struct sock *sk, struct hci_dev *hdev, void *data,
2557 u16 len)
2558{
2559 struct mgmt_cp_set_device_id *cp = data;
2560 int err;
Szymon Jancc72d4b82012-03-16 16:02:57 +01002561 __u16 source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002562
2563 BT_DBG("%s", hdev->name);
2564
Szymon Jancc72d4b82012-03-16 16:02:57 +01002565 source = __le16_to_cpu(cp->source);
2566
2567 if (source > 0x0002)
2568 return cmd_status(sk, hdev->id, MGMT_OP_SET_DEVICE_ID,
2569 MGMT_STATUS_INVALID_PARAMS);
2570
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002571 hci_dev_lock(hdev);
2572
Szymon Jancc72d4b82012-03-16 16:02:57 +01002573 hdev->devid_source = source;
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002574 hdev->devid_vendor = __le16_to_cpu(cp->vendor);
2575 hdev->devid_product = __le16_to_cpu(cp->product);
2576 hdev->devid_version = __le16_to_cpu(cp->version);
2577
2578 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_DEVICE_ID, 0, NULL, 0);
2579
2580 update_eir(hdev);
2581
2582 hci_dev_unlock(hdev);
2583
2584 return err;
2585}
2586
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002587static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002588 void *data, u16 len)
Antti Julkuf6422ec2011-06-22 13:11:56 +03002589{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002590 struct mgmt_mode *cp = data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002591 struct hci_cp_write_page_scan_activity acp;
2592 u8 type;
2593 int err;
2594
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002595 BT_DBG("%s", hdev->name);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002596
Johan Hedberg5400c042012-02-21 16:40:33 +02002597 if (!hdev_is_powered(hdev))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002598 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002599 MGMT_STATUS_NOT_POWERED);
Johan Hedberg5400c042012-02-21 16:40:33 +02002600
2601 if (!test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002602 return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002603 MGMT_STATUS_REJECTED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002604
2605 hci_dev_lock(hdev);
2606
Johan Hedbergf7c68692011-12-15 00:47:36 +02002607 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002608 type = PAGE_SCAN_TYPE_INTERLACED;
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002609
2610 /* 22.5 msec page scan interval */
2611 acp.interval = __constant_cpu_to_le16(0x0024);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002612 } else {
2613 type = PAGE_SCAN_TYPE_STANDARD; /* default */
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002614
2615 /* default 1.28 sec page scan */
2616 acp.interval = __constant_cpu_to_le16(0x0800);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002617 }
2618
Andrei Emeltchenko76ec9de2012-03-12 12:13:11 +02002619 /* default 11.25 msec page scan window */
2620 acp.window = __constant_cpu_to_le16(0x0012);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002621
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002622 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY, sizeof(acp),
2623 &acp);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002624 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002625 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002626 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002627 goto done;
2628 }
2629
2630 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2631 if (err < 0) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002632 err = cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002633 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002634 goto done;
2635 }
2636
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002637 err = cmd_complete(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE, 0,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002638 NULL, 0);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002639done:
2640 hci_dev_unlock(hdev);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002641 return err;
2642}
2643
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002644static int load_long_term_keys(struct sock *sk, struct hci_dev *hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002645 void *cp_data, u16 len)
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002646{
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002647 struct mgmt_cp_load_long_term_keys *cp = cp_data;
2648 u16 key_count, expected_len;
2649 int i;
2650
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002651 key_count = __le16_to_cpu(cp->key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002652
2653 expected_len = sizeof(*cp) + key_count *
2654 sizeof(struct mgmt_ltk_info);
2655 if (expected_len != len) {
2656 BT_ERR("load_keys: expected %u bytes, got %u bytes",
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002657 len, expected_len);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002658 return cmd_status(sk, hdev->id, MGMT_OP_LOAD_LONG_TERM_KEYS,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002659 EINVAL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002660 }
2661
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002662 BT_DBG("%s key_count %u", hdev->name, key_count);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002663
2664 hci_dev_lock(hdev);
2665
2666 hci_smp_ltks_clear(hdev);
2667
2668 for (i = 0; i < key_count; i++) {
2669 struct mgmt_ltk_info *key = &cp->keys[i];
2670 u8 type;
2671
2672 if (key->master)
2673 type = HCI_SMP_LTK;
2674 else
2675 type = HCI_SMP_LTK_SLAVE;
2676
Hemant Gupta4596fde2012-04-16 14:57:40 +05302677 hci_add_ltk(hdev, &key->addr.bdaddr,
Andre Guedes378b5b72012-04-24 21:02:51 -03002678 bdaddr_to_le(key->addr.type),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002679 type, 0, key->authenticated, key->val,
2680 key->enc_size, key->ediv, key->rand);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002681 }
2682
2683 hci_dev_unlock(hdev);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002684
2685 return 0;
2686}
2687
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002688static const struct mgmt_handler {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002689 int (*func) (struct sock *sk, struct hci_dev *hdev, void *data,
2690 u16 data_len);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002691 bool var_len;
2692 size_t data_len;
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002693} mgmt_handlers[] = {
2694 { NULL }, /* 0x0000 (no command) */
Johan Hedbergbe22b542012-03-01 22:24:41 +02002695 { read_version, false, MGMT_READ_VERSION_SIZE },
2696 { read_commands, false, MGMT_READ_COMMANDS_SIZE },
2697 { read_index_list, false, MGMT_READ_INDEX_LIST_SIZE },
2698 { read_controller_info, false, MGMT_READ_INFO_SIZE },
2699 { set_powered, false, MGMT_SETTING_SIZE },
2700 { set_discoverable, false, MGMT_SET_DISCOVERABLE_SIZE },
2701 { set_connectable, false, MGMT_SETTING_SIZE },
2702 { set_fast_connectable, false, MGMT_SETTING_SIZE },
2703 { set_pairable, false, MGMT_SETTING_SIZE },
2704 { set_link_security, false, MGMT_SETTING_SIZE },
2705 { set_ssp, false, MGMT_SETTING_SIZE },
2706 { set_hs, false, MGMT_SETTING_SIZE },
2707 { set_le, false, MGMT_SETTING_SIZE },
2708 { set_dev_class, false, MGMT_SET_DEV_CLASS_SIZE },
2709 { set_local_name, false, MGMT_SET_LOCAL_NAME_SIZE },
2710 { add_uuid, false, MGMT_ADD_UUID_SIZE },
2711 { remove_uuid, false, MGMT_REMOVE_UUID_SIZE },
2712 { load_link_keys, true, MGMT_LOAD_LINK_KEYS_SIZE },
2713 { load_long_term_keys, true, MGMT_LOAD_LONG_TERM_KEYS_SIZE },
2714 { disconnect, false, MGMT_DISCONNECT_SIZE },
2715 { get_connections, false, MGMT_GET_CONNECTIONS_SIZE },
2716 { pin_code_reply, false, MGMT_PIN_CODE_REPLY_SIZE },
2717 { pin_code_neg_reply, false, MGMT_PIN_CODE_NEG_REPLY_SIZE },
2718 { set_io_capability, false, MGMT_SET_IO_CAPABILITY_SIZE },
2719 { pair_device, false, MGMT_PAIR_DEVICE_SIZE },
2720 { cancel_pair_device, false, MGMT_CANCEL_PAIR_DEVICE_SIZE },
2721 { unpair_device, false, MGMT_UNPAIR_DEVICE_SIZE },
2722 { user_confirm_reply, false, MGMT_USER_CONFIRM_REPLY_SIZE },
2723 { user_confirm_neg_reply, false, MGMT_USER_CONFIRM_NEG_REPLY_SIZE },
2724 { user_passkey_reply, false, MGMT_USER_PASSKEY_REPLY_SIZE },
2725 { user_passkey_neg_reply, false, MGMT_USER_PASSKEY_NEG_REPLY_SIZE },
2726 { read_local_oob_data, false, MGMT_READ_LOCAL_OOB_DATA_SIZE },
2727 { add_remote_oob_data, false, MGMT_ADD_REMOTE_OOB_DATA_SIZE },
2728 { remove_remote_oob_data, false, MGMT_REMOVE_REMOTE_OOB_DATA_SIZE },
2729 { start_discovery, false, MGMT_START_DISCOVERY_SIZE },
2730 { stop_discovery, false, MGMT_STOP_DISCOVERY_SIZE },
2731 { confirm_name, false, MGMT_CONFIRM_NAME_SIZE },
2732 { block_device, false, MGMT_BLOCK_DEVICE_SIZE },
2733 { unblock_device, false, MGMT_UNBLOCK_DEVICE_SIZE },
Marcel Holtmanncdbaccc2012-03-11 20:00:29 -07002734 { set_device_id, false, MGMT_SET_DEVICE_ID_SIZE },
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002735};
2736
2737
Johan Hedberg03811012010-12-08 00:21:06 +02002738int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2739{
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002740 void *buf;
2741 u8 *cp;
Johan Hedberg03811012010-12-08 00:21:06 +02002742 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002743 u16 opcode, index, len;
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002744 struct hci_dev *hdev = NULL;
Andrei Emeltchenko2e3c35e2012-03-14 18:54:15 +02002745 const struct mgmt_handler *handler;
Johan Hedberg03811012010-12-08 00:21:06 +02002746 int err;
2747
2748 BT_DBG("got %zu bytes", msglen);
2749
2750 if (msglen < sizeof(*hdr))
2751 return -EINVAL;
2752
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002753 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002754 if (!buf)
2755 return -ENOMEM;
2756
2757 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2758 err = -EFAULT;
2759 goto done;
2760 }
2761
Vinicius Costa Gomes650f7262012-02-02 21:07:59 -03002762 hdr = buf;
Marcel Holtmann1f350c82012-03-12 20:31:08 -07002763 opcode = __le16_to_cpu(hdr->opcode);
2764 index = __le16_to_cpu(hdr->index);
2765 len = __le16_to_cpu(hdr->len);
Johan Hedberg03811012010-12-08 00:21:06 +02002766
2767 if (len != msglen - sizeof(*hdr)) {
2768 err = -EINVAL;
2769 goto done;
2770 }
2771
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002772 if (index != MGMT_INDEX_NONE) {
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002773 hdev = hci_dev_get(index);
2774 if (!hdev) {
2775 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002776 MGMT_STATUS_INVALID_INDEX);
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002777 goto done;
2778 }
2779 }
2780
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002781 if (opcode >= ARRAY_SIZE(mgmt_handlers) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002782 mgmt_handlers[opcode].func == NULL) {
Johan Hedberg03811012010-12-08 00:21:06 +02002783 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002784 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002785 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002786 goto done;
Johan Hedberg03811012010-12-08 00:21:06 +02002787 }
2788
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002789 if ((hdev && opcode < MGMT_OP_READ_INFO) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002790 (!hdev && opcode >= MGMT_OP_READ_INFO)) {
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002791 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002792 MGMT_STATUS_INVALID_INDEX);
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002793 goto done;
2794 }
2795
Johan Hedbergbe22b542012-03-01 22:24:41 +02002796 handler = &mgmt_handlers[opcode];
2797
2798 if ((handler->var_len && len < handler->data_len) ||
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03002799 (!handler->var_len && len != handler->data_len)) {
Johan Hedbergbe22b542012-03-01 22:24:41 +02002800 err = cmd_status(sk, index, opcode,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002801 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergbe22b542012-03-01 22:24:41 +02002802 goto done;
2803 }
2804
Johan Hedberg0f4e68c2012-02-28 17:18:30 +02002805 if (hdev)
2806 mgmt_init_hdev(sk, hdev);
2807
2808 cp = buf + sizeof(*hdr);
2809
Johan Hedbergbe22b542012-03-01 22:24:41 +02002810 err = handler->func(sk, hdev, cp, len);
Johan Hedberge41d8b42010-12-13 21:07:03 +02002811 if (err < 0)
2812 goto done;
2813
Johan Hedberg03811012010-12-08 00:21:06 +02002814 err = msglen;
2815
2816done:
Johan Hedbergbdb6d972012-02-28 06:13:32 +02002817 if (hdev)
2818 hci_dev_put(hdev);
2819
Johan Hedberg03811012010-12-08 00:21:06 +02002820 kfree(buf);
2821 return err;
2822}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002823
Johan Hedbergb24752f2011-11-03 14:40:33 +02002824static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2825{
2826 u8 *status = data;
2827
2828 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2829 mgmt_pending_remove(cmd);
2830}
2831
Johan Hedberg744cf192011-11-08 20:40:14 +02002832int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002833{
Johan Hedberg744cf192011-11-08 20:40:14 +02002834 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002835}
2836
Johan Hedberg744cf192011-11-08 20:40:14 +02002837int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002838{
Johan Hedberg5f159032012-03-02 03:13:19 +02002839 u8 status = MGMT_STATUS_INVALID_INDEX;
Johan Hedbergb24752f2011-11-03 14:40:33 +02002840
Johan Hedberg744cf192011-11-08 20:40:14 +02002841 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002842
Johan Hedberg744cf192011-11-08 20:40:14 +02002843 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002844}
2845
Johan Hedberg73f22f62010-12-29 16:00:25 +02002846struct cmd_lookup {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002847 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002848 struct hci_dev *hdev;
Johan Hedberg90e70452012-02-23 23:09:40 +02002849 u8 mgmt_status;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002850};
2851
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002852static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002853{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002854 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002855
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002856 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002857
2858 list_del(&cmd->list);
2859
2860 if (match->sk == NULL) {
2861 match->sk = cmd->sk;
2862 sock_hold(match->sk);
2863 }
2864
2865 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002866}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002867
Johan Hedberg744cf192011-11-08 20:40:14 +02002868int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002869{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002870 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002871 int err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002872
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002873 if (!test_bit(HCI_MGMT, &hdev->dev_flags))
2874 return 0;
2875
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002876 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002877
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002878 if (powered) {
2879 u8 scan = 0;
2880
2881 if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2882 scan |= SCAN_PAGE;
2883 if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2884 scan |= SCAN_INQUIRY;
2885
2886 if (scan)
2887 hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002888
2889 update_class(hdev);
Johan Hedberg2b4bf392012-03-03 00:19:06 +02002890 update_name(hdev, hdev->dev_name);
Johan Hedberg504c8dc2012-02-23 13:30:41 +02002891 update_eir(hdev);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002892 } else {
Johan Hedbergd4f68522012-03-02 03:07:07 +02002893 u8 status = MGMT_STATUS_NOT_POWERED;
Johan Hedberg744cf192011-11-08 20:40:14 +02002894 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002895 }
2896
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002897 err = new_settings(hdev, match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002898
2899 if (match.sk)
2900 sock_put(match.sk);
2901
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002902 return err;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002903}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002904
Johan Hedberg744cf192011-11-08 20:40:14 +02002905int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002906{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002907 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002908 bool changed = false;
2909 int err = 0;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002910
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002911 if (discoverable) {
2912 if (!test_and_set_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2913 changed = true;
2914 } else {
2915 if (test_and_clear_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
2916 changed = true;
2917 }
Johan Hedberg73f22f62010-12-29 16:00:25 +02002918
Johan Hedberged9b5f22012-02-21 20:47:06 +02002919 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002920 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002921
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002922 if (changed)
2923 err = new_settings(hdev, match.sk);
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002924
Johan Hedberg73f22f62010-12-29 16:00:25 +02002925 if (match.sk)
2926 sock_put(match.sk);
2927
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002928 return err;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002929}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002930
Johan Hedberg744cf192011-11-08 20:40:14 +02002931int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002932{
Johan Hedberg76a7f3a2012-02-17 00:34:40 +02002933 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002934 bool changed = false;
2935 int err = 0;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002936
Johan Hedberg5e5282b2012-02-21 16:01:30 +02002937 if (connectable) {
2938 if (!test_and_set_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2939 changed = true;
2940 } else {
2941 if (test_and_clear_bit(HCI_CONNECTABLE, &hdev->dev_flags))
2942 changed = true;
2943 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002944
Johan Hedberged9b5f22012-02-21 20:47:06 +02002945 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002946 &match);
Johan Hedberged9b5f22012-02-21 20:47:06 +02002947
Johan Hedbergbeadb2b2012-02-21 16:55:31 +02002948 if (changed)
2949 err = new_settings(hdev, match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002950
2951 if (match.sk)
2952 sock_put(match.sk);
2953
Johan Hedberg7bb895d2012-02-17 01:20:00 +02002954 return err;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002955}
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002956
Johan Hedberg744cf192011-11-08 20:40:14 +02002957int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002958{
Johan Hedbergca69b792011-11-11 18:10:00 +02002959 u8 mgmt_err = mgmt_status(status);
2960
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002961 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002962 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002963 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002964
2965 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002966 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03002967 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002968
2969 return 0;
2970}
2971
Cristian Chilipirea53168e52012-05-09 08:44:52 +03002972int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2973 bool persistent)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002974{
Johan Hedberg86742e12011-11-07 23:13:38 +02002975 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002976
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002977 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002978
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002979 ev.store_hint = persistent;
Johan Hedbergd753fdc2012-02-17 14:06:34 +02002980 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03002981 ev.key.addr.type = BDADDR_BREDR;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002982 ev.key.type = key->type;
Andrei Emeltchenko9b3b4462012-05-23 11:31:20 +03002983 memcpy(ev.key.val, key->val, HCI_LINK_KEY_SIZE);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002984 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002985
Johan Hedberg744cf192011-11-08 20:40:14 +02002986 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002987}
Johan Hedbergf7520542011-01-20 12:34:39 +02002988
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002989int mgmt_new_ltk(struct hci_dev *hdev, struct smp_ltk *key, u8 persistent)
2990{
2991 struct mgmt_ev_new_long_term_key ev;
2992
2993 memset(&ev, 0, sizeof(ev));
2994
2995 ev.store_hint = persistent;
2996 bacpy(&ev.key.addr.bdaddr, &key->bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03002997 ev.key.addr.type = link_to_bdaddr(LE_LINK, key->bdaddr_type);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03002998 ev.key.authenticated = key->authenticated;
2999 ev.key.enc_size = key->enc_size;
3000 ev.key.ediv = key->ediv;
3001
3002 if (key->type == HCI_SMP_LTK)
3003 ev.key.master = 1;
3004
3005 memcpy(ev.key.rand, key->rand, sizeof(key->rand));
3006 memcpy(ev.key.val, key->val, sizeof(key->val));
3007
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003008 return mgmt_event(MGMT_EV_NEW_LONG_TERM_KEY, hdev, &ev, sizeof(ev),
3009 NULL);
Vinicius Costa Gomes346af672012-02-02 21:08:02 -03003010}
3011
Johan Hedbergafc747a2012-01-15 18:11:07 +02003012int mgmt_device_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003013 u8 addr_type, u32 flags, u8 *name, u8 name_len,
3014 u8 *dev_class)
Johan Hedbergf7520542011-01-20 12:34:39 +02003015{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003016 char buf[512];
3017 struct mgmt_ev_device_connected *ev = (void *) buf;
3018 u16 eir_len = 0;
Johan Hedbergf7520542011-01-20 12:34:39 +02003019
Johan Hedbergb644ba32012-01-17 21:48:47 +02003020 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003021 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003022
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003023 ev->flags = __cpu_to_le32(flags);
Johan Hedberg08c79b62012-02-23 22:31:51 +02003024
Johan Hedbergb644ba32012-01-17 21:48:47 +02003025 if (name_len > 0)
3026 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003027 name, name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003028
3029 if (dev_class && memcmp(dev_class, "\0\0\0", 3) != 0)
Brian Gix53156382012-03-09 14:07:03 -08003030 eir_len = eir_append_data(ev->eir, eir_len,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003031 EIR_CLASS_OF_DEV, dev_class, 3);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003032
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003033 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003034
3035 return mgmt_event(MGMT_EV_DEVICE_CONNECTED, hdev, buf,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003036 sizeof(*ev) + eir_len, NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02003037}
3038
Johan Hedberg8962ee72011-01-20 12:40:27 +02003039static void disconnect_rsp(struct pending_cmd *cmd, void *data)
3040{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01003041 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003042 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02003043 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003044
Johan Hedberg88c3df12012-02-09 14:27:38 +02003045 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3046 rp.addr.type = cp->addr.type;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003047
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003048 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, 0, &rp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003049 sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003050
3051 *sk = cmd->sk;
3052 sock_hold(*sk);
3053
Johan Hedberga664b5b2011-02-19 12:06:02 -03003054 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003055}
3056
Johan Hedberg124f6e32012-02-09 13:50:12 +02003057static void unpair_device_rsp(struct pending_cmd *cmd, void *data)
Johan Hedberga8a1d192011-11-10 15:54:38 +02003058{
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003059 struct hci_dev *hdev = data;
Johan Hedberg124f6e32012-02-09 13:50:12 +02003060 struct mgmt_cp_unpair_device *cp = cmd->param;
3061 struct mgmt_rp_unpair_device rp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003062
3063 memset(&rp, 0, sizeof(rp));
Johan Hedberg124f6e32012-02-09 13:50:12 +02003064 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
3065 rp.addr.type = cp->addr.type;
Johan Hedberga8a1d192011-11-10 15:54:38 +02003066
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003067 device_unpaired(hdev, &cp->addr.bdaddr, cp->addr.type, cmd->sk);
3068
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003069 cmd_complete(cmd->sk, cmd->index, cmd->opcode, 0, &rp, sizeof(rp));
Johan Hedberga8a1d192011-11-10 15:54:38 +02003070
3071 mgmt_pending_remove(cmd);
3072}
3073
Johan Hedbergafc747a2012-01-15 18:11:07 +02003074int mgmt_device_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003075 u8 link_type, u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02003076{
Johan Hedberg4c659c32011-11-07 23:13:39 +02003077 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003078 struct sock *sk = NULL;
3079 int err;
3080
Johan Hedberg744cf192011-11-08 20:40:14 +02003081 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02003082
Johan Hedbergf7520542011-01-20 12:34:39 +02003083 bacpy(&ev.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003084 ev.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02003085
Johan Hedbergafc747a2012-01-15 18:11:07 +02003086 err = mgmt_event(MGMT_EV_DEVICE_DISCONNECTED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003087 sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003088
3089 if (sk)
Szymon Jancd97dcb62012-03-16 16:02:56 +01003090 sock_put(sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003091
Johan Hedberg124f6e32012-02-09 13:50:12 +02003092 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003093 hdev);
Johan Hedberga8a1d192011-11-10 15:54:38 +02003094
Johan Hedberg8962ee72011-01-20 12:40:27 +02003095 return err;
3096}
3097
Johan Hedberg88c3df12012-02-09 14:27:38 +02003098int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003099 u8 link_type, u8 addr_type, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02003100{
Johan Hedberg88c3df12012-02-09 14:27:38 +02003101 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02003102 struct pending_cmd *cmd;
3103 int err;
3104
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003105 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003106 if (!cmd)
3107 return -ENOENT;
3108
Johan Hedberg88c3df12012-02-09 14:27:38 +02003109 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003110 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02003111
Johan Hedberg88c3df12012-02-09 14:27:38 +02003112 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003113 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02003114
Johan Hedberga664b5b2011-02-19 12:06:02 -03003115 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003116
Johan Hedbergb1078ad2012-02-09 17:21:16 +02003117 mgmt_pending_foreach(MGMT_OP_UNPAIR_DEVICE, hdev, unpair_device_rsp,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003118 hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02003119 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02003120}
Johan Hedberg17d5c042011-01-22 06:09:08 +02003121
Johan Hedberg48264f02011-11-09 13:58:58 +02003122int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003123 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02003124{
3125 struct mgmt_ev_connect_failed ev;
3126
Johan Hedberg4c659c32011-11-07 23:13:39 +02003127 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003128 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003129 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003130
Johan Hedberg744cf192011-11-08 20:40:14 +02003131 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02003132}
Johan Hedberg980e1a52011-01-22 06:10:07 +02003133
Johan Hedberg744cf192011-11-08 20:40:14 +02003134int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003135{
3136 struct mgmt_ev_pin_code_request ev;
3137
Johan Hedbergd8457692012-02-17 14:24:57 +02003138 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003139 ev.addr.type = BDADDR_BREDR;
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02003140 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003141
Johan Hedberg744cf192011-11-08 20:40:14 +02003142 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003143 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003144}
3145
Johan Hedberg744cf192011-11-08 20:40:14 +02003146int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003147 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003148{
3149 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003150 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003151 int err;
3152
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003153 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003154 if (!cmd)
3155 return -ENOENT;
3156
Johan Hedbergd8457692012-02-17 14:24:57 +02003157 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003158 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003159
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003160 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003161 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003162
Johan Hedberga664b5b2011-02-19 12:06:02 -03003163 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003164
3165 return err;
3166}
3167
Johan Hedberg744cf192011-11-08 20:40:14 +02003168int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003169 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02003170{
3171 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003172 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02003173 int err;
3174
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003175 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003176 if (!cmd)
3177 return -ENOENT;
3178
Johan Hedbergd8457692012-02-17 14:24:57 +02003179 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes591f47f2012-04-24 21:02:49 -03003180 rp.addr.type = BDADDR_BREDR;
Johan Hedbergac56fb12011-02-19 12:05:59 -03003181
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003182 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003183 mgmt_status(status), &rp, sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02003184
Johan Hedberga664b5b2011-02-19 12:06:02 -03003185 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02003186
3187 return err;
3188}
Johan Hedberga5c29682011-02-19 12:05:57 -03003189
Johan Hedberg744cf192011-11-08 20:40:14 +02003190int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003191 u8 link_type, u8 addr_type, __le32 value,
3192 u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03003193{
3194 struct mgmt_ev_user_confirm_request ev;
3195
Johan Hedberg744cf192011-11-08 20:40:14 +02003196 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03003197
Johan Hedberg272d90d2012-02-09 15:26:12 +02003198 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003199 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07003200 ev.confirm_hint = confirm_hint;
Andrei Emeltchenko78e8098e2012-03-09 13:00:50 +02003201 ev.value = value;
Johan Hedberga5c29682011-02-19 12:05:57 -03003202
Johan Hedberg744cf192011-11-08 20:40:14 +02003203 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003204 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03003205}
3206
Johan Hedberg272d90d2012-02-09 15:26:12 +02003207int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003208 u8 link_type, u8 addr_type)
Brian Gix604086b2011-11-23 08:28:33 -08003209{
3210 struct mgmt_ev_user_passkey_request ev;
3211
3212 BT_DBG("%s", hdev->name);
3213
Johan Hedberg272d90d2012-02-09 15:26:12 +02003214 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003215 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Brian Gix604086b2011-11-23 08:28:33 -08003216
3217 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003218 NULL);
Brian Gix604086b2011-11-23 08:28:33 -08003219}
3220
Brian Gix0df4c182011-11-16 13:53:13 -08003221static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo Padovan8ce8e2b2012-05-17 00:36:20 -03003222 u8 link_type, u8 addr_type, u8 status,
3223 u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03003224{
3225 struct pending_cmd *cmd;
3226 struct mgmt_rp_user_confirm_reply rp;
3227 int err;
3228
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003229 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03003230 if (!cmd)
3231 return -ENOENT;
3232
Johan Hedberg272d90d2012-02-09 15:26:12 +02003233 bacpy(&rp.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003234 rp.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003235 err = cmd_complete(cmd->sk, hdev->id, opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003236 &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03003237
Johan Hedberga664b5b2011-02-19 12:06:02 -03003238 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03003239
3240 return err;
3241}
3242
Johan Hedberg744cf192011-11-08 20:40:14 +02003243int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003244 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003245{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003246 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003247 status, MGMT_OP_USER_CONFIRM_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003248}
3249
Johan Hedberg272d90d2012-02-09 15:26:12 +02003250int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003251 u8 link_type, u8 addr_type, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03003252{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003253 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003254 status,
3255 MGMT_OP_USER_CONFIRM_NEG_REPLY);
Johan Hedberga5c29682011-02-19 12:05:57 -03003256}
Johan Hedberg2a611692011-02-19 12:06:00 -03003257
Brian Gix604086b2011-11-23 08:28:33 -08003258int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003259 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003260{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003261 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003262 status, MGMT_OP_USER_PASSKEY_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003263}
3264
Johan Hedberg272d90d2012-02-09 15:26:12 +02003265int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003266 u8 link_type, u8 addr_type, u8 status)
Brian Gix604086b2011-11-23 08:28:33 -08003267{
Johan Hedberg272d90d2012-02-09 15:26:12 +02003268 return user_pairing_resp_complete(hdev, bdaddr, link_type, addr_type,
Gustavo Padovan8fc9ced2012-05-23 04:04:21 -03003269 status,
3270 MGMT_OP_USER_PASSKEY_NEG_REPLY);
Brian Gix604086b2011-11-23 08:28:33 -08003271}
3272
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003273int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003274 u8 addr_type, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03003275{
3276 struct mgmt_ev_auth_failed ev;
3277
Johan Hedbergbab73cb2012-02-09 16:07:29 +02003278 bacpy(&ev.addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003279 ev.addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02003280 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03003281
Johan Hedberg744cf192011-11-08 20:40:14 +02003282 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03003283}
Johan Hedbergb312b1612011-03-16 14:29:37 +02003284
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003285int mgmt_auth_enable_complete(struct hci_dev *hdev, u8 status)
3286{
3287 struct cmd_lookup match = { NULL, hdev };
Johan Hedberg47990ea2012-02-22 11:58:37 +02003288 bool changed = false;
3289 int err = 0;
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003290
3291 if (status) {
3292 u8 mgmt_err = mgmt_status(status);
3293 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003294 cmd_status_rsp, &mgmt_err);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003295 return 0;
3296 }
3297
Johan Hedberg47990ea2012-02-22 11:58:37 +02003298 if (test_bit(HCI_AUTH, &hdev->flags)) {
3299 if (!test_and_set_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3300 changed = true;
3301 } else {
3302 if (test_and_clear_bit(HCI_LINK_SECURITY, &hdev->dev_flags))
3303 changed = true;
3304 }
3305
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003306 mgmt_pending_foreach(MGMT_OP_SET_LINK_SECURITY, hdev, settings_rsp,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003307 &match);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003308
Johan Hedberg47990ea2012-02-22 11:58:37 +02003309 if (changed)
3310 err = new_settings(hdev, match.sk);
Johan Hedberg33ef95e2012-02-16 23:56:27 +02003311
3312 if (match.sk)
3313 sock_put(match.sk);
3314
3315 return err;
3316}
3317
Johan Hedbergcacaf522012-02-21 00:52:42 +02003318static int clear_eir(struct hci_dev *hdev)
3319{
3320 struct hci_cp_write_eir cp;
3321
3322 if (!(hdev->features[6] & LMP_EXT_INQ))
3323 return 0;
3324
Johan Hedbergc80da272012-02-22 15:38:48 +02003325 memset(hdev->eir, 0, sizeof(hdev->eir));
3326
Johan Hedbergcacaf522012-02-21 00:52:42 +02003327 memset(&cp, 0, sizeof(cp));
3328
3329 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
3330}
3331
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003332int mgmt_ssp_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003333{
3334 struct cmd_lookup match = { NULL, hdev };
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003335 bool changed = false;
3336 int err = 0;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003337
3338 if (status) {
3339 u8 mgmt_err = mgmt_status(status);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003340
3341 if (enable && test_and_clear_bit(HCI_SSP_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003342 &hdev->dev_flags))
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003343 err = new_settings(hdev, NULL);
3344
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003345 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, cmd_status_rsp,
3346 &mgmt_err);
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003347
3348 return err;
3349 }
3350
3351 if (enable) {
3352 if (!test_and_set_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3353 changed = true;
3354 } else {
3355 if (test_and_clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3356 changed = true;
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003357 }
3358
3359 mgmt_pending_foreach(MGMT_OP_SET_SSP, hdev, settings_rsp, &match);
3360
Johan Hedbergc0ecddc2012-02-22 12:38:31 +02003361 if (changed)
3362 err = new_settings(hdev, match.sk);
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003363
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003364 if (match.sk)
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003365 sock_put(match.sk);
3366
Johan Hedberg5fc6ebb2012-02-22 15:10:59 +02003367 if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
3368 update_eir(hdev);
3369 else
3370 clear_eir(hdev);
Johan Hedbergcacaf522012-02-21 00:52:42 +02003371
Johan Hedberged2c4ee2012-02-17 00:56:28 +02003372 return err;
3373}
3374
Johan Hedberg90e70452012-02-23 23:09:40 +02003375static void class_rsp(struct pending_cmd *cmd, void *data)
3376{
3377 struct cmd_lookup *match = data;
3378
3379 cmd_complete(cmd->sk, cmd->index, cmd->opcode, match->mgmt_status,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003380 match->hdev->dev_class, 3);
Johan Hedberg90e70452012-02-23 23:09:40 +02003381
3382 list_del(&cmd->list);
3383
3384 if (match->sk == NULL) {
3385 match->sk = cmd->sk;
3386 sock_hold(match->sk);
3387 }
3388
3389 mgmt_pending_free(cmd);
3390}
3391
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003392int mgmt_set_class_of_dev_complete(struct hci_dev *hdev, u8 *dev_class,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003393 u8 status)
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003394{
Johan Hedberg90e70452012-02-23 23:09:40 +02003395 struct cmd_lookup match = { NULL, hdev, mgmt_status(status) };
3396 int err = 0;
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003397
Johan Hedbergc95f0ba2012-02-23 22:54:38 +02003398 clear_bit(HCI_PENDING_CLASS, &hdev->dev_flags);
3399
Johan Hedberg90e70452012-02-23 23:09:40 +02003400 mgmt_pending_foreach(MGMT_OP_SET_DEV_CLASS, hdev, class_rsp, &match);
3401 mgmt_pending_foreach(MGMT_OP_ADD_UUID, hdev, class_rsp, &match);
3402 mgmt_pending_foreach(MGMT_OP_REMOVE_UUID, hdev, class_rsp, &match);
3403
3404 if (!status)
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003405 err = mgmt_event(MGMT_EV_CLASS_OF_DEV_CHANGED, hdev, dev_class,
3406 3, NULL);
Johan Hedberg90e70452012-02-23 23:09:40 +02003407
3408 if (match.sk)
3409 sock_put(match.sk);
Marcel Holtmann7f9a9032012-02-22 18:38:01 +01003410
3411 return err;
3412}
3413
Johan Hedberg744cf192011-11-08 20:40:14 +02003414int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02003415{
3416 struct pending_cmd *cmd;
3417 struct mgmt_cp_set_local_name ev;
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003418 bool changed = false;
3419 int err = 0;
3420
3421 if (memcmp(name, hdev->dev_name, sizeof(hdev->dev_name)) != 0) {
3422 memcpy(hdev->dev_name, name, sizeof(hdev->dev_name));
3423 changed = true;
3424 }
Johan Hedbergb312b1612011-03-16 14:29:37 +02003425
3426 memset(&ev, 0, sizeof(ev));
3427 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003428 memcpy(ev.short_name, hdev->short_name, HCI_MAX_SHORT_NAME_LENGTH);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003429
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003430 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003431 if (!cmd)
3432 goto send_event;
3433
Johan Hedberg7bdaae42012-02-22 21:39:58 +02003434 /* Always assume that either the short or the complete name has
3435 * changed if there was a pending mgmt command */
3436 changed = true;
3437
Johan Hedbergb312b1612011-03-16 14:29:37 +02003438 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02003439 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003440 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003441 goto failed;
3442 }
3443
Johan Hedbergaee9b2182012-02-18 15:07:59 +02003444 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, 0, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003445 sizeof(ev));
Johan Hedbergb312b1612011-03-16 14:29:37 +02003446 if (err < 0)
3447 goto failed;
3448
3449send_event:
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003450 if (changed)
3451 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003452 sizeof(ev), cmd ? cmd->sk : NULL);
Johan Hedberg28cc7bd2012-02-22 21:06:55 +02003453
Johan Hedbergf51d5b22012-02-22 18:17:32 +02003454 update_eir(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02003455
3456failed:
3457 if (cmd)
3458 mgmt_pending_remove(cmd);
3459 return err;
3460}
Szymon Jancc35938b2011-03-22 13:12:21 +01003461
Johan Hedberg744cf192011-11-08 20:40:14 +02003462int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003463 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01003464{
3465 struct pending_cmd *cmd;
3466 int err;
3467
Johan Hedberg744cf192011-11-08 20:40:14 +02003468 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01003469
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003470 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01003471 if (!cmd)
3472 return -ENOENT;
3473
3474 if (status) {
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003475 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_READ_LOCAL_OOB_DATA,
3476 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01003477 } else {
3478 struct mgmt_rp_read_local_oob_data rp;
3479
3480 memcpy(rp.hash, hash, sizeof(rp.hash));
3481 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
3482
Johan Hedberg744cf192011-11-08 20:40:14 +02003483 err = cmd_complete(cmd->sk, hdev->id,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003484 MGMT_OP_READ_LOCAL_OOB_DATA, 0, &rp,
3485 sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01003486 }
3487
3488 mgmt_pending_remove(cmd);
3489
3490 return err;
3491}
Johan Hedberge17acd42011-03-30 23:57:16 +03003492
Johan Hedberg06199cf2012-02-22 16:37:11 +02003493int mgmt_le_enable_complete(struct hci_dev *hdev, u8 enable, u8 status)
3494{
3495 struct cmd_lookup match = { NULL, hdev };
3496 bool changed = false;
3497 int err = 0;
3498
3499 if (status) {
3500 u8 mgmt_err = mgmt_status(status);
3501
3502 if (enable && test_and_clear_bit(HCI_LE_ENABLED,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003503 &hdev->dev_flags))
Szymon Jancd97dcb62012-03-16 16:02:56 +01003504 err = new_settings(hdev, NULL);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003505
Szymon Jancd97dcb62012-03-16 16:02:56 +01003506 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, cmd_status_rsp,
3507 &mgmt_err);
Johan Hedberg06199cf2012-02-22 16:37:11 +02003508
3509 return err;
3510 }
3511
3512 if (enable) {
3513 if (!test_and_set_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3514 changed = true;
3515 } else {
3516 if (test_and_clear_bit(HCI_LE_ENABLED, &hdev->dev_flags))
3517 changed = true;
3518 }
3519
3520 mgmt_pending_foreach(MGMT_OP_SET_LE, hdev, settings_rsp, &match);
3521
3522 if (changed)
3523 err = new_settings(hdev, match.sk);
3524
3525 if (match.sk)
3526 sock_put(match.sk);
3527
3528 return err;
3529}
3530
Johan Hedberg48264f02011-11-09 13:58:58 +02003531int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003532 u8 addr_type, u8 *dev_class, s8 rssi, u8 cfm_name, u8
3533 ssp, u8 *eir, u16 eir_len)
Johan Hedberge17acd42011-03-30 23:57:16 +03003534{
Johan Hedberge319d2e2012-01-15 19:51:59 +02003535 char buf[512];
3536 struct mgmt_ev_device_found *ev = (void *) buf;
Johan Hedberg1dc06092012-01-15 21:01:23 +02003537 size_t ev_size;
Johan Hedberge17acd42011-03-30 23:57:16 +03003538
Johan Hedberg1dc06092012-01-15 21:01:23 +02003539 /* Leave 5 bytes for a potential CoD field */
3540 if (sizeof(*ev) + eir_len + 5 > sizeof(buf))
Andre Guedes7d262f82012-01-10 18:20:49 -03003541 return -EINVAL;
3542
Johan Hedberg1dc06092012-01-15 21:01:23 +02003543 memset(buf, 0, sizeof(buf));
3544
Johan Hedberge319d2e2012-01-15 19:51:59 +02003545 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003546 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedberge319d2e2012-01-15 19:51:59 +02003547 ev->rssi = rssi;
Johan Hedberg9a395a82012-02-23 00:00:32 +02003548 if (cfm_name)
Andrei Emeltchenko33cef262012-06-18 13:03:46 +03003549 ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
Johan Hedberg388fc8f2012-02-23 00:38:59 +02003550 if (!ssp)
Andrei Emeltchenko33cef262012-06-18 13:03:46 +03003551 ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
Johan Hedberge17acd42011-03-30 23:57:16 +03003552
Johan Hedberg1dc06092012-01-15 21:01:23 +02003553 if (eir_len > 0)
Johan Hedberge319d2e2012-01-15 19:51:59 +02003554 memcpy(ev->eir, eir, eir_len);
Johan Hedberge17acd42011-03-30 23:57:16 +03003555
Johan Hedberg1dc06092012-01-15 21:01:23 +02003556 if (dev_class && !eir_has_data_type(ev->eir, eir_len, EIR_CLASS_OF_DEV))
3557 eir_len = eir_append_data(ev->eir, eir_len, EIR_CLASS_OF_DEV,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003558 dev_class, 3);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003559
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003560 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedberg1dc06092012-01-15 21:01:23 +02003561 ev_size = sizeof(*ev) + eir_len;
Andre Guedesf8523592011-09-09 18:56:26 -03003562
Johan Hedberge319d2e2012-01-15 19:51:59 +02003563 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev, ev_size, NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03003564}
Johan Hedberga88a9652011-03-30 13:18:12 +03003565
Johan Hedbergb644ba32012-01-17 21:48:47 +02003566int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003567 u8 addr_type, s8 rssi, u8 *name, u8 name_len)
Johan Hedberga88a9652011-03-30 13:18:12 +03003568{
Johan Hedbergb644ba32012-01-17 21:48:47 +02003569 struct mgmt_ev_device_found *ev;
3570 char buf[sizeof(*ev) + HCI_MAX_NAME_LENGTH + 2];
3571 u16 eir_len;
Johan Hedberga88a9652011-03-30 13:18:12 +03003572
Johan Hedbergb644ba32012-01-17 21:48:47 +02003573 ev = (struct mgmt_ev_device_found *) buf;
Johan Hedberga88a9652011-03-30 13:18:12 +03003574
Johan Hedbergb644ba32012-01-17 21:48:47 +02003575 memset(buf, 0, sizeof(buf));
Johan Hedberga88a9652011-03-30 13:18:12 +03003576
Johan Hedbergb644ba32012-01-17 21:48:47 +02003577 bacpy(&ev->addr.bdaddr, bdaddr);
Andre Guedes57c14772012-04-24 21:02:50 -03003578 ev->addr.type = link_to_bdaddr(link_type, addr_type);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003579 ev->rssi = rssi;
3580
3581 eir_len = eir_append_data(ev->eir, 0, EIR_NAME_COMPLETE, name,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003582 name_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003583
Marcel Holtmanneb55ef02012-03-14 18:08:46 +02003584 ev->eir_len = cpu_to_le16(eir_len);
Johan Hedbergb644ba32012-01-17 21:48:47 +02003585
Johan Hedberg053c7e02012-02-04 00:06:00 +02003586 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, ev,
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003587 sizeof(*ev) + eir_len, NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03003588}
Johan Hedberg314b2382011-04-27 10:29:57 -04003589
Andre Guedes7a135102011-11-09 17:14:25 -03003590int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02003591{
3592 struct pending_cmd *cmd;
Johan Hedbergf808e162012-02-19 12:52:07 +02003593 u8 type;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003594 int err;
3595
Andre Guedes203159d2012-02-13 15:41:01 -03003596 hci_discovery_set_state(hdev, DISCOVERY_STOPPED);
3597
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003598 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003599 if (!cmd)
3600 return -ENOENT;
3601
Johan Hedbergf808e162012-02-19 12:52:07 +02003602 type = hdev->discovery.type;
3603
3604 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003605 &type, sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003606 mgmt_pending_remove(cmd);
3607
3608 return err;
3609}
3610
Andre Guedese6d465c2011-11-09 17:14:26 -03003611int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
3612{
3613 struct pending_cmd *cmd;
3614 int err;
3615
3616 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
3617 if (!cmd)
3618 return -ENOENT;
3619
Johan Hedbergd9306502012-02-20 23:25:18 +02003620 err = cmd_complete(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003621 &hdev->discovery.type, sizeof(hdev->discovery.type));
Johan Hedberg03811012010-12-08 00:21:06 +02003622 mgmt_pending_remove(cmd);
3623
3624 return err;
3625}
Johan Hedberg314b2382011-04-27 10:29:57 -04003626
Johan Hedberg744cf192011-11-08 20:40:14 +02003627int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04003628{
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003629 struct mgmt_ev_discovering ev;
Johan Hedberg164a6e72011-11-01 17:06:44 +02003630 struct pending_cmd *cmd;
3631
Andre Guedes343fb142011-11-22 17:14:19 -03003632 BT_DBG("%s discovering %u", hdev->name, discovering);
3633
Johan Hedberg164a6e72011-11-01 17:06:44 +02003634 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003635 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003636 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003637 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02003638
3639 if (cmd != NULL) {
Johan Hedbergf808e162012-02-19 12:52:07 +02003640 u8 type = hdev->discovery.type;
3641
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003642 cmd_complete(cmd->sk, hdev->id, cmd->opcode, 0, &type,
3643 sizeof(type));
Johan Hedberg164a6e72011-11-01 17:06:44 +02003644 mgmt_pending_remove(cmd);
3645 }
3646
Johan Hedbergf963e8e2012-02-20 23:30:44 +02003647 memset(&ev, 0, sizeof(ev));
3648 ev.type = hdev->discovery.type;
3649 ev.discovering = discovering;
3650
3651 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg314b2382011-04-27 10:29:57 -04003652}
Antti Julku5e762442011-08-25 16:48:02 +03003653
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003654int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003655{
3656 struct pending_cmd *cmd;
3657 struct mgmt_ev_device_blocked ev;
3658
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003659 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003660
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003661 bacpy(&ev.addr.bdaddr, bdaddr);
3662 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003663
Johan Hedberg744cf192011-11-08 20:40:14 +02003664 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003665 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003666}
3667
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003668int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
Antti Julku5e762442011-08-25 16:48:02 +03003669{
3670 struct pending_cmd *cmd;
3671 struct mgmt_ev_device_unblocked ev;
3672
Johan Hedberg2e58ef32011-11-08 20:40:15 +02003673 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03003674
Johan Hedberg88c1fe42012-02-09 15:56:11 +02003675 bacpy(&ev.addr.bdaddr, bdaddr);
3676 ev.addr.type = type;
Antti Julku5e762442011-08-25 16:48:02 +03003677
Johan Hedberg744cf192011-11-08 20:40:14 +02003678 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
Gustavo F. Padovan04124682012-03-08 01:25:00 -03003679 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03003680}
Marcel Holtmannd7b7e792012-02-20 21:47:49 +01003681
3682module_param(enable_hs, bool, 0644);
3683MODULE_PARM_DESC(enable_hs, "Enable High Speed support");