blob: 559b938f504c73cc37e4ff6a4d94418e0673fbd9 [file] [log] [blame]
Johan Hedberg03811012010-12-08 00:21:06 +02001/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2010 Nokia Corporation
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License version 2 as
7 published by the Free Software Foundation;
8
9 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
10 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
11 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
12 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
13 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
18 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
19 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
20 SOFTWARE IS DISCLAIMED.
21*/
22
23/* Bluetooth HCI Management interface */
24
Johan Hedbergca69b792011-11-11 18:10:00 +020025#include <linux/kernel.h>
Szymon Janc72359752011-02-17 14:16:32 +010026#include <linux/uaccess.h>
Johan Hedberg03811012010-12-08 00:21:06 +020027#include <asm/unaligned.h>
28
29#include <net/bluetooth/bluetooth.h>
30#include <net/bluetooth/hci_core.h>
31#include <net/bluetooth/mgmt.h>
32
Johan Hedberg02d98122010-12-13 21:07:04 +020033#define MGMT_VERSION 0
34#define MGMT_REVISION 1
35
Andre Guedes2519a1f2011-11-07 11:45:24 -030036#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
37
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020038struct pending_cmd {
39 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020040 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020041 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010042 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020043 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030044 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020045};
46
Johan Hedbergca69b792011-11-11 18:10:00 +020047/* HCI to MGMT error code conversion table */
48static u8 mgmt_status_table[] = {
49 MGMT_STATUS_SUCCESS,
50 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
51 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
52 MGMT_STATUS_FAILED, /* Hardware Failure */
53 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
54 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
55 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
56 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
57 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
58 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
59 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
60 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
61 MGMT_STATUS_BUSY, /* Command Disallowed */
62 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
63 MGMT_STATUS_REJECTED, /* Rejected Security */
64 MGMT_STATUS_REJECTED, /* Rejected Personal */
65 MGMT_STATUS_TIMEOUT, /* Host Timeout */
66 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
67 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
68 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
69 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
70 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
71 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
72 MGMT_STATUS_BUSY, /* Repeated Attempts */
73 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
74 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
75 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
76 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
77 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
78 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
79 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
80 MGMT_STATUS_FAILED, /* Unspecified Error */
81 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
82 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
83 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
84 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
85 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
86 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
87 MGMT_STATUS_FAILED, /* Unit Link Key Used */
88 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
89 MGMT_STATUS_TIMEOUT, /* Instant Passed */
90 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
91 MGMT_STATUS_FAILED, /* Transaction Collision */
92 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
93 MGMT_STATUS_REJECTED, /* QoS Rejected */
94 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
95 MGMT_STATUS_REJECTED, /* Insufficient Security */
96 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
97 MGMT_STATUS_BUSY, /* Role Switch Pending */
98 MGMT_STATUS_FAILED, /* Slot Violation */
99 MGMT_STATUS_FAILED, /* Role Switch Failed */
100 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
101 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
102 MGMT_STATUS_BUSY, /* Host Busy Pairing */
103 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
104 MGMT_STATUS_BUSY, /* Controller Busy */
105 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
106 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
107 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
108 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
109 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
110};
111
112static u8 mgmt_status(u8 hci_status)
113{
114 if (hci_status < ARRAY_SIZE(mgmt_status_table))
115 return mgmt_status_table[hci_status];
116
117 return MGMT_STATUS_FAILED;
118}
119
Szymon Janc4e51eae2011-02-25 19:05:48 +0100120static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200121{
122 struct sk_buff *skb;
123 struct mgmt_hdr *hdr;
124 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300125 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200126
Szymon Janc34eb5252011-02-28 14:10:08 +0100127 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200128
129 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
130 if (!skb)
131 return -ENOMEM;
132
133 hdr = (void *) skb_put(skb, sizeof(*hdr));
134
135 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100136 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200137 hdr->len = cpu_to_le16(sizeof(*ev));
138
139 ev = (void *) skb_put(skb, sizeof(*ev));
140 ev->status = status;
141 put_unaligned_le16(cmd, &ev->opcode);
142
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300143 err = sock_queue_rcv_skb(sk, skb);
144 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200145 kfree_skb(skb);
146
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300147 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200148}
149
Szymon Janc4e51eae2011-02-25 19:05:48 +0100150static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
151 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200152{
153 struct sk_buff *skb;
154 struct mgmt_hdr *hdr;
155 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300156 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200157
158 BT_DBG("sock %p", sk);
159
Johan Hedberga38528f2011-01-22 06:46:43 +0200160 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200161 if (!skb)
162 return -ENOMEM;
163
164 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200165
Johan Hedberg02d98122010-12-13 21:07:04 +0200166 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100167 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200168 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200169
Johan Hedberga38528f2011-01-22 06:46:43 +0200170 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
171 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100172
173 if (rp)
174 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200175
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300176 err = sock_queue_rcv_skb(sk, skb);
177 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200178 kfree_skb(skb);
179
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300180 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200181}
182
Johan Hedberga38528f2011-01-22 06:46:43 +0200183static int read_version(struct sock *sk)
184{
185 struct mgmt_rp_read_version rp;
186
187 BT_DBG("sock %p", sk);
188
189 rp.version = MGMT_VERSION;
190 put_unaligned_le16(MGMT_REVISION, &rp.revision);
191
Szymon Janc4e51eae2011-02-25 19:05:48 +0100192 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
193 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200194}
195
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200196static int read_index_list(struct sock *sk)
197{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200198 struct mgmt_rp_read_index_list *rp;
199 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200200 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200201 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200202 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200203 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200204
205 BT_DBG("sock %p", sk);
206
207 read_lock(&hci_dev_list_lock);
208
209 count = 0;
210 list_for_each(p, &hci_dev_list) {
211 count++;
212 }
213
Johan Hedberga38528f2011-01-22 06:46:43 +0200214 rp_len = sizeof(*rp) + (2 * count);
215 rp = kmalloc(rp_len, GFP_ATOMIC);
216 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100217 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200218 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100219 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200220
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200221 put_unaligned_le16(count, &rp->num_controllers);
222
223 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200224 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberg32435532011-11-07 22:16:04 +0200225 if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200226 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200227
228 if (test_bit(HCI_SETUP, &d->flags))
229 continue;
230
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200231 put_unaligned_le16(d->id, &rp->index[i++]);
232 BT_DBG("Added hci%u", d->id);
233 }
234
235 read_unlock(&hci_dev_list_lock);
236
Szymon Janc4e51eae2011-02-25 19:05:48 +0100237 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
238 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200239
Johan Hedberga38528f2011-01-22 06:46:43 +0200240 kfree(rp);
241
242 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200243}
244
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200245static u32 get_supported_settings(struct hci_dev *hdev)
246{
247 u32 settings = 0;
248
249 settings |= MGMT_SETTING_POWERED;
250 settings |= MGMT_SETTING_CONNECTABLE;
251 settings |= MGMT_SETTING_FAST_CONNECTABLE;
252 settings |= MGMT_SETTING_DISCOVERABLE;
253 settings |= MGMT_SETTING_PAIRABLE;
254
255 if (hdev->features[6] & LMP_SIMPLE_PAIR)
256 settings |= MGMT_SETTING_SSP;
257
258 if (!(hdev->features[4] & LMP_NO_BREDR)) {
259 settings |= MGMT_SETTING_BREDR;
260 settings |= MGMT_SETTING_LINK_SECURITY;
261 }
262
263 if (hdev->features[4] & LMP_LE)
264 settings |= MGMT_SETTING_LE;
265
266 return settings;
267}
268
269static u32 get_current_settings(struct hci_dev *hdev)
270{
271 u32 settings = 0;
272
273 if (test_bit(HCI_UP, &hdev->flags))
274 settings |= MGMT_SETTING_POWERED;
275 else
276 return settings;
277
278 if (test_bit(HCI_PSCAN, &hdev->flags))
279 settings |= MGMT_SETTING_CONNECTABLE;
280
281 if (test_bit(HCI_ISCAN, &hdev->flags))
282 settings |= MGMT_SETTING_DISCOVERABLE;
283
284 if (test_bit(HCI_PAIRABLE, &hdev->flags))
285 settings |= MGMT_SETTING_PAIRABLE;
286
287 if (!(hdev->features[4] & LMP_NO_BREDR))
288 settings |= MGMT_SETTING_BREDR;
289
290 if (hdev->extfeatures[0] & LMP_HOST_LE)
291 settings |= MGMT_SETTING_LE;
292
293 if (test_bit(HCI_AUTH, &hdev->flags))
294 settings |= MGMT_SETTING_LINK_SECURITY;
295
296 if (hdev->ssp_mode > 0)
297 settings |= MGMT_SETTING_SSP;
298
299 return settings;
300}
301
Szymon Janc4e51eae2011-02-25 19:05:48 +0100302static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200303{
Johan Hedberga38528f2011-01-22 06:46:43 +0200304 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200305 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200306
Szymon Janc4e51eae2011-02-25 19:05:48 +0100307 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200308
Szymon Janc4e51eae2011-02-25 19:05:48 +0100309 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200310 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200311 return cmd_status(sk, index, MGMT_OP_READ_INFO,
312 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200313
Johan Hedberg32435532011-11-07 22:16:04 +0200314 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
315 cancel_delayed_work_sync(&hdev->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200316
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300317 hci_dev_lock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200318
Johan Hedberg14c0b602011-12-15 00:47:37 +0200319 if (test_and_clear_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags)) {
320 set_bit(HCI_MGMT, &hdev->flags);
321 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
322 }
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200323
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200324 memset(&rp, 0, sizeof(rp));
325
Johan Hedberga38528f2011-01-22 06:46:43 +0200326 bacpy(&rp.bdaddr, &hdev->bdaddr);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200327
328 rp.version = hdev->hci_ver;
329
Johan Hedberga38528f2011-01-22 06:46:43 +0200330 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200331
332 rp.supported_settings = cpu_to_le32(get_supported_settings(hdev));
333 rp.current_settings = cpu_to_le32(get_current_settings(hdev));
334
335 memcpy(rp.dev_class, hdev->dev_class, 3);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200336
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200337 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
338
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300339 hci_dev_unlock(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200340 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200341
Szymon Janc4e51eae2011-02-25 19:05:48 +0100342 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200343}
344
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200345static void mgmt_pending_free(struct pending_cmd *cmd)
346{
347 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100348 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200349 kfree(cmd);
350}
351
Johan Hedberg366a0332011-02-19 12:05:55 -0300352static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200353 struct hci_dev *hdev,
354 void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200355{
356 struct pending_cmd *cmd;
357
358 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
359 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300360 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200361
362 cmd->opcode = opcode;
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200363 cmd->index = hdev->id;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200364
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100365 cmd->param = kmalloc(len, GFP_ATOMIC);
366 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200367 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300368 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200369 }
370
Szymon Janc8fce6352011-03-22 13:12:20 +0100371 if (data)
372 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200373
374 cmd->sk = sk;
375 sock_hold(sk);
376
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200377 list_add(&cmd->list, &hdev->mgmt_pending);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200378
Johan Hedberg366a0332011-02-19 12:05:55 -0300379 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200380}
381
Johan Hedberg744cf192011-11-08 20:40:14 +0200382static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200383 void (*cb)(struct pending_cmd *cmd, void *data),
384 void *data)
385{
386 struct list_head *p, *n;
387
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200388 list_for_each_safe(p, n, &hdev->mgmt_pending) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200389 struct pending_cmd *cmd;
390
391 cmd = list_entry(p, struct pending_cmd, list);
392
Johan Hedbergb24752f2011-11-03 14:40:33 +0200393 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200394 continue;
395
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200396 cb(cmd, data);
397 }
398}
399
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200400static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200401{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200402 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200403
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200404 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberg2aeabcb2011-11-09 13:58:57 +0200405 if (cmd->opcode == opcode)
406 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200407 }
408
409 return NULL;
410}
411
Johan Hedberga664b5b2011-02-19 12:06:02 -0300412static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200413{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200414 list_del(&cmd->list);
415 mgmt_pending_free(cmd);
416}
417
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200418static int send_settings_rsp(struct sock *sk, u16 opcode, struct hci_dev *hdev)
Johan Hedberg86805702011-11-11 16:18:52 +0200419{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200420 __le32 settings = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg86805702011-11-11 16:18:52 +0200421
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200422 return cmd_complete(sk, hdev->id, opcode, &settings, sizeof(settings));
Johan Hedberg86805702011-11-11 16:18:52 +0200423}
424
Szymon Janc4e51eae2011-02-25 19:05:48 +0100425static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200426{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200427 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200428 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300429 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300430 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200431
432 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200433
Szymon Janc4e51eae2011-02-25 19:05:48 +0100434 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200435
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100436 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200437 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
438 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100439
Szymon Janc4e51eae2011-02-25 19:05:48 +0100440 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200441 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200442 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
443 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200444
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300445 hci_dev_lock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200446
447 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200448 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200449 err = send_settings_rsp(sk, MGMT_OP_SET_POWERED, hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200450 goto failed;
451 }
452
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200453 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200454 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
455 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200456 goto failed;
457 }
458
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200459 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300460 if (!cmd) {
461 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200462 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300463 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200464
Johan Hedberg72a734e2010-12-30 00:38:22 +0200465 if (cp->val)
Gustavo F. Padovan7f971042011-12-18 12:40:32 -0200466 schedule_work(&hdev->power_on);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200467 else
Gustavo F. Padovan80b7ab32011-12-17 14:52:27 -0200468 schedule_work(&hdev->power_off.work);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200469
Johan Hedberg366a0332011-02-19 12:05:55 -0300470 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200471
472failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300473 hci_dev_unlock(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200474 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300475 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200476}
477
Szymon Janc4e51eae2011-02-25 19:05:48 +0100478static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
479 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200480{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200481 struct mgmt_cp_set_discoverable *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200482 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300483 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200484 u8 scan;
485 int err;
486
487 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200488
Szymon Janc4e51eae2011-02-25 19:05:48 +0100489 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200490
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100491 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200492 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
493 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100494
Szymon Janc4e51eae2011-02-25 19:05:48 +0100495 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200496 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200497 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
498 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200499
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300500 hci_dev_lock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200501
502 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200503 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
504 MGMT_STATUS_NOT_POWERED);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200505 goto failed;
506 }
507
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200508 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
509 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200510 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
511 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200512 goto failed;
513 }
514
Johan Hedberg72a734e2010-12-30 00:38:22 +0200515 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200516 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200517 err = send_settings_rsp(sk, MGMT_OP_SET_DISCOVERABLE, hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200518 goto failed;
519 }
520
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200521 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300522 if (!cmd) {
523 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200524 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300525 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200526
527 scan = SCAN_PAGE;
528
Johan Hedberg72a734e2010-12-30 00:38:22 +0200529 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200530 scan |= SCAN_INQUIRY;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200531 else
Johan Hedberge0f93092011-11-09 01:44:22 +0200532 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200533
534 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
535 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300536 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200537
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200538 if (cp->val)
539 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
540
Johan Hedberg73f22f62010-12-29 16:00:25 +0200541failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300542 hci_dev_unlock(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200543 hci_dev_put(hdev);
544
545 return err;
546}
547
Szymon Janc4e51eae2011-02-25 19:05:48 +0100548static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
549 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200550{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200551 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200552 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300553 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200554 u8 scan;
555 int err;
556
557 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200558
Szymon Janc4e51eae2011-02-25 19:05:48 +0100559 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200560
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100561 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200562 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
563 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100564
Szymon Janc4e51eae2011-02-25 19:05:48 +0100565 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200566 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200567 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
568 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200569
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300570 hci_dev_lock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200571
572 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200573 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
574 MGMT_STATUS_NOT_POWERED);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200575 goto failed;
576 }
577
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200578 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
579 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200580 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
581 MGMT_STATUS_BUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200582 goto failed;
583 }
584
Johan Hedberg72a734e2010-12-30 00:38:22 +0200585 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200586 err = send_settings_rsp(sk, MGMT_OP_SET_CONNECTABLE, hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200587 goto failed;
588 }
589
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200590 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300591 if (!cmd) {
592 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200593 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300594 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200595
Johan Hedberg72a734e2010-12-30 00:38:22 +0200596 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200597 scan = SCAN_PAGE;
598 else
599 scan = 0;
600
601 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
602 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300603 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200604
605failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300606 hci_dev_unlock(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200607 hci_dev_put(hdev);
608
609 return err;
610}
611
Johan Hedberg744cf192011-11-08 20:40:14 +0200612static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
613 u16 data_len, struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200614{
615 struct sk_buff *skb;
616 struct mgmt_hdr *hdr;
617
618 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
619 if (!skb)
620 return -ENOMEM;
621
622 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
623
624 hdr = (void *) skb_put(skb, sizeof(*hdr));
625 hdr->opcode = cpu_to_le16(event);
Johan Hedberg744cf192011-11-08 20:40:14 +0200626 if (hdev)
627 hdr->index = cpu_to_le16(hdev->id);
628 else
629 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergc542a062011-01-26 13:11:03 +0200630 hdr->len = cpu_to_le16(data_len);
631
Szymon Janc4e51eae2011-02-25 19:05:48 +0100632 if (data)
633 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200634
635 hci_send_to_sock(NULL, skb, skip_sk);
636 kfree_skb(skb);
637
638 return 0;
639}
640
Szymon Janc4e51eae2011-02-25 19:05:48 +0100641static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
642 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200643{
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200644 struct mgmt_mode *cp;
Johan Hedbergc542a062011-01-26 13:11:03 +0200645 struct hci_dev *hdev;
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200646 __le32 ev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200647 int err;
648
649 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200650
Szymon Janc4e51eae2011-02-25 19:05:48 +0100651 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200652
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100653 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200654 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
655 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100656
Szymon Janc4e51eae2011-02-25 19:05:48 +0100657 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200658 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200659 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
660 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergc542a062011-01-26 13:11:03 +0200661
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300662 hci_dev_lock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200663
664 if (cp->val)
665 set_bit(HCI_PAIRABLE, &hdev->flags);
666 else
667 clear_bit(HCI_PAIRABLE, &hdev->flags);
668
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200669 err = send_settings_rsp(sk, MGMT_OP_SET_PAIRABLE, hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200670 if (err < 0)
671 goto failed;
672
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200673 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergc542a062011-01-26 13:11:03 +0200674
Johan Hedberg69ab39e2011-12-15 00:47:35 +0200675 err = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200676
677failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300678 hci_dev_unlock(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200679 hci_dev_put(hdev);
680
681 return err;
682}
683
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300684#define EIR_FLAGS 0x01 /* flags */
685#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
686#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
687#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
688#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
689#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
690#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
691#define EIR_NAME_SHORT 0x08 /* shortened local name */
692#define EIR_NAME_COMPLETE 0x09 /* complete local name */
693#define EIR_TX_POWER 0x0A /* transmit power level */
694#define EIR_DEVICE_ID 0x10 /* device ID */
695
696#define PNP_INFO_SVCLASS_ID 0x1200
697
698static u8 bluetooth_base_uuid[] = {
699 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
700 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
701};
702
703static u16 get_uuid16(u8 *uuid128)
704{
705 u32 val;
706 int i;
707
708 for (i = 0; i < 12; i++) {
709 if (bluetooth_base_uuid[i] != uuid128[i])
710 return 0;
711 }
712
713 memcpy(&val, &uuid128[12], 4);
714
715 val = le32_to_cpu(val);
716 if (val > 0xffff)
717 return 0;
718
719 return (u16) val;
720}
721
722static void create_eir(struct hci_dev *hdev, u8 *data)
723{
724 u8 *ptr = data;
725 u16 eir_len = 0;
726 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
727 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200728 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300729 size_t name_len;
730
731 name_len = strlen(hdev->dev_name);
732
733 if (name_len > 0) {
734 /* EIR Data type */
735 if (name_len > 48) {
736 name_len = 48;
737 ptr[1] = EIR_NAME_SHORT;
738 } else
739 ptr[1] = EIR_NAME_COMPLETE;
740
741 /* EIR Data length */
742 ptr[0] = name_len + 1;
743
744 memcpy(ptr + 2, hdev->dev_name, name_len);
745
746 eir_len += (name_len + 2);
747 ptr += (name_len + 2);
748 }
749
750 memset(uuid16_list, 0, sizeof(uuid16_list));
751
752 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200753 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300754 u16 uuid16;
755
756 uuid16 = get_uuid16(uuid->uuid);
757 if (uuid16 == 0)
758 return;
759
760 if (uuid16 < 0x1100)
761 continue;
762
763 if (uuid16 == PNP_INFO_SVCLASS_ID)
764 continue;
765
766 /* Stop if not enough space to put next UUID */
767 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
768 truncated = 1;
769 break;
770 }
771
772 /* Check for duplicates */
773 for (i = 0; uuid16_list[i] != 0; i++)
774 if (uuid16_list[i] == uuid16)
775 break;
776
777 if (uuid16_list[i] == 0) {
778 uuid16_list[i] = uuid16;
779 eir_len += sizeof(u16);
780 }
781 }
782
783 if (uuid16_list[0] != 0) {
784 u8 *length = ptr;
785
786 /* EIR Data type */
787 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
788
789 ptr += 2;
790 eir_len += 2;
791
792 for (i = 0; uuid16_list[i] != 0; i++) {
793 *ptr++ = (uuid16_list[i] & 0x00ff);
794 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
795 }
796
797 /* EIR Data length */
798 *length = (i * sizeof(u16)) + 1;
799 }
800}
801
802static int update_eir(struct hci_dev *hdev)
803{
804 struct hci_cp_write_eir cp;
805
806 if (!(hdev->features[6] & LMP_EXT_INQ))
807 return 0;
808
809 if (hdev->ssp_mode == 0)
810 return 0;
811
812 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
813 return 0;
814
815 memset(&cp, 0, sizeof(cp));
816
817 create_eir(hdev, cp.data);
818
819 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
820 return 0;
821
822 memcpy(hdev->eir, cp.data, sizeof(cp.data));
823
824 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
825}
826
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200827static u8 get_service_classes(struct hci_dev *hdev)
828{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300829 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200830 u8 val = 0;
831
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300832 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200833 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200834
835 return val;
836}
837
838static int update_class(struct hci_dev *hdev)
839{
840 u8 cod[3];
841
842 BT_DBG("%s", hdev->name);
843
844 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
845 return 0;
846
847 cod[0] = hdev->minor_class;
848 cod[1] = hdev->major_class;
849 cod[2] = get_service_classes(hdev);
850
851 if (memcmp(cod, hdev->dev_class, 3) == 0)
852 return 0;
853
854 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
855}
856
Szymon Janc4e51eae2011-02-25 19:05:48 +0100857static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200858{
859 struct mgmt_cp_add_uuid *cp;
860 struct hci_dev *hdev;
861 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200862 int err;
863
864 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200865
Szymon Janc4e51eae2011-02-25 19:05:48 +0100866 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200867
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100868 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200869 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
870 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100871
Szymon Janc4e51eae2011-02-25 19:05:48 +0100872 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200873 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200874 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
875 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200876
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300877 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200878
879 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
880 if (!uuid) {
881 err = -ENOMEM;
882 goto failed;
883 }
884
885 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200886 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200887
888 list_add(&uuid->list, &hdev->uuids);
889
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200890 err = update_class(hdev);
891 if (err < 0)
892 goto failed;
893
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300894 err = update_eir(hdev);
895 if (err < 0)
896 goto failed;
897
Szymon Janc4e51eae2011-02-25 19:05:48 +0100898 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200899
900failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300901 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200902 hci_dev_put(hdev);
903
904 return err;
905}
906
Szymon Janc4e51eae2011-02-25 19:05:48 +0100907static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200908{
909 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100910 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200911 struct hci_dev *hdev;
912 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 +0200913 int err, found;
914
915 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200916
Szymon Janc4e51eae2011-02-25 19:05:48 +0100917 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200918
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100919 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200920 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
921 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100922
Szymon Janc4e51eae2011-02-25 19:05:48 +0100923 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200924 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200925 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
926 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200927
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300928 hci_dev_lock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200929
930 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
931 err = hci_uuids_clear(hdev);
932 goto unlock;
933 }
934
935 found = 0;
936
937 list_for_each_safe(p, n, &hdev->uuids) {
938 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
939
940 if (memcmp(match->uuid, cp->uuid, 16) != 0)
941 continue;
942
943 list_del(&match->list);
944 found++;
945 }
946
947 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200948 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
949 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200950 goto unlock;
951 }
952
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200953 err = update_class(hdev);
954 if (err < 0)
955 goto unlock;
956
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300957 err = update_eir(hdev);
958 if (err < 0)
959 goto unlock;
960
Szymon Janc4e51eae2011-02-25 19:05:48 +0100961 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200962
963unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300964 hci_dev_unlock(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200965 hci_dev_put(hdev);
966
967 return err;
968}
969
Szymon Janc4e51eae2011-02-25 19:05:48 +0100970static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
971 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200972{
973 struct hci_dev *hdev;
974 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200975 int err;
976
977 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200978
Szymon Janc4e51eae2011-02-25 19:05:48 +0100979 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200980
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100981 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200982 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
983 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100984
Szymon Janc4e51eae2011-02-25 19:05:48 +0100985 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200986 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200987 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
988 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200989
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -0300990 hci_dev_lock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200991
992 hdev->major_class = cp->major;
993 hdev->minor_class = cp->minor;
994
Johan Hedberg14c0b602011-12-15 00:47:37 +0200995 if (test_and_clear_bit(HCI_SERVICE_CACHE, &hdev->flags))
996 update_eir(hdev);
997
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200998 err = update_class(hdev);
999
1000 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001001 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001002
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001003 hci_dev_unlock(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001004 hci_dev_put(hdev);
1005
1006 return err;
1007}
1008
Johan Hedberg86742e12011-11-07 23:13:38 +02001009static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
1010 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001011{
1012 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001013 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001014 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001015 int i;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001016
1017 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001018
1019 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001020 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1021 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001022
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001023 key_count = get_unaligned_le16(&cp->key_count);
1024
Johan Hedberg86742e12011-11-07 23:13:38 +02001025 expected_len = sizeof(*cp) + key_count *
1026 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001027 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001028 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001029 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001030 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1031 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001032 }
1033
Szymon Janc4e51eae2011-02-25 19:05:48 +01001034 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001035 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001036 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1037 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001038
Szymon Janc4e51eae2011-02-25 19:05:48 +01001039 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001040 key_count);
1041
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001042 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001043
1044 hci_link_keys_clear(hdev);
1045
1046 set_bit(HCI_LINK_KEYS, &hdev->flags);
1047
1048 if (cp->debug_keys)
1049 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1050 else
1051 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1052
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001053 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001054 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001055
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001056 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001057 key->pin_len);
1058 }
1059
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001060 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1061
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001062 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001063 hci_dev_put(hdev);
1064
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001065 return 0;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001066}
1067
Johan Hedberg86742e12011-11-07 23:13:38 +02001068static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
1069 u16 len)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001070{
1071 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001072 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001073 struct mgmt_rp_remove_keys rp;
1074 struct hci_cp_disconnect dc;
1075 struct pending_cmd *cmd;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001076 struct hci_conn *conn;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001077 int err;
1078
1079 cp = (void *) data;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001080
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001081 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001082 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1083 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001084
Szymon Janc4e51eae2011-02-25 19:05:48 +01001085 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001086 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001087 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1088 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001089
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001090 hci_dev_lock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001091
Johan Hedberga8a1d192011-11-10 15:54:38 +02001092 memset(&rp, 0, sizeof(rp));
1093 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001094 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001095
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001096 err = hci_remove_link_key(hdev, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001097 if (err < 0) {
1098 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001099 goto unlock;
Johan Hedbergca69b792011-11-11 18:10:00 +02001100 }
Johan Hedberga8a1d192011-11-10 15:54:38 +02001101
1102 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1103 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1104 sizeof(rp));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001105 goto unlock;
1106 }
1107
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001108 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001109 if (!conn) {
1110 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1111 sizeof(rp));
1112 goto unlock;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001113 }
1114
Johan Hedberga8a1d192011-11-10 15:54:38 +02001115 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1116 if (!cmd) {
1117 err = -ENOMEM;
1118 goto unlock;
1119 }
1120
1121 put_unaligned_le16(conn->handle, &dc.handle);
1122 dc.reason = 0x13; /* Remote User Terminated Connection */
1123 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1124 if (err < 0)
1125 mgmt_pending_remove(cmd);
1126
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001127unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001128 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001129 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1130 sizeof(rp));
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001131 hci_dev_unlock(hdev);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02001132 hci_dev_put(hdev);
1133
1134 return err;
1135}
1136
Szymon Janc4e51eae2011-02-25 19:05:48 +01001137static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001138{
1139 struct hci_dev *hdev;
1140 struct mgmt_cp_disconnect *cp;
1141 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001142 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001143 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001144 int err;
1145
1146 BT_DBG("");
1147
1148 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001149
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001150 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001151 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1152 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001153
Szymon Janc4e51eae2011-02-25 19:05:48 +01001154 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001155 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001156 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1157 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001158
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001159 hci_dev_lock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001160
1161 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001162 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1163 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001164 goto failed;
1165 }
1166
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001167 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001168 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1169 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001170 goto failed;
1171 }
1172
1173 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001174 if (!conn)
1175 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1176
Johan Hedberg8962ee72011-01-20 12:40:27 +02001177 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001178 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1179 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001180 goto failed;
1181 }
1182
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001183 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001184 if (!cmd) {
1185 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001186 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001187 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001188
1189 put_unaligned_le16(conn->handle, &dc.handle);
1190 dc.reason = 0x13; /* Remote User Terminated Connection */
1191
1192 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1193 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001194 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001195
1196failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001197 hci_dev_unlock(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001198 hci_dev_put(hdev);
1199
1200 return err;
1201}
1202
Johan Hedberg48264f02011-11-09 13:58:58 +02001203static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001204{
1205 switch (link_type) {
1206 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001207 switch (addr_type) {
1208 case ADDR_LE_DEV_PUBLIC:
1209 return MGMT_ADDR_LE_PUBLIC;
1210 case ADDR_LE_DEV_RANDOM:
1211 return MGMT_ADDR_LE_RANDOM;
1212 default:
1213 return MGMT_ADDR_INVALID;
1214 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001215 case ACL_LINK:
1216 return MGMT_ADDR_BREDR;
1217 default:
1218 return MGMT_ADDR_INVALID;
1219 }
1220}
1221
Szymon Janc8ce62842011-03-01 16:55:32 +01001222static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001223{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001224 struct mgmt_rp_get_connections *rp;
1225 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001226 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001227 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001228 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001229 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001230 int i, err;
1231
1232 BT_DBG("");
1233
Szymon Janc4e51eae2011-02-25 19:05:48 +01001234 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001235 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001236 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1237 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001238
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001239 hci_dev_lock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001240
1241 count = 0;
1242 list_for_each(p, &hdev->conn_hash.list) {
1243 count++;
1244 }
1245
Johan Hedberg4c659c32011-11-07 23:13:39 +02001246 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001247 rp = kmalloc(rp_len, GFP_ATOMIC);
1248 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001249 err = -ENOMEM;
1250 goto unlock;
1251 }
1252
Johan Hedberg2784eb42011-01-21 13:56:35 +02001253 put_unaligned_le16(count, &rp->conn_count);
1254
Johan Hedberg2784eb42011-01-21 13:56:35 +02001255 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001256 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1257 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001258 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001259 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1260 continue;
1261 i++;
1262 }
1263
1264 /* Recalculate length in case of filtered SCO connections, etc */
1265 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001266
Szymon Janc4e51eae2011-02-25 19:05:48 +01001267 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001268
1269unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001270 kfree(rp);
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001271 hci_dev_unlock(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001272 hci_dev_put(hdev);
1273 return err;
1274}
1275
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001276static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1277 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1278{
1279 struct pending_cmd *cmd;
1280 int err;
1281
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001282 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001283 sizeof(*cp));
1284 if (!cmd)
1285 return -ENOMEM;
1286
1287 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1288 &cp->bdaddr);
1289 if (err < 0)
1290 mgmt_pending_remove(cmd);
1291
1292 return err;
1293}
1294
Szymon Janc4e51eae2011-02-25 19:05:48 +01001295static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1296 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001297{
1298 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001299 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001300 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001301 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001302 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001303 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001304 int err;
1305
1306 BT_DBG("");
1307
1308 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001309
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001310 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001311 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1312 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001313
Szymon Janc4e51eae2011-02-25 19:05:48 +01001314 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001315 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001316 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1317 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001318
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001319 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001320
1321 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001322 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1323 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001324 goto failed;
1325 }
1326
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001327 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1328 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001329 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1330 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001331 goto failed;
1332 }
1333
1334 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1335 bacpy(&ncp.bdaddr, &cp->bdaddr);
1336
1337 BT_ERR("PIN code is not 16 bytes long");
1338
1339 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1340 if (err >= 0)
1341 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001342 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001343
1344 goto failed;
1345 }
1346
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001347 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001348 if (!cmd) {
1349 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001350 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001351 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001352
1353 bacpy(&reply.bdaddr, &cp->bdaddr);
1354 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001355 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001356
1357 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1358 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001359 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001360
1361failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001362 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001363 hci_dev_put(hdev);
1364
1365 return err;
1366}
1367
Szymon Janc4e51eae2011-02-25 19:05:48 +01001368static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1369 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001370{
1371 struct hci_dev *hdev;
1372 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001373 int err;
1374
1375 BT_DBG("");
1376
1377 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001378
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001379 if (len != sizeof(*cp))
1380 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001381 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001382
Szymon Janc4e51eae2011-02-25 19:05:48 +01001383 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001384 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001385 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001386 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001387
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001388 hci_dev_lock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001389
1390 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001391 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001392 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001393 goto failed;
1394 }
1395
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001396 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001397
1398failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001399 hci_dev_unlock(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001400 hci_dev_put(hdev);
1401
1402 return err;
1403}
1404
Szymon Janc4e51eae2011-02-25 19:05:48 +01001405static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1406 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001407{
1408 struct hci_dev *hdev;
1409 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001410
1411 BT_DBG("");
1412
1413 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001414
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001415 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001416 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1417 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001418
Szymon Janc4e51eae2011-02-25 19:05:48 +01001419 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001420 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001421 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1422 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001423
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001424 hci_dev_lock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001425
1426 hdev->io_capability = cp->io_capability;
1427
1428 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001429 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001430
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001431 hci_dev_unlock(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001432 hci_dev_put(hdev);
1433
Szymon Janc4e51eae2011-02-25 19:05:48 +01001434 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001435}
1436
Johan Hedberge9a416b2011-02-19 12:05:56 -03001437static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1438{
1439 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001440 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001441
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001442 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001443 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1444 continue;
1445
Johan Hedberge9a416b2011-02-19 12:05:56 -03001446 if (cmd->user_data != conn)
1447 continue;
1448
1449 return cmd;
1450 }
1451
1452 return NULL;
1453}
1454
1455static void pairing_complete(struct pending_cmd *cmd, u8 status)
1456{
1457 struct mgmt_rp_pair_device rp;
1458 struct hci_conn *conn = cmd->user_data;
1459
Johan Hedbergba4e5642011-11-11 00:07:34 +02001460 bacpy(&rp.addr.bdaddr, &conn->dst);
1461 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001462 rp.status = status;
1463
Szymon Janc4e51eae2011-02-25 19:05:48 +01001464 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001465
1466 /* So we don't get further callbacks for this connection */
1467 conn->connect_cfm_cb = NULL;
1468 conn->security_cfm_cb = NULL;
1469 conn->disconn_cfm_cb = NULL;
1470
1471 hci_conn_put(conn);
1472
Johan Hedberga664b5b2011-02-19 12:06:02 -03001473 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001474}
1475
1476static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1477{
1478 struct pending_cmd *cmd;
1479
1480 BT_DBG("status %u", status);
1481
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001482 cmd = find_pairing(conn);
1483 if (!cmd)
1484 BT_DBG("Unable to find a pending command");
1485 else
1486 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001487}
1488
Szymon Janc4e51eae2011-02-25 19:05:48 +01001489static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001490{
1491 struct hci_dev *hdev;
1492 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001493 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001494 struct pending_cmd *cmd;
1495 u8 sec_level, auth_type;
1496 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001497 int err;
1498
1499 BT_DBG("");
1500
1501 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001502
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001503 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001504 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1505 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001506
Szymon Janc4e51eae2011-02-25 19:05:48 +01001507 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001508 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001509 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1510 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001511
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001512 hci_dev_lock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001513
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001514 sec_level = BT_SECURITY_MEDIUM;
1515 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001516 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001517 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001518 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001519
Johan Hedbergba4e5642011-11-11 00:07:34 +02001520 if (cp->addr.type == MGMT_ADDR_BREDR)
1521 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001522 auth_type);
1523 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001524 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001525 auth_type);
1526
Johan Hedberg1425acb2011-11-11 00:07:35 +02001527 memset(&rp, 0, sizeof(rp));
1528 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1529 rp.addr.type = cp->addr.type;
1530
Ville Tervo30e76272011-02-22 16:10:53 -03001531 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001532 rp.status = -PTR_ERR(conn);
1533 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1534 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001535 goto unlock;
1536 }
1537
1538 if (conn->connect_cfm_cb) {
1539 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001540 rp.status = EBUSY;
1541 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1542 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001543 goto unlock;
1544 }
1545
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001546 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001547 if (!cmd) {
1548 err = -ENOMEM;
1549 hci_conn_put(conn);
1550 goto unlock;
1551 }
1552
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001553 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001554 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001555 conn->connect_cfm_cb = pairing_complete_cb;
1556
Johan Hedberge9a416b2011-02-19 12:05:56 -03001557 conn->security_cfm_cb = pairing_complete_cb;
1558 conn->disconn_cfm_cb = pairing_complete_cb;
1559 conn->io_capability = cp->io_cap;
1560 cmd->user_data = conn;
1561
1562 if (conn->state == BT_CONNECTED &&
1563 hci_conn_security(conn, sec_level, auth_type))
1564 pairing_complete(cmd, 0);
1565
1566 err = 0;
1567
1568unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001569 hci_dev_unlock(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001570 hci_dev_put(hdev);
1571
1572 return err;
1573}
1574
Brian Gix0df4c182011-11-16 13:53:13 -08001575static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1576 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001577{
Johan Hedberga5c29682011-02-19 12:05:57 -03001578 struct pending_cmd *cmd;
1579 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001580 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001581 int err;
1582
Szymon Janc4e51eae2011-02-25 19:05:48 +01001583 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001584 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001585 return cmd_status(sk, index, mgmt_op,
1586 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001587
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001588 hci_dev_lock(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001589
Johan Hedberga5c29682011-02-19 12:05:57 -03001590 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001591 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1592 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001593 }
1594
Brian Gix47c15e22011-11-16 13:53:14 -08001595 /*
1596 * Check for an existing ACL link, if present pair via
1597 * HCI commands.
1598 *
1599 * If no ACL link is present, check for an LE link and if
1600 * present, pair via the SMP engine.
1601 *
1602 * If neither ACL nor LE links are present, fail with error.
1603 */
1604 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1605 if (!conn) {
1606 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1607 if (!conn) {
1608 err = cmd_status(sk, index, mgmt_op,
1609 MGMT_STATUS_NOT_CONNECTED);
1610 goto done;
1611 }
1612
1613 /* Continue with pairing via SMP */
1614
1615 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_SUCCESS);
1616 goto done;
1617 }
1618
Brian Gix0df4c182011-11-16 13:53:13 -08001619 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001620 if (!cmd) {
1621 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001622 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001623 }
1624
Brian Gix0df4c182011-11-16 13:53:13 -08001625 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001626 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1627 struct hci_cp_user_passkey_reply cp;
1628
1629 bacpy(&cp.bdaddr, bdaddr);
1630 cp.passkey = passkey;
1631 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1632 } else
1633 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1634
Johan Hedberga664b5b2011-02-19 12:06:02 -03001635 if (err < 0)
1636 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001637
Brian Gix0df4c182011-11-16 13:53:13 -08001638done:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001639 hci_dev_unlock(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001640 hci_dev_put(hdev);
1641
1642 return err;
1643}
1644
Brian Gix0df4c182011-11-16 13:53:13 -08001645static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1646{
1647 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1648
1649 BT_DBG("");
1650
1651 if (len != sizeof(*cp))
1652 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1653 MGMT_STATUS_INVALID_PARAMS);
1654
1655 return user_pairing_resp(sk, index, &cp->bdaddr,
1656 MGMT_OP_USER_CONFIRM_REPLY,
1657 HCI_OP_USER_CONFIRM_REPLY, 0);
1658}
1659
1660static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1661 u16 len)
1662{
1663 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1664
1665 BT_DBG("");
1666
1667 if (len != sizeof(*cp))
1668 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1669 MGMT_STATUS_INVALID_PARAMS);
1670
1671 return user_pairing_resp(sk, index, &cp->bdaddr,
1672 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1673 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1674}
1675
Brian Gix604086b2011-11-23 08:28:33 -08001676static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1677{
1678 struct mgmt_cp_user_passkey_reply *cp = (void *) data;
1679
1680 BT_DBG("");
1681
1682 if (len != sizeof(*cp))
1683 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1684 EINVAL);
1685
1686 return user_pairing_resp(sk, index, &cp->bdaddr,
1687 MGMT_OP_USER_PASSKEY_REPLY,
1688 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1689}
1690
1691static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1692 u16 len)
1693{
1694 struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data;
1695
1696 BT_DBG("");
1697
1698 if (len != sizeof(*cp))
1699 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1700 EINVAL);
1701
1702 return user_pairing_resp(sk, index, &cp->bdaddr,
1703 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1704 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1705}
1706
Johan Hedbergb312b1612011-03-16 14:29:37 +02001707static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1708 u16 len)
1709{
1710 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1711 struct hci_cp_write_local_name hci_cp;
1712 struct hci_dev *hdev;
1713 struct pending_cmd *cmd;
1714 int err;
1715
1716 BT_DBG("");
1717
1718 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001719 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1720 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001721
1722 hdev = hci_dev_get(index);
1723 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001724 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1725 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001726
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001727 hci_dev_lock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001728
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001729 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001730 if (!cmd) {
1731 err = -ENOMEM;
1732 goto failed;
1733 }
1734
1735 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1736 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1737 &hci_cp);
1738 if (err < 0)
1739 mgmt_pending_remove(cmd);
1740
1741failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001742 hci_dev_unlock(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001743 hci_dev_put(hdev);
1744
1745 return err;
1746}
1747
Szymon Jancc35938b2011-03-22 13:12:21 +01001748static int read_local_oob_data(struct sock *sk, u16 index)
1749{
1750 struct hci_dev *hdev;
1751 struct pending_cmd *cmd;
1752 int err;
1753
1754 BT_DBG("hci%u", index);
1755
1756 hdev = hci_dev_get(index);
1757 if (!hdev)
1758 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001759 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001760
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001761 hci_dev_lock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001762
1763 if (!test_bit(HCI_UP, &hdev->flags)) {
1764 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001765 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001766 goto unlock;
1767 }
1768
1769 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1770 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001771 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001772 goto unlock;
1773 }
1774
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001775 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001776 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1777 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001778 goto unlock;
1779 }
1780
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001781 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001782 if (!cmd) {
1783 err = -ENOMEM;
1784 goto unlock;
1785 }
1786
1787 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1788 if (err < 0)
1789 mgmt_pending_remove(cmd);
1790
1791unlock:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001792 hci_dev_unlock(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001793 hci_dev_put(hdev);
1794
1795 return err;
1796}
1797
Szymon Janc2763eda2011-03-22 13:12:22 +01001798static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1799 u16 len)
1800{
1801 struct hci_dev *hdev;
1802 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1803 int err;
1804
1805 BT_DBG("hci%u ", index);
1806
1807 if (len != sizeof(*cp))
1808 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001809 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001810
1811 hdev = hci_dev_get(index);
1812 if (!hdev)
1813 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001814 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001815
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001816 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001817
1818 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1819 cp->randomizer);
1820 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001821 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1822 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001823 else
1824 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1825 0);
1826
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001827 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001828 hci_dev_put(hdev);
1829
1830 return err;
1831}
1832
1833static int remove_remote_oob_data(struct sock *sk, u16 index,
1834 unsigned char *data, u16 len)
1835{
1836 struct hci_dev *hdev;
1837 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1838 int err;
1839
1840 BT_DBG("hci%u ", index);
1841
1842 if (len != sizeof(*cp))
1843 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001844 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001845
1846 hdev = hci_dev_get(index);
1847 if (!hdev)
1848 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001849 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001850
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001851 hci_dev_lock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001852
1853 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1854 if (err < 0)
1855 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001856 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001857 else
1858 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1859 NULL, 0);
1860
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001861 hci_dev_unlock(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001862 hci_dev_put(hdev);
1863
1864 return err;
1865}
1866
Johan Hedberg450dfda2011-11-12 11:58:22 +02001867static int start_discovery(struct sock *sk, u16 index,
1868 unsigned char *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001869{
Johan Hedberg450dfda2011-11-12 11:58:22 +02001870 struct mgmt_cp_start_discovery *cp = (void *) data;
Johan Hedberg14a53662011-04-27 10:29:56 -04001871 struct pending_cmd *cmd;
1872 struct hci_dev *hdev;
1873 int err;
1874
1875 BT_DBG("hci%u", index);
1876
Johan Hedberg450dfda2011-11-12 11:58:22 +02001877 if (len != sizeof(*cp))
1878 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1879 MGMT_STATUS_INVALID_PARAMS);
1880
Johan Hedberg14a53662011-04-27 10:29:56 -04001881 hdev = hci_dev_get(index);
1882 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001883 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1884 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001885
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001886 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001887
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001888 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001889 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1890 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001891 goto failed;
1892 }
1893
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001894 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001895 if (!cmd) {
1896 err = -ENOMEM;
1897 goto failed;
1898 }
1899
Andre Guedes2519a1f2011-11-07 11:45:24 -03001900 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001901 if (err < 0)
1902 mgmt_pending_remove(cmd);
1903
1904failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001905 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001906 hci_dev_put(hdev);
1907
1908 return err;
1909}
1910
1911static int stop_discovery(struct sock *sk, u16 index)
1912{
1913 struct hci_dev *hdev;
1914 struct pending_cmd *cmd;
1915 int err;
1916
1917 BT_DBG("hci%u", index);
1918
1919 hdev = hci_dev_get(index);
1920 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001921 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1922 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001923
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001924 hci_dev_lock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001925
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001926 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001927 if (!cmd) {
1928 err = -ENOMEM;
1929 goto failed;
1930 }
1931
Andre Guedes023d50492011-11-04 14:16:52 -03001932 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001933 if (err < 0)
1934 mgmt_pending_remove(cmd);
1935
1936failed:
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001937 hci_dev_unlock(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001938 hci_dev_put(hdev);
1939
1940 return err;
1941}
1942
Antti Julku7fbec222011-06-15 12:01:15 +03001943static int block_device(struct sock *sk, u16 index, unsigned char *data,
1944 u16 len)
1945{
1946 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001947 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001948 int err;
1949
1950 BT_DBG("hci%u", index);
1951
Antti Julku7fbec222011-06-15 12:01:15 +03001952 if (len != sizeof(*cp))
1953 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001954 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001955
1956 hdev = hci_dev_get(index);
1957 if (!hdev)
1958 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001959 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001960
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001961 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03001962
Antti Julku7fbec222011-06-15 12:01:15 +03001963 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001964 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001965 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1966 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03001967 else
1968 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1969 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001970
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001971 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001972 hci_dev_put(hdev);
1973
1974 return err;
1975}
1976
1977static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1978 u16 len)
1979{
1980 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001981 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001982 int err;
1983
1984 BT_DBG("hci%u", index);
1985
Antti Julku7fbec222011-06-15 12:01:15 +03001986 if (len != sizeof(*cp))
1987 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001988 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001989
1990 hdev = hci_dev_get(index);
1991 if (!hdev)
1992 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001993 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001994
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03001995 hci_dev_lock(hdev);
Antti Julku5e762442011-08-25 16:48:02 +03001996
Antti Julku7fbec222011-06-15 12:01:15 +03001997 err = hci_blacklist_del(hdev, &cp->bdaddr);
1998
1999 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02002000 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2001 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03002002 else
2003 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2004 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002005
Gustavo F. Padovan09fd0de2011-06-17 13:03:21 -03002006 hci_dev_unlock(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002007 hci_dev_put(hdev);
2008
2009 return err;
2010}
2011
Antti Julkuf6422ec2011-06-22 13:11:56 +03002012static int set_fast_connectable(struct sock *sk, u16 index,
2013 unsigned char *data, u16 len)
2014{
2015 struct hci_dev *hdev;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002016 struct mgmt_mode *cp = (void *) data;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002017 struct hci_cp_write_page_scan_activity acp;
2018 u8 type;
2019 int err;
2020
2021 BT_DBG("hci%u", index);
2022
2023 if (len != sizeof(*cp))
2024 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002025 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002026
2027 hdev = hci_dev_get(index);
2028 if (!hdev)
2029 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002030 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002031
2032 hci_dev_lock(hdev);
2033
Johan Hedbergf7c68692011-12-15 00:47:36 +02002034 if (cp->val) {
Antti Julkuf6422ec2011-06-22 13:11:56 +03002035 type = PAGE_SCAN_TYPE_INTERLACED;
2036 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2037 } else {
2038 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2039 acp.interval = 0x0800; /* default 1.28 sec page scan */
2040 }
2041
2042 acp.window = 0x0012; /* default 11.25 msec page scan window */
2043
2044 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2045 sizeof(acp), &acp);
2046 if (err < 0) {
2047 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002048 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002049 goto done;
2050 }
2051
2052 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2053 if (err < 0) {
2054 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002055 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002056 goto done;
2057 }
2058
2059 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2060 NULL, 0);
2061done:
2062 hci_dev_unlock(hdev);
2063 hci_dev_put(hdev);
2064
2065 return err;
2066}
2067
Johan Hedberg03811012010-12-08 00:21:06 +02002068int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2069{
2070 unsigned char *buf;
2071 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002072 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002073 int err;
2074
2075 BT_DBG("got %zu bytes", msglen);
2076
2077 if (msglen < sizeof(*hdr))
2078 return -EINVAL;
2079
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002080 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002081 if (!buf)
2082 return -ENOMEM;
2083
2084 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2085 err = -EFAULT;
2086 goto done;
2087 }
2088
2089 hdr = (struct mgmt_hdr *) buf;
2090 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002091 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002092 len = get_unaligned_le16(&hdr->len);
2093
2094 if (len != msglen - sizeof(*hdr)) {
2095 err = -EINVAL;
2096 goto done;
2097 }
2098
2099 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002100 case MGMT_OP_READ_VERSION:
2101 err = read_version(sk);
2102 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002103 case MGMT_OP_READ_INDEX_LIST:
2104 err = read_index_list(sk);
2105 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002106 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002107 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002108 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002109 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002110 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002111 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002112 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002113 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002114 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002115 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002116 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002117 break;
Johan Hedbergf7c68692011-12-15 00:47:36 +02002118 case MGMT_OP_SET_FAST_CONNECTABLE:
2119 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
2120 len);
2121 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002122 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002123 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002124 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002125 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002126 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002127 break;
2128 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002129 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002130 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002131 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002132 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002133 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002134 case MGMT_OP_LOAD_LINK_KEYS:
2135 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002136 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002137 case MGMT_OP_REMOVE_KEYS:
2138 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002139 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002140 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002141 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002142 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002143 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002144 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002145 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002146 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002147 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002148 break;
2149 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002150 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002151 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002152 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002153 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002154 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002155 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002156 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002157 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002158 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002159 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002160 break;
2161 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002162 err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr),
2163 len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002164 break;
Brian Gix604086b2011-11-23 08:28:33 -08002165 case MGMT_OP_USER_PASSKEY_REPLY:
2166 err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len);
2167 break;
2168 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
2169 err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr),
2170 len);
2171 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002172 case MGMT_OP_SET_LOCAL_NAME:
2173 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2174 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002175 case MGMT_OP_READ_LOCAL_OOB_DATA:
2176 err = read_local_oob_data(sk, index);
2177 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002178 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2179 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2180 break;
2181 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2182 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2183 len);
2184 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002185 case MGMT_OP_START_DISCOVERY:
Johan Hedberg450dfda2011-11-12 11:58:22 +02002186 err = start_discovery(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002187 break;
2188 case MGMT_OP_STOP_DISCOVERY:
2189 err = stop_discovery(sk, index);
2190 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002191 case MGMT_OP_BLOCK_DEVICE:
2192 err = block_device(sk, index, buf + sizeof(*hdr), len);
2193 break;
2194 case MGMT_OP_UNBLOCK_DEVICE:
2195 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
2196 break;
Johan Hedberg03811012010-12-08 00:21:06 +02002197 default:
2198 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002199 err = cmd_status(sk, index, opcode,
2200 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg03811012010-12-08 00:21:06 +02002201 break;
2202 }
2203
Johan Hedberge41d8b42010-12-13 21:07:03 +02002204 if (err < 0)
2205 goto done;
2206
Johan Hedberg03811012010-12-08 00:21:06 +02002207 err = msglen;
2208
2209done:
2210 kfree(buf);
2211 return err;
2212}
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002213
Johan Hedbergb24752f2011-11-03 14:40:33 +02002214static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2215{
2216 u8 *status = data;
2217
2218 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2219 mgmt_pending_remove(cmd);
2220}
2221
Johan Hedberg744cf192011-11-08 20:40:14 +02002222int mgmt_index_added(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002223{
Johan Hedberg744cf192011-11-08 20:40:14 +02002224 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002225}
2226
Johan Hedberg744cf192011-11-08 20:40:14 +02002227int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002228{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002229 u8 status = ENODEV;
2230
Johan Hedberg744cf192011-11-08 20:40:14 +02002231 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002232
Johan Hedberg744cf192011-11-08 20:40:14 +02002233 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002234}
2235
Johan Hedberg73f22f62010-12-29 16:00:25 +02002236struct cmd_lookup {
Johan Hedberg72a734e2010-12-30 00:38:22 +02002237 u8 val;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002238 struct sock *sk;
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002239 struct hci_dev *hdev;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002240};
2241
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002242static void settings_rsp(struct pending_cmd *cmd, void *data)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002243{
Johan Hedberg73f22f62010-12-29 16:00:25 +02002244 struct cmd_lookup *match = data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002245
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002246 send_settings_rsp(cmd->sk, cmd->opcode, match->hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002247
2248 list_del(&cmd->list);
2249
2250 if (match->sk == NULL) {
2251 match->sk = cmd->sk;
2252 sock_hold(match->sk);
2253 }
2254
2255 mgmt_pending_free(cmd);
Johan Hedbergc71e97b2010-12-13 21:07:07 +02002256}
Johan Hedberg5add6af2010-12-16 10:00:37 +02002257
Johan Hedberg744cf192011-11-08 20:40:14 +02002258int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg5add6af2010-12-16 10:00:37 +02002259{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002260 struct cmd_lookup match = { powered, NULL, hdev };
2261 __le32 ev;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002262 int ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002263
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002264 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
Johan Hedberg5add6af2010-12-16 10:00:37 +02002265
Johan Hedbergb24752f2011-11-03 14:40:33 +02002266 if (!powered) {
2267 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002268 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002269 }
2270
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002271 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002272
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002273 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
2274 match.sk);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002275
2276 if (match.sk)
2277 sock_put(match.sk);
2278
2279 return ret;
Johan Hedberg5add6af2010-12-16 10:00:37 +02002280}
Johan Hedberg73f22f62010-12-29 16:00:25 +02002281
Johan Hedberg744cf192011-11-08 20:40:14 +02002282int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg73f22f62010-12-29 16:00:25 +02002283{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002284 struct cmd_lookup match = { discoverable, NULL, hdev };
2285 __le32 ev;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002286 int ret;
2287
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002288 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, settings_rsp, &match);
Johan Hedberg72a734e2010-12-30 00:38:22 +02002289
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002290 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg73f22f62010-12-29 16:00:25 +02002291
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002292 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002293 match.sk);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002294 if (match.sk)
2295 sock_put(match.sk);
2296
2297 return ret;
2298}
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002299
Johan Hedberg744cf192011-11-08 20:40:14 +02002300int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002301{
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002302 __le32 ev;
2303 struct cmd_lookup match = { connectable, NULL, hdev };
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002304 int ret;
2305
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002306 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, settings_rsp,
2307 &match);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002308
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002309 ev = cpu_to_le32(get_current_settings(hdev));
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002310
Johan Hedberg69ab39e2011-12-15 00:47:35 +02002311 ret = mgmt_event(MGMT_EV_NEW_SETTINGS, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002312
2313 if (match.sk)
2314 sock_put(match.sk);
2315
2316 return ret;
2317}
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002318
Johan Hedberg744cf192011-11-08 20:40:14 +02002319int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002320{
Johan Hedbergca69b792011-11-11 18:10:00 +02002321 u8 mgmt_err = mgmt_status(status);
2322
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002323 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002324 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002325 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002326
2327 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002328 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002329 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002330
2331 return 0;
2332}
2333
Johan Hedberg744cf192011-11-08 20:40:14 +02002334int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2335 u8 persistent)
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002336{
Johan Hedberg86742e12011-11-07 23:13:38 +02002337 struct mgmt_ev_new_link_key ev;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002338
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002339 memset(&ev, 0, sizeof(ev));
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002340
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002341 ev.store_hint = persistent;
2342 bacpy(&ev.key.bdaddr, &key->bdaddr);
2343 ev.key.type = key->type;
2344 memcpy(ev.key.val, key->val, 16);
2345 ev.key.pin_len = key->pin_len;
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002346
Johan Hedberg744cf192011-11-08 20:40:14 +02002347 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg55ed8ca2011-01-17 14:41:05 +02002348}
Johan Hedbergf7520542011-01-20 12:34:39 +02002349
Johan Hedberg48264f02011-11-09 13:58:58 +02002350int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2351 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002352{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002353 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002354
Johan Hedbergf7520542011-01-20 12:34:39 +02002355 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002356 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002357
Johan Hedberg744cf192011-11-08 20:40:14 +02002358 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002359}
2360
Johan Hedberg8962ee72011-01-20 12:40:27 +02002361static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2362{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002363 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002364 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002365 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002366
Johan Hedberga38528f2011-01-22 06:46:43 +02002367 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002368 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002369
Szymon Janc4e51eae2011-02-25 19:05:48 +01002370 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002371
2372 *sk = cmd->sk;
2373 sock_hold(*sk);
2374
Johan Hedberga664b5b2011-02-19 12:06:02 -03002375 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002376}
2377
Johan Hedberga8a1d192011-11-10 15:54:38 +02002378static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2379{
2380 u8 *status = data;
2381 struct mgmt_cp_remove_keys *cp = cmd->param;
2382 struct mgmt_rp_remove_keys rp;
2383
2384 memset(&rp, 0, sizeof(rp));
2385 bacpy(&rp.bdaddr, &cp->bdaddr);
2386 if (status != NULL)
2387 rp.status = *status;
2388
2389 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2390 sizeof(rp));
2391
2392 mgmt_pending_remove(cmd);
2393}
2394
Johan Hedberg48264f02011-11-09 13:58:58 +02002395int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2396 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002397{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002398 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002399 struct sock *sk = NULL;
2400 int err;
2401
Johan Hedberg744cf192011-11-08 20:40:14 +02002402 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002403
Johan Hedbergf7520542011-01-20 12:34:39 +02002404 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002405 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002406
Johan Hedberg744cf192011-11-08 20:40:14 +02002407 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002408
2409 if (sk)
2410 sock_put(sk);
2411
Johan Hedberga8a1d192011-11-10 15:54:38 +02002412 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2413
Johan Hedberg8962ee72011-01-20 12:40:27 +02002414 return err;
2415}
2416
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002417int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002418{
2419 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002420 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002421 int err;
2422
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002423 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002424 if (!cmd)
2425 return -ENOENT;
2426
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002427 if (bdaddr) {
2428 struct mgmt_rp_disconnect rp;
2429
2430 bacpy(&rp.bdaddr, bdaddr);
2431 rp.status = status;
2432
2433 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2434 &rp, sizeof(rp));
2435 } else
2436 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002437 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002438
Johan Hedberga664b5b2011-02-19 12:06:02 -03002439 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002440
2441 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002442}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002443
Johan Hedberg48264f02011-11-09 13:58:58 +02002444int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2445 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002446{
2447 struct mgmt_ev_connect_failed ev;
2448
Johan Hedberg4c659c32011-11-07 23:13:39 +02002449 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002450 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002451 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002452
Johan Hedberg744cf192011-11-08 20:40:14 +02002453 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002454}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002455
Johan Hedberg744cf192011-11-08 20:40:14 +02002456int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002457{
2458 struct mgmt_ev_pin_code_request ev;
2459
Johan Hedberg980e1a52011-01-22 06:10:07 +02002460 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002461 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002462
Johan Hedberg744cf192011-11-08 20:40:14 +02002463 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002464 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002465}
2466
Johan Hedberg744cf192011-11-08 20:40:14 +02002467int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2468 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002469{
2470 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002471 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002472 int err;
2473
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002474 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002475 if (!cmd)
2476 return -ENOENT;
2477
Johan Hedbergac56fb12011-02-19 12:05:59 -03002478 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002479 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002480
Johan Hedberg744cf192011-11-08 20:40:14 +02002481 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002482 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002483
Johan Hedberga664b5b2011-02-19 12:06:02 -03002484 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002485
2486 return err;
2487}
2488
Johan Hedberg744cf192011-11-08 20:40:14 +02002489int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2490 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002491{
2492 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002493 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002494 int err;
2495
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002496 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002497 if (!cmd)
2498 return -ENOENT;
2499
Johan Hedbergac56fb12011-02-19 12:05:59 -03002500 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002501 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002502
Johan Hedberg744cf192011-11-08 20:40:14 +02002503 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002504 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002505
Johan Hedberga664b5b2011-02-19 12:06:02 -03002506 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002507
2508 return err;
2509}
Johan Hedberga5c29682011-02-19 12:05:57 -03002510
Johan Hedberg744cf192011-11-08 20:40:14 +02002511int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2512 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002513{
2514 struct mgmt_ev_user_confirm_request ev;
2515
Johan Hedberg744cf192011-11-08 20:40:14 +02002516 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002517
Johan Hedberga5c29682011-02-19 12:05:57 -03002518 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002519 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002520 put_unaligned_le32(value, &ev.value);
2521
Johan Hedberg744cf192011-11-08 20:40:14 +02002522 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002523 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002524}
2525
Brian Gix604086b2011-11-23 08:28:33 -08002526int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2527{
2528 struct mgmt_ev_user_passkey_request ev;
2529
2530 BT_DBG("%s", hdev->name);
2531
2532 bacpy(&ev.bdaddr, bdaddr);
2533
2534 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2535 NULL);
2536}
2537
Brian Gix0df4c182011-11-16 13:53:13 -08002538static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002539 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002540{
2541 struct pending_cmd *cmd;
2542 struct mgmt_rp_user_confirm_reply rp;
2543 int err;
2544
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002545 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002546 if (!cmd)
2547 return -ENOENT;
2548
Johan Hedberga5c29682011-02-19 12:05:57 -03002549 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002550 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002551 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002552
Johan Hedberga664b5b2011-02-19 12:06:02 -03002553 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002554
2555 return err;
2556}
2557
Johan Hedberg744cf192011-11-08 20:40:14 +02002558int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2559 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002560{
Brian Gix0df4c182011-11-16 13:53:13 -08002561 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002562 MGMT_OP_USER_CONFIRM_REPLY);
2563}
2564
Johan Hedberg744cf192011-11-08 20:40:14 +02002565int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2566 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002567{
Brian Gix0df4c182011-11-16 13:53:13 -08002568 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002569 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2570}
Johan Hedberg2a611692011-02-19 12:06:00 -03002571
Brian Gix604086b2011-11-23 08:28:33 -08002572int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2573 u8 status)
2574{
2575 return user_pairing_resp_complete(hdev, bdaddr, status,
2576 MGMT_OP_USER_PASSKEY_REPLY);
2577}
2578
2579int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2580 bdaddr_t *bdaddr, u8 status)
2581{
2582 return user_pairing_resp_complete(hdev, bdaddr, status,
2583 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2584}
2585
Johan Hedberg744cf192011-11-08 20:40:14 +02002586int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002587{
2588 struct mgmt_ev_auth_failed ev;
2589
Johan Hedberg2a611692011-02-19 12:06:00 -03002590 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002591 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002592
Johan Hedberg744cf192011-11-08 20:40:14 +02002593 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002594}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002595
Johan Hedberg744cf192011-11-08 20:40:14 +02002596int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002597{
2598 struct pending_cmd *cmd;
2599 struct mgmt_cp_set_local_name ev;
2600 int err;
2601
2602 memset(&ev, 0, sizeof(ev));
2603 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2604
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002605 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002606 if (!cmd)
2607 goto send_event;
2608
2609 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002610 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002611 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002612 goto failed;
2613 }
2614
Johan Hedberg744cf192011-11-08 20:40:14 +02002615 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002616
Johan Hedberg744cf192011-11-08 20:40:14 +02002617 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002618 sizeof(ev));
2619 if (err < 0)
2620 goto failed;
2621
2622send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002623 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002624 cmd ? cmd->sk : NULL);
2625
2626failed:
2627 if (cmd)
2628 mgmt_pending_remove(cmd);
2629 return err;
2630}
Szymon Jancc35938b2011-03-22 13:12:21 +01002631
Johan Hedberg744cf192011-11-08 20:40:14 +02002632int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2633 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002634{
2635 struct pending_cmd *cmd;
2636 int err;
2637
Johan Hedberg744cf192011-11-08 20:40:14 +02002638 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002639
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002640 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002641 if (!cmd)
2642 return -ENOENT;
2643
2644 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002645 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002646 MGMT_OP_READ_LOCAL_OOB_DATA,
2647 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002648 } else {
2649 struct mgmt_rp_read_local_oob_data rp;
2650
2651 memcpy(rp.hash, hash, sizeof(rp.hash));
2652 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2653
Johan Hedberg744cf192011-11-08 20:40:14 +02002654 err = cmd_complete(cmd->sk, hdev->id,
2655 MGMT_OP_READ_LOCAL_OOB_DATA,
2656 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002657 }
2658
2659 mgmt_pending_remove(cmd);
2660
2661 return err;
2662}
Johan Hedberge17acd42011-03-30 23:57:16 +03002663
Johan Hedberg48264f02011-11-09 13:58:58 +02002664int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2665 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002666{
2667 struct mgmt_ev_device_found ev;
2668
2669 memset(&ev, 0, sizeof(ev));
2670
Johan Hedberg4c659c32011-11-07 23:13:39 +02002671 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002672 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002673 ev.rssi = rssi;
2674
2675 if (eir)
2676 memcpy(ev.eir, eir, sizeof(ev.eir));
2677
Andre Guedesf8523592011-09-09 18:56:26 -03002678 if (dev_class)
2679 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2680
Johan Hedberg744cf192011-11-08 20:40:14 +02002681 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002682}
Johan Hedberga88a9652011-03-30 13:18:12 +03002683
Johan Hedberg744cf192011-11-08 20:40:14 +02002684int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002685{
2686 struct mgmt_ev_remote_name ev;
2687
2688 memset(&ev, 0, sizeof(ev));
2689
2690 bacpy(&ev.bdaddr, bdaddr);
2691 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2692
Johan Hedberg744cf192011-11-08 20:40:14 +02002693 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002694}
Johan Hedberg314b2382011-04-27 10:29:57 -04002695
Andre Guedes7a135102011-11-09 17:14:25 -03002696int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002697{
2698 struct pending_cmd *cmd;
2699 int err;
2700
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002701 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002702 if (!cmd)
2703 return -ENOENT;
2704
Johan Hedbergca69b792011-11-11 18:10:00 +02002705 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002706 mgmt_pending_remove(cmd);
2707
2708 return err;
2709}
2710
Andre Guedese6d465c2011-11-09 17:14:26 -03002711int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2712{
2713 struct pending_cmd *cmd;
2714 int err;
2715
2716 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2717 if (!cmd)
2718 return -ENOENT;
2719
2720 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
2721 mgmt_pending_remove(cmd);
2722
2723 return err;
2724}
2725
Johan Hedberg744cf192011-11-08 20:40:14 +02002726int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002727{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002728 struct pending_cmd *cmd;
2729
2730 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002731 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002732 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002733 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002734
2735 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002736 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002737 mgmt_pending_remove(cmd);
2738 }
2739
Johan Hedberg744cf192011-11-08 20:40:14 +02002740 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002741 sizeof(discovering), NULL);
2742}
Antti Julku5e762442011-08-25 16:48:02 +03002743
Johan Hedberg744cf192011-11-08 20:40:14 +02002744int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002745{
2746 struct pending_cmd *cmd;
2747 struct mgmt_ev_device_blocked ev;
2748
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002749 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002750
2751 bacpy(&ev.bdaddr, bdaddr);
2752
Johan Hedberg744cf192011-11-08 20:40:14 +02002753 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2754 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002755}
2756
Johan Hedberg744cf192011-11-08 20:40:14 +02002757int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002758{
2759 struct pending_cmd *cmd;
2760 struct mgmt_ev_device_unblocked ev;
2761
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002762 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002763
2764 bacpy(&ev.bdaddr, bdaddr);
2765
Johan Hedberg744cf192011-11-08 20:40:14 +02002766 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2767 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002768}