blob: 1ce549bae241809104194b8ed545a81c35821586 [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>
Paul Gortmaker3a9a2312011-05-27 09:12:25 -040027#include <linux/module.h>
Johan Hedberg03811012010-12-08 00:21:06 +020028#include <asm/unaligned.h>
29
30#include <net/bluetooth/bluetooth.h>
31#include <net/bluetooth/hci_core.h>
32#include <net/bluetooth/mgmt.h>
33
Johan Hedberg02d98122010-12-13 21:07:04 +020034#define MGMT_VERSION 0
35#define MGMT_REVISION 1
36
Andre Guedes2519a1f2011-11-07 11:45:24 -030037#define INQUIRY_LEN_BREDR 0x08 /* TGAP(100) */
38
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020039struct pending_cmd {
40 struct list_head list;
Johan Hedbergfc2f4b12011-11-09 13:58:56 +020041 u16 opcode;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020042 int index;
Szymon Jancc68fb7f2011-03-22 13:12:19 +010043 void *param;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020044 struct sock *sk;
Johan Hedberge9a416b2011-02-19 12:05:56 -030045 void *user_data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +020046};
47
Johan Hedbergca69b792011-11-11 18:10:00 +020048/* HCI to MGMT error code conversion table */
49static u8 mgmt_status_table[] = {
50 MGMT_STATUS_SUCCESS,
51 MGMT_STATUS_UNKNOWN_COMMAND, /* Unknown Command */
52 MGMT_STATUS_NOT_CONNECTED, /* No Connection */
53 MGMT_STATUS_FAILED, /* Hardware Failure */
54 MGMT_STATUS_CONNECT_FAILED, /* Page Timeout */
55 MGMT_STATUS_AUTH_FAILED, /* Authentication Failed */
56 MGMT_STATUS_NOT_PAIRED, /* PIN or Key Missing */
57 MGMT_STATUS_NO_RESOURCES, /* Memory Full */
58 MGMT_STATUS_TIMEOUT, /* Connection Timeout */
59 MGMT_STATUS_NO_RESOURCES, /* Max Number of Connections */
60 MGMT_STATUS_NO_RESOURCES, /* Max Number of SCO Connections */
61 MGMT_STATUS_ALREADY_CONNECTED, /* ACL Connection Exists */
62 MGMT_STATUS_BUSY, /* Command Disallowed */
63 MGMT_STATUS_NO_RESOURCES, /* Rejected Limited Resources */
64 MGMT_STATUS_REJECTED, /* Rejected Security */
65 MGMT_STATUS_REJECTED, /* Rejected Personal */
66 MGMT_STATUS_TIMEOUT, /* Host Timeout */
67 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Feature */
68 MGMT_STATUS_INVALID_PARAMS, /* Invalid Parameters */
69 MGMT_STATUS_DISCONNECTED, /* OE User Ended Connection */
70 MGMT_STATUS_NO_RESOURCES, /* OE Low Resources */
71 MGMT_STATUS_DISCONNECTED, /* OE Power Off */
72 MGMT_STATUS_DISCONNECTED, /* Connection Terminated */
73 MGMT_STATUS_BUSY, /* Repeated Attempts */
74 MGMT_STATUS_REJECTED, /* Pairing Not Allowed */
75 MGMT_STATUS_FAILED, /* Unknown LMP PDU */
76 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported Remote Feature */
77 MGMT_STATUS_REJECTED, /* SCO Offset Rejected */
78 MGMT_STATUS_REJECTED, /* SCO Interval Rejected */
79 MGMT_STATUS_REJECTED, /* Air Mode Rejected */
80 MGMT_STATUS_INVALID_PARAMS, /* Invalid LMP Parameters */
81 MGMT_STATUS_FAILED, /* Unspecified Error */
82 MGMT_STATUS_NOT_SUPPORTED, /* Unsupported LMP Parameter Value */
83 MGMT_STATUS_FAILED, /* Role Change Not Allowed */
84 MGMT_STATUS_TIMEOUT, /* LMP Response Timeout */
85 MGMT_STATUS_FAILED, /* LMP Error Transaction Collision */
86 MGMT_STATUS_FAILED, /* LMP PDU Not Allowed */
87 MGMT_STATUS_REJECTED, /* Encryption Mode Not Accepted */
88 MGMT_STATUS_FAILED, /* Unit Link Key Used */
89 MGMT_STATUS_NOT_SUPPORTED, /* QoS Not Supported */
90 MGMT_STATUS_TIMEOUT, /* Instant Passed */
91 MGMT_STATUS_NOT_SUPPORTED, /* Pairing Not Supported */
92 MGMT_STATUS_FAILED, /* Transaction Collision */
93 MGMT_STATUS_INVALID_PARAMS, /* Unacceptable Parameter */
94 MGMT_STATUS_REJECTED, /* QoS Rejected */
95 MGMT_STATUS_NOT_SUPPORTED, /* Classification Not Supported */
96 MGMT_STATUS_REJECTED, /* Insufficient Security */
97 MGMT_STATUS_INVALID_PARAMS, /* Parameter Out Of Range */
98 MGMT_STATUS_BUSY, /* Role Switch Pending */
99 MGMT_STATUS_FAILED, /* Slot Violation */
100 MGMT_STATUS_FAILED, /* Role Switch Failed */
101 MGMT_STATUS_INVALID_PARAMS, /* EIR Too Large */
102 MGMT_STATUS_NOT_SUPPORTED, /* Simple Pairing Not Supported */
103 MGMT_STATUS_BUSY, /* Host Busy Pairing */
104 MGMT_STATUS_REJECTED, /* Rejected, No Suitable Channel */
105 MGMT_STATUS_BUSY, /* Controller Busy */
106 MGMT_STATUS_INVALID_PARAMS, /* Unsuitable Connection Interval */
107 MGMT_STATUS_TIMEOUT, /* Directed Advertising Timeout */
108 MGMT_STATUS_AUTH_FAILED, /* Terminated Due to MIC Failure */
109 MGMT_STATUS_CONNECT_FAILED, /* Connection Establishment Failed */
110 MGMT_STATUS_CONNECT_FAILED, /* MAC Connection Failed */
111};
112
113static u8 mgmt_status(u8 hci_status)
114{
115 if (hci_status < ARRAY_SIZE(mgmt_status_table))
116 return mgmt_status_table[hci_status];
117
118 return MGMT_STATUS_FAILED;
119}
120
Szymon Janc4e51eae2011-02-25 19:05:48 +0100121static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200122{
123 struct sk_buff *skb;
124 struct mgmt_hdr *hdr;
125 struct mgmt_ev_cmd_status *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300126 int err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200127
Szymon Janc34eb5252011-02-28 14:10:08 +0100128 BT_DBG("sock %p, index %u, cmd %u, status %u", sk, index, cmd, status);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200129
130 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev), GFP_ATOMIC);
131 if (!skb)
132 return -ENOMEM;
133
134 hdr = (void *) skb_put(skb, sizeof(*hdr));
135
136 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100137 hdr->index = cpu_to_le16(index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200138 hdr->len = cpu_to_le16(sizeof(*ev));
139
140 ev = (void *) skb_put(skb, sizeof(*ev));
141 ev->status = status;
142 put_unaligned_le16(cmd, &ev->opcode);
143
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300144 err = sock_queue_rcv_skb(sk, skb);
145 if (err < 0)
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200146 kfree_skb(skb);
147
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300148 return err;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200149}
150
Szymon Janc4e51eae2011-02-25 19:05:48 +0100151static int cmd_complete(struct sock *sk, u16 index, u16 cmd, void *rp,
152 size_t rp_len)
Johan Hedberg02d98122010-12-13 21:07:04 +0200153{
154 struct sk_buff *skb;
155 struct mgmt_hdr *hdr;
156 struct mgmt_ev_cmd_complete *ev;
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300157 int err;
Johan Hedberg02d98122010-12-13 21:07:04 +0200158
159 BT_DBG("sock %p", sk);
160
Johan Hedberga38528f2011-01-22 06:46:43 +0200161 skb = alloc_skb(sizeof(*hdr) + sizeof(*ev) + rp_len, GFP_ATOMIC);
Johan Hedberg02d98122010-12-13 21:07:04 +0200162 if (!skb)
163 return -ENOMEM;
164
165 hdr = (void *) skb_put(skb, sizeof(*hdr));
Johan Hedberga38528f2011-01-22 06:46:43 +0200166
Johan Hedberg02d98122010-12-13 21:07:04 +0200167 hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
Szymon Janc4e51eae2011-02-25 19:05:48 +0100168 hdr->index = cpu_to_le16(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200169 hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200170
Johan Hedberga38528f2011-01-22 06:46:43 +0200171 ev = (void *) skb_put(skb, sizeof(*ev) + rp_len);
172 put_unaligned_le16(cmd, &ev->opcode);
Szymon Janc8020c162011-02-28 14:09:50 +0100173
174 if (rp)
175 memcpy(ev->data, rp, rp_len);
Johan Hedberg02d98122010-12-13 21:07:04 +0200176
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300177 err = sock_queue_rcv_skb(sk, skb);
178 if (err < 0)
Johan Hedberg02d98122010-12-13 21:07:04 +0200179 kfree_skb(skb);
180
Gustavo F. Padovan56b7d132011-10-14 19:20:01 -0300181 return err;;
Johan Hedberg02d98122010-12-13 21:07:04 +0200182}
183
Johan Hedberga38528f2011-01-22 06:46:43 +0200184static int read_version(struct sock *sk)
185{
186 struct mgmt_rp_read_version rp;
187
188 BT_DBG("sock %p", sk);
189
190 rp.version = MGMT_VERSION;
191 put_unaligned_le16(MGMT_REVISION, &rp.revision);
192
Szymon Janc4e51eae2011-02-25 19:05:48 +0100193 return cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_VERSION, &rp,
194 sizeof(rp));
Johan Hedberga38528f2011-01-22 06:46:43 +0200195}
196
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200197static int read_index_list(struct sock *sk)
198{
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200199 struct mgmt_rp_read_index_list *rp;
200 struct list_head *p;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200201 struct hci_dev *d;
Johan Hedberga38528f2011-01-22 06:46:43 +0200202 size_t rp_len;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200203 u16 count;
Johan Hedberga38528f2011-01-22 06:46:43 +0200204 int i, err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200205
206 BT_DBG("sock %p", sk);
207
208 read_lock(&hci_dev_list_lock);
209
210 count = 0;
211 list_for_each(p, &hci_dev_list) {
212 count++;
213 }
214
Johan Hedberga38528f2011-01-22 06:46:43 +0200215 rp_len = sizeof(*rp) + (2 * count);
216 rp = kmalloc(rp_len, GFP_ATOMIC);
217 if (!rp) {
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100218 read_unlock(&hci_dev_list_lock);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200219 return -ENOMEM;
Jesper Juhlb2c60d42011-01-14 00:18:49 +0100220 }
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200221
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200222 put_unaligned_le16(count, &rp->num_controllers);
223
224 i = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200225 list_for_each_entry(d, &hci_dev_list, list) {
Johan Hedberg32435532011-11-07 22:16:04 +0200226 if (test_and_clear_bit(HCI_AUTO_OFF, &d->flags))
Johan Hedberge0f93092011-11-09 01:44:22 +0200227 cancel_delayed_work(&d->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200228
229 if (test_bit(HCI_SETUP, &d->flags))
230 continue;
231
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200232 put_unaligned_le16(d->id, &rp->index[i++]);
233 BT_DBG("Added hci%u", d->id);
234 }
235
236 read_unlock(&hci_dev_list_lock);
237
Szymon Janc4e51eae2011-02-25 19:05:48 +0100238 err = cmd_complete(sk, MGMT_INDEX_NONE, MGMT_OP_READ_INDEX_LIST, rp,
239 rp_len);
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200240
Johan Hedberga38528f2011-01-22 06:46:43 +0200241 kfree(rp);
242
243 return err;
Johan Hedbergfaba42e2010-12-13 21:07:05 +0200244}
245
Szymon Janc4e51eae2011-02-25 19:05:48 +0100246static int read_controller_info(struct sock *sk, u16 index)
Johan Hedberg03811012010-12-08 00:21:06 +0200247{
Johan Hedberga38528f2011-01-22 06:46:43 +0200248 struct mgmt_rp_read_info rp;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200249 struct hci_dev *hdev;
Johan Hedberg03811012010-12-08 00:21:06 +0200250
Szymon Janc4e51eae2011-02-25 19:05:48 +0100251 BT_DBG("sock %p hci%u", sk, index);
Johan Hedberg03811012010-12-08 00:21:06 +0200252
Szymon Janc4e51eae2011-02-25 19:05:48 +0100253 hdev = hci_dev_get(index);
Johan Hedberga38528f2011-01-22 06:46:43 +0200254 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200255 return cmd_status(sk, index, MGMT_OP_READ_INFO,
256 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200257
Johan Hedberg32435532011-11-07 22:16:04 +0200258 if (test_and_clear_bit(HCI_AUTO_OFF, &hdev->flags))
259 cancel_delayed_work_sync(&hdev->power_off);
Johan Hedbergab81cbf2010-12-15 13:53:18 +0200260
Andre Guedes8c156c32011-07-07 10:30:36 -0300261 hci_dev_lock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200262
Johan Hedbergebc99fe2011-01-04 11:54:26 +0200263 set_bit(HCI_MGMT, &hdev->flags);
264
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200265 memset(&rp, 0, sizeof(rp));
266
Johan Hedberga38528f2011-01-22 06:46:43 +0200267 rp.type = hdev->dev_type;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200268
Johan Hedberga38528f2011-01-22 06:46:43 +0200269 rp.powered = test_bit(HCI_UP, &hdev->flags);
270 rp.connectable = test_bit(HCI_PSCAN, &hdev->flags);
271 rp.discoverable = test_bit(HCI_ISCAN, &hdev->flags);
272 rp.pairable = test_bit(HCI_PSCAN, &hdev->flags);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200273
274 if (test_bit(HCI_AUTH, &hdev->flags))
Johan Hedberga38528f2011-01-22 06:46:43 +0200275 rp.sec_mode = 3;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200276 else if (hdev->ssp_mode > 0)
Johan Hedberga38528f2011-01-22 06:46:43 +0200277 rp.sec_mode = 4;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200278 else
Johan Hedberga38528f2011-01-22 06:46:43 +0200279 rp.sec_mode = 2;
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200280
Johan Hedberga38528f2011-01-22 06:46:43 +0200281 bacpy(&rp.bdaddr, &hdev->bdaddr);
282 memcpy(rp.features, hdev->features, 8);
283 memcpy(rp.dev_class, hdev->dev_class, 3);
284 put_unaligned_le16(hdev->manufacturer, &rp.manufacturer);
285 rp.hci_ver = hdev->hci_ver;
286 put_unaligned_le16(hdev->hci_rev, &rp.hci_rev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200287
Johan Hedbergdc4fe302011-03-16 14:29:36 +0200288 memcpy(rp.name, hdev->dev_name, sizeof(hdev->dev_name));
289
Andre Guedes8c156c32011-07-07 10:30:36 -0300290 hci_dev_unlock_bh(hdev);
Johan Hedbergf7b64e62010-12-13 21:07:06 +0200291 hci_dev_put(hdev);
Johan Hedberg03811012010-12-08 00:21:06 +0200292
Szymon Janc4e51eae2011-02-25 19:05:48 +0100293 return cmd_complete(sk, index, MGMT_OP_READ_INFO, &rp, sizeof(rp));
Johan Hedberg03811012010-12-08 00:21:06 +0200294}
295
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200296static void mgmt_pending_free(struct pending_cmd *cmd)
297{
298 sock_put(cmd->sk);
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100299 kfree(cmd->param);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200300 kfree(cmd);
301}
302
Johan Hedberg366a0332011-02-19 12:05:55 -0300303static struct pending_cmd *mgmt_pending_add(struct sock *sk, u16 opcode,
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200304 struct hci_dev *hdev,
305 void *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200306{
307 struct pending_cmd *cmd;
308
309 cmd = kmalloc(sizeof(*cmd), GFP_ATOMIC);
310 if (!cmd)
Johan Hedberg366a0332011-02-19 12:05:55 -0300311 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200312
313 cmd->opcode = opcode;
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200314 cmd->index = hdev->id;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200315
Szymon Jancc68fb7f2011-03-22 13:12:19 +0100316 cmd->param = kmalloc(len, GFP_ATOMIC);
317 if (!cmd->param) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200318 kfree(cmd);
Johan Hedberg366a0332011-02-19 12:05:55 -0300319 return NULL;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200320 }
321
Szymon Janc8fce6352011-03-22 13:12:20 +0100322 if (data)
323 memcpy(cmd->param, data, len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200324
325 cmd->sk = sk;
326 sock_hold(sk);
327
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200328 list_add(&cmd->list, &hdev->mgmt_pending);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200329
Johan Hedberg366a0332011-02-19 12:05:55 -0300330 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200331}
332
Johan Hedberg744cf192011-11-08 20:40:14 +0200333static void mgmt_pending_foreach(u16 opcode, struct hci_dev *hdev,
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200334 void (*cb)(struct pending_cmd *cmd, void *data),
335 void *data)
336{
337 struct list_head *p, *n;
338
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200339 list_for_each_safe(p, n, &hdev->mgmt_pending) {
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200340 struct pending_cmd *cmd;
341
342 cmd = list_entry(p, struct pending_cmd, list);
343
Johan Hedbergb24752f2011-11-03 14:40:33 +0200344 if (opcode > 0 && cmd->opcode != opcode)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200345 continue;
346
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200347 cb(cmd, data);
348 }
349}
350
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200351static struct pending_cmd *mgmt_pending_find(u16 opcode, struct hci_dev *hdev)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200352{
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200353 struct pending_cmd *cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200354
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200355 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberg2aeabcb2011-11-09 13:58:57 +0200356 if (cmd->opcode == opcode)
357 return cmd;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200358 }
359
360 return NULL;
361}
362
Johan Hedberga664b5b2011-02-19 12:06:02 -0300363static void mgmt_pending_remove(struct pending_cmd *cmd)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200364{
Johan Hedberg73f22f62010-12-29 16:00:25 +0200365 list_del(&cmd->list);
366 mgmt_pending_free(cmd);
367}
368
Johan Hedberg86805702011-11-11 16:18:52 +0200369static int send_mode_rsp(struct sock *sk, u16 opcode, u16 index, u8 val)
370{
371 struct mgmt_mode rp;
372
373 rp.val = val;
374
375 return cmd_complete(sk, index, opcode, &rp, sizeof(rp));
376}
377
Szymon Janc4e51eae2011-02-25 19:05:48 +0100378static int set_powered(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200379{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200380 struct mgmt_mode *cp;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200381 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300382 struct pending_cmd *cmd;
Johan Hedberg366a0332011-02-19 12:05:55 -0300383 int err, up;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200384
385 cp = (void *) data;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200386
Szymon Janc4e51eae2011-02-25 19:05:48 +0100387 BT_DBG("request for hci%u", index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200388
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100389 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200390 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
391 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100392
Szymon Janc4e51eae2011-02-25 19:05:48 +0100393 hdev = hci_dev_get(index);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200394 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200395 return cmd_status(sk, index, MGMT_OP_SET_POWERED,
396 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200397
Andre Guedes8c156c32011-07-07 10:30:36 -0300398 hci_dev_lock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200399
400 up = test_bit(HCI_UP, &hdev->flags);
Johan Hedberg72a734e2010-12-30 00:38:22 +0200401 if ((cp->val && up) || (!cp->val && !up)) {
Johan Hedberg86805702011-11-11 16:18:52 +0200402 err = send_mode_rsp(sk, index, MGMT_OP_SET_POWERED, cp->val);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200403 goto failed;
404 }
405
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200406 if (mgmt_pending_find(MGMT_OP_SET_POWERED, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200407 err = cmd_status(sk, index, MGMT_OP_SET_POWERED,
408 MGMT_STATUS_BUSY);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200409 goto failed;
410 }
411
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200412 cmd = mgmt_pending_add(sk, MGMT_OP_SET_POWERED, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300413 if (!cmd) {
414 err = -ENOMEM;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200415 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300416 }
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200417
Johan Hedberg72a734e2010-12-30 00:38:22 +0200418 if (cp->val)
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200419 queue_work(hdev->workqueue, &hdev->power_on);
420 else
Johan Hedberg32435532011-11-07 22:16:04 +0200421 queue_work(hdev->workqueue, &hdev->power_off.work);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200422
Johan Hedberg366a0332011-02-19 12:05:55 -0300423 err = 0;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200424
425failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300426 hci_dev_unlock_bh(hdev);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200427 hci_dev_put(hdev);
Johan Hedberg366a0332011-02-19 12:05:55 -0300428 return err;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +0200429}
430
Szymon Janc4e51eae2011-02-25 19:05:48 +0100431static int set_discoverable(struct sock *sk, u16 index, unsigned char *data,
432 u16 len)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200433{
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200434 struct mgmt_cp_set_discoverable *cp;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200435 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300436 struct pending_cmd *cmd;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200437 u8 scan;
438 int err;
439
440 cp = (void *) data;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200441
Szymon Janc4e51eae2011-02-25 19:05:48 +0100442 BT_DBG("request for hci%u", index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200443
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100444 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200445 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
446 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100447
Szymon Janc4e51eae2011-02-25 19:05:48 +0100448 hdev = hci_dev_get(index);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200449 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200450 return cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
451 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200452
Andre Guedes8c156c32011-07-07 10:30:36 -0300453 hci_dev_lock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200454
455 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200456 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
457 MGMT_STATUS_NOT_POWERED);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200458 goto failed;
459 }
460
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200461 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
462 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200463 err = cmd_status(sk, index, MGMT_OP_SET_DISCOVERABLE,
464 MGMT_STATUS_BUSY);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200465 goto failed;
466 }
467
Johan Hedberg72a734e2010-12-30 00:38:22 +0200468 if (cp->val == test_bit(HCI_ISCAN, &hdev->flags) &&
Johan Hedberg73f22f62010-12-29 16:00:25 +0200469 test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg86805702011-11-11 16:18:52 +0200470 err = send_mode_rsp(sk, index, MGMT_OP_SET_DISCOVERABLE,
471 cp->val);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200472 goto failed;
473 }
474
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200475 cmd = mgmt_pending_add(sk, MGMT_OP_SET_DISCOVERABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300476 if (!cmd) {
477 err = -ENOMEM;
Johan Hedberg73f22f62010-12-29 16:00:25 +0200478 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300479 }
Johan Hedberg73f22f62010-12-29 16:00:25 +0200480
481 scan = SCAN_PAGE;
482
Johan Hedberg72a734e2010-12-30 00:38:22 +0200483 if (cp->val)
Johan Hedberg73f22f62010-12-29 16:00:25 +0200484 scan |= SCAN_INQUIRY;
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200485 else
Johan Hedberge0f93092011-11-09 01:44:22 +0200486 cancel_delayed_work(&hdev->discov_off);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200487
488 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
489 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300490 mgmt_pending_remove(cmd);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200491
Johan Hedberg16ab91a2011-11-07 22:16:02 +0200492 if (cp->val)
493 hdev->discov_timeout = get_unaligned_le16(&cp->timeout);
494
Johan Hedberg73f22f62010-12-29 16:00:25 +0200495failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300496 hci_dev_unlock_bh(hdev);
Johan Hedberg73f22f62010-12-29 16:00:25 +0200497 hci_dev_put(hdev);
498
499 return err;
500}
501
Szymon Janc4e51eae2011-02-25 19:05:48 +0100502static int set_connectable(struct sock *sk, u16 index, unsigned char *data,
503 u16 len)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200504{
Johan Hedberg72a734e2010-12-30 00:38:22 +0200505 struct mgmt_mode *cp;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200506 struct hci_dev *hdev;
Johan Hedberg366a0332011-02-19 12:05:55 -0300507 struct pending_cmd *cmd;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200508 u8 scan;
509 int err;
510
511 cp = (void *) data;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200512
Szymon Janc4e51eae2011-02-25 19:05:48 +0100513 BT_DBG("request for hci%u", index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200514
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100515 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200516 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
517 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100518
Szymon Janc4e51eae2011-02-25 19:05:48 +0100519 hdev = hci_dev_get(index);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200520 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200521 return cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
522 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200523
Andre Guedes8c156c32011-07-07 10:30:36 -0300524 hci_dev_lock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200525
526 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200527 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
528 MGMT_STATUS_NOT_POWERED);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200529 goto failed;
530 }
531
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200532 if (mgmt_pending_find(MGMT_OP_SET_DISCOVERABLE, hdev) ||
533 mgmt_pending_find(MGMT_OP_SET_CONNECTABLE, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200534 err = cmd_status(sk, index, MGMT_OP_SET_CONNECTABLE,
535 MGMT_STATUS_BUSY);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200536 goto failed;
537 }
538
Johan Hedberg72a734e2010-12-30 00:38:22 +0200539 if (cp->val == test_bit(HCI_PSCAN, &hdev->flags)) {
Johan Hedberg86805702011-11-11 16:18:52 +0200540 err = send_mode_rsp(sk, index, MGMT_OP_SET_CONNECTABLE,
541 cp->val);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200542 goto failed;
543 }
544
Johan Hedberg2e58ef32011-11-08 20:40:15 +0200545 cmd = mgmt_pending_add(sk, MGMT_OP_SET_CONNECTABLE, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -0300546 if (!cmd) {
547 err = -ENOMEM;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200548 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -0300549 }
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200550
Johan Hedberg72a734e2010-12-30 00:38:22 +0200551 if (cp->val)
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200552 scan = SCAN_PAGE;
553 else
554 scan = 0;
555
556 err = hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
557 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -0300558 mgmt_pending_remove(cmd);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200559
560failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300561 hci_dev_unlock_bh(hdev);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +0200562 hci_dev_put(hdev);
563
564 return err;
565}
566
Johan Hedberg744cf192011-11-08 20:40:14 +0200567static int mgmt_event(u16 event, struct hci_dev *hdev, void *data,
568 u16 data_len, struct sock *skip_sk)
Johan Hedbergc542a062011-01-26 13:11:03 +0200569{
570 struct sk_buff *skb;
571 struct mgmt_hdr *hdr;
572
573 skb = alloc_skb(sizeof(*hdr) + data_len, GFP_ATOMIC);
574 if (!skb)
575 return -ENOMEM;
576
577 bt_cb(skb)->channel = HCI_CHANNEL_CONTROL;
578
579 hdr = (void *) skb_put(skb, sizeof(*hdr));
580 hdr->opcode = cpu_to_le16(event);
Johan Hedberg744cf192011-11-08 20:40:14 +0200581 if (hdev)
582 hdr->index = cpu_to_le16(hdev->id);
583 else
584 hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
Johan Hedbergc542a062011-01-26 13:11:03 +0200585 hdr->len = cpu_to_le16(data_len);
586
Szymon Janc4e51eae2011-02-25 19:05:48 +0100587 if (data)
588 memcpy(skb_put(skb, data_len), data, data_len);
Johan Hedbergc542a062011-01-26 13:11:03 +0200589
590 hci_send_to_sock(NULL, skb, skip_sk);
591 kfree_skb(skb);
592
593 return 0;
594}
595
Szymon Janc4e51eae2011-02-25 19:05:48 +0100596static int set_pairable(struct sock *sk, u16 index, unsigned char *data,
597 u16 len)
Johan Hedbergc542a062011-01-26 13:11:03 +0200598{
599 struct mgmt_mode *cp, ev;
600 struct hci_dev *hdev;
Johan Hedbergc542a062011-01-26 13:11:03 +0200601 int err;
602
603 cp = (void *) data;
Johan Hedbergc542a062011-01-26 13:11:03 +0200604
Szymon Janc4e51eae2011-02-25 19:05:48 +0100605 BT_DBG("request for hci%u", index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200606
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100607 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200608 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
609 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100610
Szymon Janc4e51eae2011-02-25 19:05:48 +0100611 hdev = hci_dev_get(index);
Johan Hedbergc542a062011-01-26 13:11:03 +0200612 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200613 return cmd_status(sk, index, MGMT_OP_SET_PAIRABLE,
614 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergc542a062011-01-26 13:11:03 +0200615
Andre Guedes8c156c32011-07-07 10:30:36 -0300616 hci_dev_lock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200617
618 if (cp->val)
619 set_bit(HCI_PAIRABLE, &hdev->flags);
620 else
621 clear_bit(HCI_PAIRABLE, &hdev->flags);
622
Szymon Janc4e51eae2011-02-25 19:05:48 +0100623 err = send_mode_rsp(sk, MGMT_OP_SET_PAIRABLE, index, cp->val);
Johan Hedbergc542a062011-01-26 13:11:03 +0200624 if (err < 0)
625 goto failed;
626
Johan Hedbergc542a062011-01-26 13:11:03 +0200627 ev.val = cp->val;
628
Johan Hedberg744cf192011-11-08 20:40:14 +0200629 err = mgmt_event(MGMT_EV_PAIRABLE, hdev, &ev, sizeof(ev), sk);
Johan Hedbergc542a062011-01-26 13:11:03 +0200630
631failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300632 hci_dev_unlock_bh(hdev);
Johan Hedbergc542a062011-01-26 13:11:03 +0200633 hci_dev_put(hdev);
634
635 return err;
636}
637
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300638#define EIR_FLAGS 0x01 /* flags */
639#define EIR_UUID16_SOME 0x02 /* 16-bit UUID, more available */
640#define EIR_UUID16_ALL 0x03 /* 16-bit UUID, all listed */
641#define EIR_UUID32_SOME 0x04 /* 32-bit UUID, more available */
642#define EIR_UUID32_ALL 0x05 /* 32-bit UUID, all listed */
643#define EIR_UUID128_SOME 0x06 /* 128-bit UUID, more available */
644#define EIR_UUID128_ALL 0x07 /* 128-bit UUID, all listed */
645#define EIR_NAME_SHORT 0x08 /* shortened local name */
646#define EIR_NAME_COMPLETE 0x09 /* complete local name */
647#define EIR_TX_POWER 0x0A /* transmit power level */
648#define EIR_DEVICE_ID 0x10 /* device ID */
649
650#define PNP_INFO_SVCLASS_ID 0x1200
651
652static u8 bluetooth_base_uuid[] = {
653 0xFB, 0x34, 0x9B, 0x5F, 0x80, 0x00, 0x00, 0x80,
654 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
655};
656
657static u16 get_uuid16(u8 *uuid128)
658{
659 u32 val;
660 int i;
661
662 for (i = 0; i < 12; i++) {
663 if (bluetooth_base_uuid[i] != uuid128[i])
664 return 0;
665 }
666
667 memcpy(&val, &uuid128[12], 4);
668
669 val = le32_to_cpu(val);
670 if (val > 0xffff)
671 return 0;
672
673 return (u16) val;
674}
675
676static void create_eir(struct hci_dev *hdev, u8 *data)
677{
678 u8 *ptr = data;
679 u16 eir_len = 0;
680 u16 uuid16_list[HCI_MAX_EIR_LENGTH / sizeof(u16)];
681 int i, truncated = 0;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200682 struct bt_uuid *uuid;
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300683 size_t name_len;
684
685 name_len = strlen(hdev->dev_name);
686
687 if (name_len > 0) {
688 /* EIR Data type */
689 if (name_len > 48) {
690 name_len = 48;
691 ptr[1] = EIR_NAME_SHORT;
692 } else
693 ptr[1] = EIR_NAME_COMPLETE;
694
695 /* EIR Data length */
696 ptr[0] = name_len + 1;
697
698 memcpy(ptr + 2, hdev->dev_name, name_len);
699
700 eir_len += (name_len + 2);
701 ptr += (name_len + 2);
702 }
703
704 memset(uuid16_list, 0, sizeof(uuid16_list));
705
706 /* Group all UUID16 types */
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +0200707 list_for_each_entry(uuid, &hdev->uuids, list) {
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300708 u16 uuid16;
709
710 uuid16 = get_uuid16(uuid->uuid);
711 if (uuid16 == 0)
712 return;
713
714 if (uuid16 < 0x1100)
715 continue;
716
717 if (uuid16 == PNP_INFO_SVCLASS_ID)
718 continue;
719
720 /* Stop if not enough space to put next UUID */
721 if (eir_len + 2 + sizeof(u16) > HCI_MAX_EIR_LENGTH) {
722 truncated = 1;
723 break;
724 }
725
726 /* Check for duplicates */
727 for (i = 0; uuid16_list[i] != 0; i++)
728 if (uuid16_list[i] == uuid16)
729 break;
730
731 if (uuid16_list[i] == 0) {
732 uuid16_list[i] = uuid16;
733 eir_len += sizeof(u16);
734 }
735 }
736
737 if (uuid16_list[0] != 0) {
738 u8 *length = ptr;
739
740 /* EIR Data type */
741 ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
742
743 ptr += 2;
744 eir_len += 2;
745
746 for (i = 0; uuid16_list[i] != 0; i++) {
747 *ptr++ = (uuid16_list[i] & 0x00ff);
748 *ptr++ = (uuid16_list[i] & 0xff00) >> 8;
749 }
750
751 /* EIR Data length */
752 *length = (i * sizeof(u16)) + 1;
753 }
754}
755
756static int update_eir(struct hci_dev *hdev)
757{
758 struct hci_cp_write_eir cp;
759
760 if (!(hdev->features[6] & LMP_EXT_INQ))
761 return 0;
762
763 if (hdev->ssp_mode == 0)
764 return 0;
765
766 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
767 return 0;
768
769 memset(&cp, 0, sizeof(cp));
770
771 create_eir(hdev, cp.data);
772
773 if (memcmp(cp.data, hdev->eir, sizeof(cp.data)) == 0)
774 return 0;
775
776 memcpy(hdev->eir, cp.data, sizeof(cp.data));
777
778 return hci_send_cmd(hdev, HCI_OP_WRITE_EIR, sizeof(cp), &cp);
779}
780
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200781static u8 get_service_classes(struct hci_dev *hdev)
782{
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300783 struct bt_uuid *uuid;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200784 u8 val = 0;
785
Gustavo F. Padovan12dc0742011-10-14 19:32:56 -0300786 list_for_each_entry(uuid, &hdev->uuids, list)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200787 val |= uuid->svc_hint;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200788
789 return val;
790}
791
792static int update_class(struct hci_dev *hdev)
793{
794 u8 cod[3];
795
796 BT_DBG("%s", hdev->name);
797
798 if (test_bit(HCI_SERVICE_CACHE, &hdev->flags))
799 return 0;
800
801 cod[0] = hdev->minor_class;
802 cod[1] = hdev->major_class;
803 cod[2] = get_service_classes(hdev);
804
805 if (memcmp(cod, hdev->dev_class, 3) == 0)
806 return 0;
807
808 return hci_send_cmd(hdev, HCI_OP_WRITE_CLASS_OF_DEV, sizeof(cod), cod);
809}
810
Szymon Janc4e51eae2011-02-25 19:05:48 +0100811static int add_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200812{
813 struct mgmt_cp_add_uuid *cp;
814 struct hci_dev *hdev;
815 struct bt_uuid *uuid;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200816 int err;
817
818 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200819
Szymon Janc4e51eae2011-02-25 19:05:48 +0100820 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200821
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100822 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200823 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
824 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100825
Szymon Janc4e51eae2011-02-25 19:05:48 +0100826 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200827 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200828 return cmd_status(sk, index, MGMT_OP_ADD_UUID,
829 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200830
Andre Guedes8c156c32011-07-07 10:30:36 -0300831 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200832
833 uuid = kmalloc(sizeof(*uuid), GFP_ATOMIC);
834 if (!uuid) {
835 err = -ENOMEM;
836 goto failed;
837 }
838
839 memcpy(uuid->uuid, cp->uuid, 16);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200840 uuid->svc_hint = cp->svc_hint;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200841
842 list_add(&uuid->list, &hdev->uuids);
843
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200844 err = update_class(hdev);
845 if (err < 0)
846 goto failed;
847
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300848 err = update_eir(hdev);
849 if (err < 0)
850 goto failed;
851
Szymon Janc4e51eae2011-02-25 19:05:48 +0100852 err = cmd_complete(sk, index, MGMT_OP_ADD_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200853
854failed:
Andre Guedes8c156c32011-07-07 10:30:36 -0300855 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200856 hci_dev_put(hdev);
857
858 return err;
859}
860
Szymon Janc4e51eae2011-02-25 19:05:48 +0100861static int remove_uuid(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200862{
863 struct list_head *p, *n;
Szymon Janc779cb852011-02-25 19:05:47 +0100864 struct mgmt_cp_remove_uuid *cp;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200865 struct hci_dev *hdev;
866 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 +0200867 int err, found;
868
869 cp = (void *) data;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200870
Szymon Janc4e51eae2011-02-25 19:05:48 +0100871 BT_DBG("request for hci%u", index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200872
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100873 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200874 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
875 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100876
Szymon Janc4e51eae2011-02-25 19:05:48 +0100877 hdev = hci_dev_get(index);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200878 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200879 return cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
880 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200881
Andre Guedes8c156c32011-07-07 10:30:36 -0300882 hci_dev_lock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200883
884 if (memcmp(cp->uuid, bt_uuid_any, 16) == 0) {
885 err = hci_uuids_clear(hdev);
886 goto unlock;
887 }
888
889 found = 0;
890
891 list_for_each_safe(p, n, &hdev->uuids) {
892 struct bt_uuid *match = list_entry(p, struct bt_uuid, list);
893
894 if (memcmp(match->uuid, cp->uuid, 16) != 0)
895 continue;
896
897 list_del(&match->list);
898 found++;
899 }
900
901 if (found == 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +0200902 err = cmd_status(sk, index, MGMT_OP_REMOVE_UUID,
903 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200904 goto unlock;
905 }
906
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200907 err = update_class(hdev);
908 if (err < 0)
909 goto unlock;
910
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300911 err = update_eir(hdev);
912 if (err < 0)
913 goto unlock;
914
Szymon Janc4e51eae2011-02-25 19:05:48 +0100915 err = cmd_complete(sk, index, MGMT_OP_REMOVE_UUID, NULL, 0);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200916
917unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -0300918 hci_dev_unlock_bh(hdev);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +0200919 hci_dev_put(hdev);
920
921 return err;
922}
923
Szymon Janc4e51eae2011-02-25 19:05:48 +0100924static int set_dev_class(struct sock *sk, u16 index, unsigned char *data,
925 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200926{
927 struct hci_dev *hdev;
928 struct mgmt_cp_set_dev_class *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200929 int err;
930
931 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200932
Szymon Janc4e51eae2011-02-25 19:05:48 +0100933 BT_DBG("request for hci%u", index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200934
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100935 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200936 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
937 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100938
Szymon Janc4e51eae2011-02-25 19:05:48 +0100939 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200940 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200941 return cmd_status(sk, index, MGMT_OP_SET_DEV_CLASS,
942 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200943
Andre Guedes8c156c32011-07-07 10:30:36 -0300944 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200945
946 hdev->major_class = cp->major;
947 hdev->minor_class = cp->minor;
948
949 err = update_class(hdev);
950
951 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100952 err = cmd_complete(sk, index, MGMT_OP_SET_DEV_CLASS, NULL, 0);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200953
Andre Guedes8c156c32011-07-07 10:30:36 -0300954 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200955 hci_dev_put(hdev);
956
957 return err;
958}
959
Szymon Janc4e51eae2011-02-25 19:05:48 +0100960static int set_service_cache(struct sock *sk, u16 index, unsigned char *data,
961 u16 len)
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200962{
963 struct hci_dev *hdev;
964 struct mgmt_cp_set_service_cache *cp;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200965 int err;
966
967 cp = (void *) data;
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200968
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100969 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +0200970 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE,
971 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +0100972
Szymon Janc4e51eae2011-02-25 19:05:48 +0100973 hdev = hci_dev_get(index);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200974 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +0200975 return cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE,
976 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200977
Andre Guedes8c156c32011-07-07 10:30:36 -0300978 hci_dev_lock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200979
Szymon Janc4e51eae2011-02-25 19:05:48 +0100980 BT_DBG("hci%u enable %d", index, cp->enable);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200981
982 if (cp->enable) {
983 set_bit(HCI_SERVICE_CACHE, &hdev->flags);
984 err = 0;
985 } else {
986 clear_bit(HCI_SERVICE_CACHE, &hdev->flags);
987 err = update_class(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +0300988 if (err == 0)
989 err = update_eir(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200990 }
991
992 if (err == 0)
Szymon Janc4e51eae2011-02-25 19:05:48 +0100993 err = cmd_complete(sk, index, MGMT_OP_SET_SERVICE_CACHE, NULL,
994 0);
Gustavo F. Padovane5b82e52011-10-15 18:03:15 -0300995 else
996 cmd_status(sk, index, MGMT_OP_SET_SERVICE_CACHE, -err);
997
Johan Hedberg1aff6f02011-01-13 21:56:52 +0200998
Andre Guedes8c156c32011-07-07 10:30:36 -0300999 hci_dev_unlock_bh(hdev);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02001000 hci_dev_put(hdev);
1001
1002 return err;
1003}
1004
Johan Hedberg86742e12011-11-07 23:13:38 +02001005static int load_link_keys(struct sock *sk, u16 index, unsigned char *data,
1006 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001007{
1008 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001009 struct mgmt_cp_load_link_keys *cp;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001010 u16 key_count, expected_len;
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001011 int i;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001012
1013 cp = (void *) data;
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001014
1015 if (len < sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001016 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1017 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001018
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001019 key_count = get_unaligned_le16(&cp->key_count);
1020
Johan Hedberg86742e12011-11-07 23:13:38 +02001021 expected_len = sizeof(*cp) + key_count *
1022 sizeof(struct mgmt_link_key_info);
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001023 if (expected_len != len) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001024 BT_ERR("load_link_keys: expected %u bytes, got %u bytes",
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001025 len, expected_len);
Johan Hedbergca69b792011-11-11 18:10:00 +02001026 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1027 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001028 }
1029
Szymon Janc4e51eae2011-02-25 19:05:48 +01001030 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001031 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001032 return cmd_status(sk, index, MGMT_OP_LOAD_LINK_KEYS,
1033 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001034
Szymon Janc4e51eae2011-02-25 19:05:48 +01001035 BT_DBG("hci%u debug_keys %u key_count %u", index, cp->debug_keys,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001036 key_count);
1037
Andre Guedes8c156c32011-07-07 10:30:36 -03001038 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001039
1040 hci_link_keys_clear(hdev);
1041
1042 set_bit(HCI_LINK_KEYS, &hdev->flags);
1043
1044 if (cp->debug_keys)
1045 set_bit(HCI_DEBUG_KEYS, &hdev->flags);
1046 else
1047 clear_bit(HCI_DEBUG_KEYS, &hdev->flags);
1048
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001049 for (i = 0; i < key_count; i++) {
Johan Hedberg86742e12011-11-07 23:13:38 +02001050 struct mgmt_link_key_info *key = &cp->keys[i];
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001051
Johan Hedbergd25e28a2011-04-28 11:28:59 -07001052 hci_add_link_key(hdev, NULL, 0, &key->bdaddr, key->val, key->type,
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001053 key->pin_len);
1054 }
1055
Johan Hedberg0e5f8752011-11-11 16:18:54 +02001056 cmd_complete(sk, index, MGMT_OP_LOAD_LINK_KEYS, NULL, 0);
1057
Andre Guedes8c156c32011-07-07 10:30:36 -03001058 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001059 hci_dev_put(hdev);
1060
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03001061 return 0;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001062}
1063
Johan Hedberg86742e12011-11-07 23:13:38 +02001064static int remove_keys(struct sock *sk, u16 index, unsigned char *data,
1065 u16 len)
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001066{
1067 struct hci_dev *hdev;
Johan Hedberg86742e12011-11-07 23:13:38 +02001068 struct mgmt_cp_remove_keys *cp;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001069 struct mgmt_rp_remove_keys rp;
1070 struct hci_cp_disconnect dc;
1071 struct pending_cmd *cmd;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001072 struct hci_conn *conn;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001073 int err;
1074
1075 cp = (void *) data;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001076
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001077 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001078 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1079 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001080
Szymon Janc4e51eae2011-02-25 19:05:48 +01001081 hdev = hci_dev_get(index);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001082 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001083 return cmd_status(sk, index, MGMT_OP_REMOVE_KEYS,
1084 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001085
Andre Guedes8c156c32011-07-07 10:30:36 -03001086 hci_dev_lock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001087
Johan Hedberga8a1d192011-11-10 15:54:38 +02001088 memset(&rp, 0, sizeof(rp));
1089 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02001090 rp.status = MGMT_STATUS_FAILED;
Johan Hedberga8a1d192011-11-10 15:54:38 +02001091
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001092 err = hci_remove_link_key(hdev, &cp->bdaddr);
1093 if (err < 0) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001094 rp.status = MGMT_STATUS_NOT_PAIRED;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001095 goto unlock;
1096 }
1097
Johan Hedberga8a1d192011-11-10 15:54:38 +02001098 if (!test_bit(HCI_UP, &hdev->flags) || !cp->disconnect) {
1099 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1100 sizeof(rp));
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001101 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001102 }
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001103
1104 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Johan Hedberga8a1d192011-11-10 15:54:38 +02001105 if (!conn) {
1106 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1107 sizeof(rp));
1108 goto unlock;
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001109 }
1110
Johan Hedberga8a1d192011-11-10 15:54:38 +02001111 cmd = mgmt_pending_add(sk, MGMT_OP_REMOVE_KEYS, hdev, cp, sizeof(*cp));
1112 if (!cmd) {
1113 err = -ENOMEM;
1114 goto unlock;
1115 }
1116
1117 put_unaligned_le16(conn->handle, &dc.handle);
1118 dc.reason = 0x13; /* Remote User Terminated Connection */
1119 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1120 if (err < 0)
1121 mgmt_pending_remove(cmd);
1122
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001123unlock:
Johan Hedbergca69b792011-11-11 18:10:00 +02001124 if (err < 0)
Johan Hedberga8a1d192011-11-10 15:54:38 +02001125 err = cmd_complete(sk, index, MGMT_OP_REMOVE_KEYS, &rp,
1126 sizeof(rp));
Andre Guedes8c156c32011-07-07 10:30:36 -03001127 hci_dev_unlock_bh(hdev);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02001128 hci_dev_put(hdev);
1129
1130 return err;
1131}
1132
Szymon Janc4e51eae2011-02-25 19:05:48 +01001133static int disconnect(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberg8962ee72011-01-20 12:40:27 +02001134{
1135 struct hci_dev *hdev;
1136 struct mgmt_cp_disconnect *cp;
1137 struct hci_cp_disconnect dc;
Johan Hedberg366a0332011-02-19 12:05:55 -03001138 struct pending_cmd *cmd;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001139 struct hci_conn *conn;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001140 int err;
1141
1142 BT_DBG("");
1143
1144 cp = (void *) data;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001145
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001146 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001147 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1148 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001149
Szymon Janc4e51eae2011-02-25 19:05:48 +01001150 hdev = hci_dev_get(index);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001151 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001152 return cmd_status(sk, index, MGMT_OP_DISCONNECT,
1153 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001154
Andre Guedes8c156c32011-07-07 10:30:36 -03001155 hci_dev_lock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001156
1157 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001158 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1159 MGMT_STATUS_NOT_POWERED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001160 goto failed;
1161 }
1162
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001163 if (mgmt_pending_find(MGMT_OP_DISCONNECT, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001164 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1165 MGMT_STATUS_BUSY);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001166 goto failed;
1167 }
1168
1169 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
Vinicius Costa Gomes365227e2011-05-06 18:41:44 -03001170 if (!conn)
1171 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->bdaddr);
1172
Johan Hedberg8962ee72011-01-20 12:40:27 +02001173 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001174 err = cmd_status(sk, index, MGMT_OP_DISCONNECT,
1175 MGMT_STATUS_NOT_CONNECTED);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001176 goto failed;
1177 }
1178
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001179 cmd = mgmt_pending_add(sk, MGMT_OP_DISCONNECT, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001180 if (!cmd) {
1181 err = -ENOMEM;
Johan Hedberg8962ee72011-01-20 12:40:27 +02001182 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001183 }
Johan Hedberg8962ee72011-01-20 12:40:27 +02001184
1185 put_unaligned_le16(conn->handle, &dc.handle);
1186 dc.reason = 0x13; /* Remote User Terminated Connection */
1187
1188 err = hci_send_cmd(hdev, HCI_OP_DISCONNECT, sizeof(dc), &dc);
1189 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001190 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001191
1192failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001193 hci_dev_unlock_bh(hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02001194 hci_dev_put(hdev);
1195
1196 return err;
1197}
1198
Johan Hedberg48264f02011-11-09 13:58:58 +02001199static u8 link_to_mgmt(u8 link_type, u8 addr_type)
Johan Hedberg4c659c32011-11-07 23:13:39 +02001200{
1201 switch (link_type) {
1202 case LE_LINK:
Johan Hedberg48264f02011-11-09 13:58:58 +02001203 switch (addr_type) {
1204 case ADDR_LE_DEV_PUBLIC:
1205 return MGMT_ADDR_LE_PUBLIC;
1206 case ADDR_LE_DEV_RANDOM:
1207 return MGMT_ADDR_LE_RANDOM;
1208 default:
1209 return MGMT_ADDR_INVALID;
1210 }
Johan Hedberg4c659c32011-11-07 23:13:39 +02001211 case ACL_LINK:
1212 return MGMT_ADDR_BREDR;
1213 default:
1214 return MGMT_ADDR_INVALID;
1215 }
1216}
1217
Szymon Janc8ce62842011-03-01 16:55:32 +01001218static int get_connections(struct sock *sk, u16 index)
Johan Hedberg2784eb42011-01-21 13:56:35 +02001219{
Johan Hedberg2784eb42011-01-21 13:56:35 +02001220 struct mgmt_rp_get_connections *rp;
1221 struct hci_dev *hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001222 struct hci_conn *c;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001223 struct list_head *p;
Johan Hedberga38528f2011-01-22 06:46:43 +02001224 size_t rp_len;
Szymon Janc4e51eae2011-02-25 19:05:48 +01001225 u16 count;
Johan Hedberg2784eb42011-01-21 13:56:35 +02001226 int i, err;
1227
1228 BT_DBG("");
1229
Szymon Janc4e51eae2011-02-25 19:05:48 +01001230 hdev = hci_dev_get(index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001231 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001232 return cmd_status(sk, index, MGMT_OP_GET_CONNECTIONS,
1233 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001234
Andre Guedes8c156c32011-07-07 10:30:36 -03001235 hci_dev_lock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001236
1237 count = 0;
1238 list_for_each(p, &hdev->conn_hash.list) {
1239 count++;
1240 }
1241
Johan Hedberg4c659c32011-11-07 23:13:39 +02001242 rp_len = sizeof(*rp) + (count * sizeof(struct mgmt_addr_info));
Johan Hedberga38528f2011-01-22 06:46:43 +02001243 rp = kmalloc(rp_len, GFP_ATOMIC);
1244 if (!rp) {
Johan Hedberg2784eb42011-01-21 13:56:35 +02001245 err = -ENOMEM;
1246 goto unlock;
1247 }
1248
Johan Hedberg2784eb42011-01-21 13:56:35 +02001249 put_unaligned_le16(count, &rp->conn_count);
1250
Johan Hedberg2784eb42011-01-21 13:56:35 +02001251 i = 0;
Johan Hedberg4c659c32011-11-07 23:13:39 +02001252 list_for_each_entry(c, &hdev->conn_hash.list, list) {
1253 bacpy(&rp->addr[i].bdaddr, &c->dst);
Johan Hedberg48264f02011-11-09 13:58:58 +02001254 rp->addr[i].type = link_to_mgmt(c->type, c->dst_type);
Johan Hedberg4c659c32011-11-07 23:13:39 +02001255 if (rp->addr[i].type == MGMT_ADDR_INVALID)
1256 continue;
1257 i++;
1258 }
1259
1260 /* Recalculate length in case of filtered SCO connections, etc */
1261 rp_len = sizeof(*rp) + (i * sizeof(struct mgmt_addr_info));
Johan Hedberg2784eb42011-01-21 13:56:35 +02001262
Szymon Janc4e51eae2011-02-25 19:05:48 +01001263 err = cmd_complete(sk, index, MGMT_OP_GET_CONNECTIONS, rp, rp_len);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001264
1265unlock:
Johan Hedberga38528f2011-01-22 06:46:43 +02001266 kfree(rp);
Andre Guedes8c156c32011-07-07 10:30:36 -03001267 hci_dev_unlock_bh(hdev);
Johan Hedberg2784eb42011-01-21 13:56:35 +02001268 hci_dev_put(hdev);
1269 return err;
1270}
1271
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001272static int send_pin_code_neg_reply(struct sock *sk, u16 index,
1273 struct hci_dev *hdev, struct mgmt_cp_pin_code_neg_reply *cp)
1274{
1275 struct pending_cmd *cmd;
1276 int err;
1277
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001278 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_NEG_REPLY, hdev, cp,
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001279 sizeof(*cp));
1280 if (!cmd)
1281 return -ENOMEM;
1282
1283 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_NEG_REPLY, sizeof(cp->bdaddr),
1284 &cp->bdaddr);
1285 if (err < 0)
1286 mgmt_pending_remove(cmd);
1287
1288 return err;
1289}
1290
Szymon Janc4e51eae2011-02-25 19:05:48 +01001291static int pin_code_reply(struct sock *sk, u16 index, unsigned char *data,
1292 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001293{
1294 struct hci_dev *hdev;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001295 struct hci_conn *conn;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001296 struct mgmt_cp_pin_code_reply *cp;
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001297 struct mgmt_cp_pin_code_neg_reply ncp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001298 struct hci_cp_pin_code_reply reply;
Johan Hedberg366a0332011-02-19 12:05:55 -03001299 struct pending_cmd *cmd;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001300 int err;
1301
1302 BT_DBG("");
1303
1304 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001305
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001306 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001307 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1308 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001309
Szymon Janc4e51eae2011-02-25 19:05:48 +01001310 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001311 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001312 return cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1313 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001314
Andre Guedes8c156c32011-07-07 10:30:36 -03001315 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001316
1317 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001318 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1319 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001320 goto failed;
1321 }
1322
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001323 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
1324 if (!conn) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001325 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
1326 MGMT_STATUS_NOT_CONNECTED);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001327 goto failed;
1328 }
1329
1330 if (conn->pending_sec_level == BT_SECURITY_HIGH && cp->pin_len != 16) {
1331 bacpy(&ncp.bdaddr, &cp->bdaddr);
1332
1333 BT_ERR("PIN code is not 16 bytes long");
1334
1335 err = send_pin_code_neg_reply(sk, index, hdev, &ncp);
1336 if (err >= 0)
1337 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001338 MGMT_STATUS_INVALID_PARAMS);
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001339
1340 goto failed;
1341 }
1342
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001343 cmd = mgmt_pending_add(sk, MGMT_OP_PIN_CODE_REPLY, hdev, data, len);
Johan Hedberg366a0332011-02-19 12:05:55 -03001344 if (!cmd) {
1345 err = -ENOMEM;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001346 goto failed;
Johan Hedberg366a0332011-02-19 12:05:55 -03001347 }
Johan Hedberg980e1a52011-01-22 06:10:07 +02001348
1349 bacpy(&reply.bdaddr, &cp->bdaddr);
1350 reply.pin_len = cp->pin_len;
Waldemar Rymarkiewicz24718ca2011-06-01 17:28:47 +02001351 memcpy(reply.pin_code, cp->pin_code, sizeof(reply.pin_code));
Johan Hedberg980e1a52011-01-22 06:10:07 +02001352
1353 err = hci_send_cmd(hdev, HCI_OP_PIN_CODE_REPLY, sizeof(reply), &reply);
1354 if (err < 0)
Johan Hedberga664b5b2011-02-19 12:06:02 -03001355 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001356
1357failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001358 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001359 hci_dev_put(hdev);
1360
1361 return err;
1362}
1363
Szymon Janc4e51eae2011-02-25 19:05:48 +01001364static int pin_code_neg_reply(struct sock *sk, u16 index, unsigned char *data,
1365 u16 len)
Johan Hedberg980e1a52011-01-22 06:10:07 +02001366{
1367 struct hci_dev *hdev;
1368 struct mgmt_cp_pin_code_neg_reply *cp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001369 int err;
1370
1371 BT_DBG("");
1372
1373 cp = (void *) data;
Johan Hedberg980e1a52011-01-22 06:10:07 +02001374
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001375 if (len != sizeof(*cp))
1376 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001377 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001378
Szymon Janc4e51eae2011-02-25 19:05:48 +01001379 hdev = hci_dev_get(index);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001380 if (!hdev)
Szymon Janc4e51eae2011-02-25 19:05:48 +01001381 return cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001382 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001383
Andre Guedes8c156c32011-07-07 10:30:36 -03001384 hci_dev_lock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001385
1386 if (!test_bit(HCI_UP, &hdev->flags)) {
Szymon Janc4e51eae2011-02-25 19:05:48 +01001387 err = cmd_status(sk, index, MGMT_OP_PIN_CODE_NEG_REPLY,
Johan Hedbergca69b792011-11-11 18:10:00 +02001388 MGMT_STATUS_NOT_POWERED);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001389 goto failed;
1390 }
1391
Waldemar Rymarkiewicz96d97a62011-06-01 17:28:48 +02001392 err = send_pin_code_neg_reply(sk, index, hdev, cp);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001393
1394failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001395 hci_dev_unlock_bh(hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02001396 hci_dev_put(hdev);
1397
1398 return err;
1399}
1400
Szymon Janc4e51eae2011-02-25 19:05:48 +01001401static int set_io_capability(struct sock *sk, u16 index, unsigned char *data,
1402 u16 len)
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001403{
1404 struct hci_dev *hdev;
1405 struct mgmt_cp_set_io_capability *cp;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001406
1407 BT_DBG("");
1408
1409 cp = (void *) data;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001410
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001411 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001412 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1413 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001414
Szymon Janc4e51eae2011-02-25 19:05:48 +01001415 hdev = hci_dev_get(index);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001416 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001417 return cmd_status(sk, index, MGMT_OP_SET_IO_CAPABILITY,
1418 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001419
Andre Guedes8c156c32011-07-07 10:30:36 -03001420 hci_dev_lock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001421
1422 hdev->io_capability = cp->io_capability;
1423
1424 BT_DBG("%s IO capability set to 0x%02x", hdev->name,
Szymon Jancb8534e02011-03-01 16:55:34 +01001425 hdev->io_capability);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001426
Andre Guedes8c156c32011-07-07 10:30:36 -03001427 hci_dev_unlock_bh(hdev);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001428 hci_dev_put(hdev);
1429
Szymon Janc4e51eae2011-02-25 19:05:48 +01001430 return cmd_complete(sk, index, MGMT_OP_SET_IO_CAPABILITY, NULL, 0);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02001431}
1432
Johan Hedberge9a416b2011-02-19 12:05:56 -03001433static inline struct pending_cmd *find_pairing(struct hci_conn *conn)
1434{
1435 struct hci_dev *hdev = conn->hdev;
Luiz Augusto von Dentz8035ded2011-11-01 10:58:56 +02001436 struct pending_cmd *cmd;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001437
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001438 list_for_each_entry(cmd, &hdev->mgmt_pending, list) {
Johan Hedberge9a416b2011-02-19 12:05:56 -03001439 if (cmd->opcode != MGMT_OP_PAIR_DEVICE)
1440 continue;
1441
Johan Hedberge9a416b2011-02-19 12:05:56 -03001442 if (cmd->user_data != conn)
1443 continue;
1444
1445 return cmd;
1446 }
1447
1448 return NULL;
1449}
1450
1451static void pairing_complete(struct pending_cmd *cmd, u8 status)
1452{
1453 struct mgmt_rp_pair_device rp;
1454 struct hci_conn *conn = cmd->user_data;
1455
Johan Hedbergba4e5642011-11-11 00:07:34 +02001456 bacpy(&rp.addr.bdaddr, &conn->dst);
1457 rp.addr.type = link_to_mgmt(conn->type, conn->dst_type);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001458 rp.status = status;
1459
Szymon Janc4e51eae2011-02-25 19:05:48 +01001460 cmd_complete(cmd->sk, cmd->index, MGMT_OP_PAIR_DEVICE, &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001461
1462 /* So we don't get further callbacks for this connection */
1463 conn->connect_cfm_cb = NULL;
1464 conn->security_cfm_cb = NULL;
1465 conn->disconn_cfm_cb = NULL;
1466
1467 hci_conn_put(conn);
1468
Johan Hedberga664b5b2011-02-19 12:06:02 -03001469 mgmt_pending_remove(cmd);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001470}
1471
1472static void pairing_complete_cb(struct hci_conn *conn, u8 status)
1473{
1474 struct pending_cmd *cmd;
1475
1476 BT_DBG("status %u", status);
1477
Johan Hedberg56e5cb82011-11-08 20:40:16 +02001478 cmd = find_pairing(conn);
1479 if (!cmd)
1480 BT_DBG("Unable to find a pending command");
1481 else
1482 pairing_complete(cmd, status);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001483}
1484
Szymon Janc4e51eae2011-02-25 19:05:48 +01001485static int pair_device(struct sock *sk, u16 index, unsigned char *data, u16 len)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001486{
1487 struct hci_dev *hdev;
1488 struct mgmt_cp_pair_device *cp;
Johan Hedberg1425acb2011-11-11 00:07:35 +02001489 struct mgmt_rp_pair_device rp;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001490 struct pending_cmd *cmd;
1491 u8 sec_level, auth_type;
1492 struct hci_conn *conn;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001493 int err;
1494
1495 BT_DBG("");
1496
1497 cp = (void *) data;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001498
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001499 if (len != sizeof(*cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001500 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1501 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancbdce7ba2011-02-25 19:05:49 +01001502
Szymon Janc4e51eae2011-02-25 19:05:48 +01001503 hdev = hci_dev_get(index);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001504 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001505 return cmd_status(sk, index, MGMT_OP_PAIR_DEVICE,
1506 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001507
Andre Guedes8c156c32011-07-07 10:30:36 -03001508 hci_dev_lock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001509
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001510 sec_level = BT_SECURITY_MEDIUM;
1511 if (cp->io_cap == 0x03)
Johan Hedberge9a416b2011-02-19 12:05:56 -03001512 auth_type = HCI_AT_DEDICATED_BONDING;
Vinicius Costa Gomesc908df32011-09-02 14:51:22 -03001513 else
Johan Hedberge9a416b2011-02-19 12:05:56 -03001514 auth_type = HCI_AT_DEDICATED_BONDING_MITM;
Johan Hedberge9a416b2011-02-19 12:05:56 -03001515
Johan Hedbergba4e5642011-11-11 00:07:34 +02001516 if (cp->addr.type == MGMT_ADDR_BREDR)
1517 conn = hci_connect(hdev, ACL_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001518 auth_type);
1519 else
Johan Hedbergba4e5642011-11-11 00:07:34 +02001520 conn = hci_connect(hdev, LE_LINK, &cp->addr.bdaddr, sec_level,
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001521 auth_type);
1522
Johan Hedberg1425acb2011-11-11 00:07:35 +02001523 memset(&rp, 0, sizeof(rp));
1524 bacpy(&rp.addr.bdaddr, &cp->addr.bdaddr);
1525 rp.addr.type = cp->addr.type;
1526
Ville Tervo30e76272011-02-22 16:10:53 -03001527 if (IS_ERR(conn)) {
Johan Hedberg1425acb2011-11-11 00:07:35 +02001528 rp.status = -PTR_ERR(conn);
1529 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1530 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001531 goto unlock;
1532 }
1533
1534 if (conn->connect_cfm_cb) {
1535 hci_conn_put(conn);
Johan Hedberg1425acb2011-11-11 00:07:35 +02001536 rp.status = EBUSY;
1537 err = cmd_complete(sk, index, MGMT_OP_PAIR_DEVICE,
1538 &rp, sizeof(rp));
Johan Hedberge9a416b2011-02-19 12:05:56 -03001539 goto unlock;
1540 }
1541
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001542 cmd = mgmt_pending_add(sk, MGMT_OP_PAIR_DEVICE, hdev, data, len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001543 if (!cmd) {
1544 err = -ENOMEM;
1545 hci_conn_put(conn);
1546 goto unlock;
1547 }
1548
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001549 /* For LE, just connecting isn't a proof that the pairing finished */
Johan Hedbergba4e5642011-11-11 00:07:34 +02001550 if (cp->addr.type == MGMT_ADDR_BREDR)
Vinicius Costa Gomes7a512d02011-08-19 21:06:54 -03001551 conn->connect_cfm_cb = pairing_complete_cb;
1552
Johan Hedberge9a416b2011-02-19 12:05:56 -03001553 conn->security_cfm_cb = pairing_complete_cb;
1554 conn->disconn_cfm_cb = pairing_complete_cb;
1555 conn->io_capability = cp->io_cap;
1556 cmd->user_data = conn;
1557
1558 if (conn->state == BT_CONNECTED &&
1559 hci_conn_security(conn, sec_level, auth_type))
1560 pairing_complete(cmd, 0);
1561
1562 err = 0;
1563
1564unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001565 hci_dev_unlock_bh(hdev);
Johan Hedberge9a416b2011-02-19 12:05:56 -03001566 hci_dev_put(hdev);
1567
1568 return err;
1569}
1570
Brian Gix0df4c182011-11-16 13:53:13 -08001571static int user_pairing_resp(struct sock *sk, u16 index, bdaddr_t *bdaddr,
1572 u16 mgmt_op, u16 hci_op, __le32 passkey)
Johan Hedberga5c29682011-02-19 12:05:57 -03001573{
Johan Hedberga5c29682011-02-19 12:05:57 -03001574 struct pending_cmd *cmd;
1575 struct hci_dev *hdev;
Brian Gix0df4c182011-11-16 13:53:13 -08001576 struct hci_conn *conn;
Johan Hedberga5c29682011-02-19 12:05:57 -03001577 int err;
1578
Szymon Janc4e51eae2011-02-25 19:05:48 +01001579 hdev = hci_dev_get(index);
Johan Hedberga5c29682011-02-19 12:05:57 -03001580 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001581 return cmd_status(sk, index, mgmt_op,
1582 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberga5c29682011-02-19 12:05:57 -03001583
Andre Guedes8c156c32011-07-07 10:30:36 -03001584 hci_dev_lock_bh(hdev);
Johan Hedberg08ba5382011-03-16 14:29:34 +02001585
Johan Hedberga5c29682011-02-19 12:05:57 -03001586 if (!test_bit(HCI_UP, &hdev->flags)) {
Brian Gix0df4c182011-11-16 13:53:13 -08001587 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_NOT_POWERED);
1588 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001589 }
1590
Brian Gix47c15e22011-11-16 13:53:14 -08001591 /*
1592 * Check for an existing ACL link, if present pair via
1593 * HCI commands.
1594 *
1595 * If no ACL link is present, check for an LE link and if
1596 * present, pair via the SMP engine.
1597 *
1598 * If neither ACL nor LE links are present, fail with error.
1599 */
1600 conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, bdaddr);
1601 if (!conn) {
1602 conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, bdaddr);
1603 if (!conn) {
1604 err = cmd_status(sk, index, mgmt_op,
1605 MGMT_STATUS_NOT_CONNECTED);
1606 goto done;
1607 }
1608
1609 /* Continue with pairing via SMP */
1610
1611 err = cmd_status(sk, index, mgmt_op, MGMT_STATUS_SUCCESS);
1612 goto done;
1613 }
1614
Brian Gix0df4c182011-11-16 13:53:13 -08001615 cmd = mgmt_pending_add(sk, mgmt_op, hdev, bdaddr, sizeof(*bdaddr));
Johan Hedberga5c29682011-02-19 12:05:57 -03001616 if (!cmd) {
1617 err = -ENOMEM;
Brian Gix0df4c182011-11-16 13:53:13 -08001618 goto done;
Johan Hedberga5c29682011-02-19 12:05:57 -03001619 }
1620
Brian Gix0df4c182011-11-16 13:53:13 -08001621 /* Continue with pairing via HCI */
Brian Gix604086b2011-11-23 08:28:33 -08001622 if (hci_op == HCI_OP_USER_PASSKEY_REPLY) {
1623 struct hci_cp_user_passkey_reply cp;
1624
1625 bacpy(&cp.bdaddr, bdaddr);
1626 cp.passkey = passkey;
1627 err = hci_send_cmd(hdev, hci_op, sizeof(cp), &cp);
1628 } else
1629 err = hci_send_cmd(hdev, hci_op, sizeof(*bdaddr), bdaddr);
1630
Johan Hedberga664b5b2011-02-19 12:06:02 -03001631 if (err < 0)
1632 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03001633
Brian Gix0df4c182011-11-16 13:53:13 -08001634done:
Andre Guedes8c156c32011-07-07 10:30:36 -03001635 hci_dev_unlock_bh(hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03001636 hci_dev_put(hdev);
1637
1638 return err;
1639}
1640
Brian Gix0df4c182011-11-16 13:53:13 -08001641static int user_confirm_reply(struct sock *sk, u16 index, void *data, u16 len)
1642{
1643 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1644
1645 BT_DBG("");
1646
1647 if (len != sizeof(*cp))
1648 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_REPLY,
1649 MGMT_STATUS_INVALID_PARAMS);
1650
1651 return user_pairing_resp(sk, index, &cp->bdaddr,
1652 MGMT_OP_USER_CONFIRM_REPLY,
1653 HCI_OP_USER_CONFIRM_REPLY, 0);
1654}
1655
1656static int user_confirm_neg_reply(struct sock *sk, u16 index, void *data,
1657 u16 len)
1658{
1659 struct mgmt_cp_user_confirm_reply *cp = (void *) data;
1660
1661 BT_DBG("");
1662
1663 if (len != sizeof(*cp))
1664 return cmd_status(sk, index, MGMT_OP_USER_CONFIRM_NEG_REPLY,
1665 MGMT_STATUS_INVALID_PARAMS);
1666
1667 return user_pairing_resp(sk, index, &cp->bdaddr,
1668 MGMT_OP_USER_CONFIRM_NEG_REPLY,
1669 HCI_OP_USER_CONFIRM_NEG_REPLY, 0);
1670}
1671
Brian Gix604086b2011-11-23 08:28:33 -08001672static int user_passkey_reply(struct sock *sk, u16 index, void *data, u16 len)
1673{
1674 struct mgmt_cp_user_passkey_reply *cp = (void *) data;
1675
1676 BT_DBG("");
1677
1678 if (len != sizeof(*cp))
1679 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_REPLY,
1680 EINVAL);
1681
1682 return user_pairing_resp(sk, index, &cp->bdaddr,
1683 MGMT_OP_USER_PASSKEY_REPLY,
1684 HCI_OP_USER_PASSKEY_REPLY, cp->passkey);
1685}
1686
1687static int user_passkey_neg_reply(struct sock *sk, u16 index, void *data,
1688 u16 len)
1689{
1690 struct mgmt_cp_user_passkey_neg_reply *cp = (void *) data;
1691
1692 BT_DBG("");
1693
1694 if (len != sizeof(*cp))
1695 return cmd_status(sk, index, MGMT_OP_USER_PASSKEY_NEG_REPLY,
1696 EINVAL);
1697
1698 return user_pairing_resp(sk, index, &cp->bdaddr,
1699 MGMT_OP_USER_PASSKEY_NEG_REPLY,
1700 HCI_OP_USER_PASSKEY_NEG_REPLY, 0);
1701}
1702
Johan Hedbergb312b1612011-03-16 14:29:37 +02001703static int set_local_name(struct sock *sk, u16 index, unsigned char *data,
1704 u16 len)
1705{
1706 struct mgmt_cp_set_local_name *mgmt_cp = (void *) data;
1707 struct hci_cp_write_local_name hci_cp;
1708 struct hci_dev *hdev;
1709 struct pending_cmd *cmd;
1710 int err;
1711
1712 BT_DBG("");
1713
1714 if (len != sizeof(*mgmt_cp))
Johan Hedbergca69b792011-11-11 18:10:00 +02001715 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1716 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001717
1718 hdev = hci_dev_get(index);
1719 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001720 return cmd_status(sk, index, MGMT_OP_SET_LOCAL_NAME,
1721 MGMT_STATUS_INVALID_PARAMS);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001722
Andre Guedes8c156c32011-07-07 10:30:36 -03001723 hci_dev_lock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001724
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001725 cmd = mgmt_pending_add(sk, MGMT_OP_SET_LOCAL_NAME, hdev, data, len);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001726 if (!cmd) {
1727 err = -ENOMEM;
1728 goto failed;
1729 }
1730
1731 memcpy(hci_cp.name, mgmt_cp->name, sizeof(hci_cp.name));
1732 err = hci_send_cmd(hdev, HCI_OP_WRITE_LOCAL_NAME, sizeof(hci_cp),
1733 &hci_cp);
1734 if (err < 0)
1735 mgmt_pending_remove(cmd);
1736
1737failed:
Andre Guedes8c156c32011-07-07 10:30:36 -03001738 hci_dev_unlock_bh(hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02001739 hci_dev_put(hdev);
1740
1741 return err;
1742}
1743
Szymon Jancc35938b2011-03-22 13:12:21 +01001744static int read_local_oob_data(struct sock *sk, u16 index)
1745{
1746 struct hci_dev *hdev;
1747 struct pending_cmd *cmd;
1748 int err;
1749
1750 BT_DBG("hci%u", index);
1751
1752 hdev = hci_dev_get(index);
1753 if (!hdev)
1754 return cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001755 MGMT_STATUS_INVALID_PARAMS);
Szymon Jancc35938b2011-03-22 13:12:21 +01001756
Andre Guedes8c156c32011-07-07 10:30:36 -03001757 hci_dev_lock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001758
1759 if (!test_bit(HCI_UP, &hdev->flags)) {
1760 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001761 MGMT_STATUS_NOT_POWERED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001762 goto unlock;
1763 }
1764
1765 if (!(hdev->features[6] & LMP_SIMPLE_PAIR)) {
1766 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001767 MGMT_STATUS_NOT_SUPPORTED);
Szymon Jancc35938b2011-03-22 13:12:21 +01001768 goto unlock;
1769 }
1770
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001771 if (mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001772 err = cmd_status(sk, index, MGMT_OP_READ_LOCAL_OOB_DATA,
1773 MGMT_STATUS_BUSY);
Szymon Jancc35938b2011-03-22 13:12:21 +01001774 goto unlock;
1775 }
1776
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001777 cmd = mgmt_pending_add(sk, MGMT_OP_READ_LOCAL_OOB_DATA, hdev, NULL, 0);
Szymon Jancc35938b2011-03-22 13:12:21 +01001778 if (!cmd) {
1779 err = -ENOMEM;
1780 goto unlock;
1781 }
1782
1783 err = hci_send_cmd(hdev, HCI_OP_READ_LOCAL_OOB_DATA, 0, NULL);
1784 if (err < 0)
1785 mgmt_pending_remove(cmd);
1786
1787unlock:
Andre Guedes8c156c32011-07-07 10:30:36 -03001788 hci_dev_unlock_bh(hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01001789 hci_dev_put(hdev);
1790
1791 return err;
1792}
1793
Szymon Janc2763eda2011-03-22 13:12:22 +01001794static int add_remote_oob_data(struct sock *sk, u16 index, unsigned char *data,
1795 u16 len)
1796{
1797 struct hci_dev *hdev;
1798 struct mgmt_cp_add_remote_oob_data *cp = (void *) data;
1799 int err;
1800
1801 BT_DBG("hci%u ", index);
1802
1803 if (len != sizeof(*cp))
1804 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001805 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001806
1807 hdev = hci_dev_get(index);
1808 if (!hdev)
1809 return cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001810 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001811
Andre Guedes8c156c32011-07-07 10:30:36 -03001812 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001813
1814 err = hci_add_remote_oob_data(hdev, &cp->bdaddr, cp->hash,
1815 cp->randomizer);
1816 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001817 err = cmd_status(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA,
1818 MGMT_STATUS_FAILED);
Szymon Janc2763eda2011-03-22 13:12:22 +01001819 else
1820 err = cmd_complete(sk, index, MGMT_OP_ADD_REMOTE_OOB_DATA, NULL,
1821 0);
1822
Andre Guedes8c156c32011-07-07 10:30:36 -03001823 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001824 hci_dev_put(hdev);
1825
1826 return err;
1827}
1828
1829static int remove_remote_oob_data(struct sock *sk, u16 index,
1830 unsigned char *data, u16 len)
1831{
1832 struct hci_dev *hdev;
1833 struct mgmt_cp_remove_remote_oob_data *cp = (void *) data;
1834 int err;
1835
1836 BT_DBG("hci%u ", index);
1837
1838 if (len != sizeof(*cp))
1839 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001840 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001841
1842 hdev = hci_dev_get(index);
1843 if (!hdev)
1844 return cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001845 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001846
Andre Guedes8c156c32011-07-07 10:30:36 -03001847 hci_dev_lock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001848
1849 err = hci_remove_remote_oob_data(hdev, &cp->bdaddr);
1850 if (err < 0)
1851 err = cmd_status(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
Johan Hedbergca69b792011-11-11 18:10:00 +02001852 MGMT_STATUS_INVALID_PARAMS);
Szymon Janc2763eda2011-03-22 13:12:22 +01001853 else
1854 err = cmd_complete(sk, index, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
1855 NULL, 0);
1856
Andre Guedes8c156c32011-07-07 10:30:36 -03001857 hci_dev_unlock_bh(hdev);
Szymon Janc2763eda2011-03-22 13:12:22 +01001858 hci_dev_put(hdev);
1859
1860 return err;
1861}
1862
Johan Hedberg450dfda2011-11-12 11:58:22 +02001863static int start_discovery(struct sock *sk, u16 index,
1864 unsigned char *data, u16 len)
Johan Hedberg14a53662011-04-27 10:29:56 -04001865{
Johan Hedberg450dfda2011-11-12 11:58:22 +02001866 struct mgmt_cp_start_discovery *cp = (void *) data;
Johan Hedberg14a53662011-04-27 10:29:56 -04001867 struct pending_cmd *cmd;
1868 struct hci_dev *hdev;
1869 int err;
1870
1871 BT_DBG("hci%u", index);
1872
Johan Hedberg450dfda2011-11-12 11:58:22 +02001873 if (len != sizeof(*cp))
1874 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1875 MGMT_STATUS_INVALID_PARAMS);
1876
Johan Hedberg14a53662011-04-27 10:29:56 -04001877 hdev = hci_dev_get(index);
1878 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001879 return cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1880 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001881
1882 hci_dev_lock_bh(hdev);
1883
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001884 if (!test_bit(HCI_UP, &hdev->flags)) {
Johan Hedbergca69b792011-11-11 18:10:00 +02001885 err = cmd_status(sk, index, MGMT_OP_START_DISCOVERY,
1886 MGMT_STATUS_NOT_POWERED);
Johan Hedbergbd2d1332011-11-07 23:13:37 +02001887 goto failed;
1888 }
1889
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001890 cmd = mgmt_pending_add(sk, MGMT_OP_START_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001891 if (!cmd) {
1892 err = -ENOMEM;
1893 goto failed;
1894 }
1895
Andre Guedes2519a1f2011-11-07 11:45:24 -03001896 err = hci_do_inquiry(hdev, INQUIRY_LEN_BREDR);
Johan Hedberg14a53662011-04-27 10:29:56 -04001897 if (err < 0)
1898 mgmt_pending_remove(cmd);
1899
1900failed:
1901 hci_dev_unlock_bh(hdev);
1902 hci_dev_put(hdev);
1903
1904 return err;
1905}
1906
1907static int stop_discovery(struct sock *sk, u16 index)
1908{
1909 struct hci_dev *hdev;
1910 struct pending_cmd *cmd;
1911 int err;
1912
1913 BT_DBG("hci%u", index);
1914
1915 hdev = hci_dev_get(index);
1916 if (!hdev)
Johan Hedbergca69b792011-11-11 18:10:00 +02001917 return cmd_status(sk, index, MGMT_OP_STOP_DISCOVERY,
1918 MGMT_STATUS_INVALID_PARAMS);
Johan Hedberg14a53662011-04-27 10:29:56 -04001919
1920 hci_dev_lock_bh(hdev);
1921
Johan Hedberg2e58ef32011-11-08 20:40:15 +02001922 cmd = mgmt_pending_add(sk, MGMT_OP_STOP_DISCOVERY, hdev, NULL, 0);
Johan Hedberg14a53662011-04-27 10:29:56 -04001923 if (!cmd) {
1924 err = -ENOMEM;
1925 goto failed;
1926 }
1927
Andre Guedes023d50492011-11-04 14:16:52 -03001928 err = hci_cancel_inquiry(hdev);
Johan Hedberg14a53662011-04-27 10:29:56 -04001929 if (err < 0)
1930 mgmt_pending_remove(cmd);
1931
1932failed:
1933 hci_dev_unlock_bh(hdev);
1934 hci_dev_put(hdev);
1935
1936 return err;
1937}
1938
Antti Julku7fbec222011-06-15 12:01:15 +03001939static int block_device(struct sock *sk, u16 index, unsigned char *data,
1940 u16 len)
1941{
1942 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001943 struct mgmt_cp_block_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001944 int err;
1945
1946 BT_DBG("hci%u", index);
1947
Antti Julku7fbec222011-06-15 12:01:15 +03001948 if (len != sizeof(*cp))
1949 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001950 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001951
1952 hdev = hci_dev_get(index);
1953 if (!hdev)
1954 return cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001955 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001956
Antti Julku5e762442011-08-25 16:48:02 +03001957 hci_dev_lock_bh(hdev);
1958
Antti Julku7fbec222011-06-15 12:01:15 +03001959 err = hci_blacklist_add(hdev, &cp->bdaddr);
Antti Julku7fbec222011-06-15 12:01:15 +03001960 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001961 err = cmd_status(sk, index, MGMT_OP_BLOCK_DEVICE,
1962 MGMT_STATUS_FAILED);
Antti Julku7fbec222011-06-15 12:01:15 +03001963 else
1964 err = cmd_complete(sk, index, MGMT_OP_BLOCK_DEVICE,
1965 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03001966
Antti Julku5e762442011-08-25 16:48:02 +03001967 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03001968 hci_dev_put(hdev);
1969
1970 return err;
1971}
1972
1973static int unblock_device(struct sock *sk, u16 index, unsigned char *data,
1974 u16 len)
1975{
1976 struct hci_dev *hdev;
Antti Julku5e762442011-08-25 16:48:02 +03001977 struct mgmt_cp_unblock_device *cp = (void *) data;
Antti Julku7fbec222011-06-15 12:01:15 +03001978 int err;
1979
1980 BT_DBG("hci%u", index);
1981
Antti Julku7fbec222011-06-15 12:01:15 +03001982 if (len != sizeof(*cp))
1983 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001984 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001985
1986 hdev = hci_dev_get(index);
1987 if (!hdev)
1988 return cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
Johan Hedbergca69b792011-11-11 18:10:00 +02001989 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001990
Antti Julku5e762442011-08-25 16:48:02 +03001991 hci_dev_lock_bh(hdev);
1992
Antti Julku7fbec222011-06-15 12:01:15 +03001993 err = hci_blacklist_del(hdev, &cp->bdaddr);
1994
1995 if (err < 0)
Johan Hedbergca69b792011-11-11 18:10:00 +02001996 err = cmd_status(sk, index, MGMT_OP_UNBLOCK_DEVICE,
1997 MGMT_STATUS_INVALID_PARAMS);
Antti Julku7fbec222011-06-15 12:01:15 +03001998 else
1999 err = cmd_complete(sk, index, MGMT_OP_UNBLOCK_DEVICE,
2000 NULL, 0);
Antti Julku5e762442011-08-25 16:48:02 +03002001
Antti Julku5e762442011-08-25 16:48:02 +03002002 hci_dev_unlock_bh(hdev);
Antti Julku7fbec222011-06-15 12:01:15 +03002003 hci_dev_put(hdev);
2004
2005 return err;
2006}
2007
Antti Julkuf6422ec2011-06-22 13:11:56 +03002008static int set_fast_connectable(struct sock *sk, u16 index,
2009 unsigned char *data, u16 len)
2010{
2011 struct hci_dev *hdev;
2012 struct mgmt_cp_set_fast_connectable *cp = (void *) data;
2013 struct hci_cp_write_page_scan_activity acp;
2014 u8 type;
2015 int err;
2016
2017 BT_DBG("hci%u", index);
2018
2019 if (len != sizeof(*cp))
2020 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002021 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002022
2023 hdev = hci_dev_get(index);
2024 if (!hdev)
2025 return cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002026 MGMT_STATUS_INVALID_PARAMS);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002027
2028 hci_dev_lock(hdev);
2029
2030 if (cp->enable) {
2031 type = PAGE_SCAN_TYPE_INTERLACED;
2032 acp.interval = 0x0024; /* 22.5 msec page scan interval */
2033 } else {
2034 type = PAGE_SCAN_TYPE_STANDARD; /* default */
2035 acp.interval = 0x0800; /* default 1.28 sec page scan */
2036 }
2037
2038 acp.window = 0x0012; /* default 11.25 msec page scan window */
2039
2040 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_ACTIVITY,
2041 sizeof(acp), &acp);
2042 if (err < 0) {
2043 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002044 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002045 goto done;
2046 }
2047
2048 err = hci_send_cmd(hdev, HCI_OP_WRITE_PAGE_SCAN_TYPE, 1, &type);
2049 if (err < 0) {
2050 err = cmd_status(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
Johan Hedbergca69b792011-11-11 18:10:00 +02002051 MGMT_STATUS_FAILED);
Antti Julkuf6422ec2011-06-22 13:11:56 +03002052 goto done;
2053 }
2054
2055 err = cmd_complete(sk, index, MGMT_OP_SET_FAST_CONNECTABLE,
2056 NULL, 0);
2057done:
2058 hci_dev_unlock(hdev);
2059 hci_dev_put(hdev);
2060
2061 return err;
2062}
2063
Johan Hedberg03811012010-12-08 00:21:06 +02002064int mgmt_control(struct sock *sk, struct msghdr *msg, size_t msglen)
2065{
2066 unsigned char *buf;
2067 struct mgmt_hdr *hdr;
Szymon Janc4e51eae2011-02-25 19:05:48 +01002068 u16 opcode, index, len;
Johan Hedberg03811012010-12-08 00:21:06 +02002069 int err;
2070
2071 BT_DBG("got %zu bytes", msglen);
2072
2073 if (msglen < sizeof(*hdr))
2074 return -EINVAL;
2075
Gustavo F. Padovane63a15e2011-04-04 18:56:53 -03002076 buf = kmalloc(msglen, GFP_KERNEL);
Johan Hedberg03811012010-12-08 00:21:06 +02002077 if (!buf)
2078 return -ENOMEM;
2079
2080 if (memcpy_fromiovec(buf, msg->msg_iov, msglen)) {
2081 err = -EFAULT;
2082 goto done;
2083 }
2084
2085 hdr = (struct mgmt_hdr *) buf;
2086 opcode = get_unaligned_le16(&hdr->opcode);
Szymon Janc4e51eae2011-02-25 19:05:48 +01002087 index = get_unaligned_le16(&hdr->index);
Johan Hedberg03811012010-12-08 00:21:06 +02002088 len = get_unaligned_le16(&hdr->len);
2089
2090 if (len != msglen - sizeof(*hdr)) {
2091 err = -EINVAL;
2092 goto done;
2093 }
2094
2095 switch (opcode) {
Johan Hedberg02d98122010-12-13 21:07:04 +02002096 case MGMT_OP_READ_VERSION:
2097 err = read_version(sk);
2098 break;
Johan Hedbergfaba42e2010-12-13 21:07:05 +02002099 case MGMT_OP_READ_INDEX_LIST:
2100 err = read_index_list(sk);
2101 break;
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002102 case MGMT_OP_READ_INFO:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002103 err = read_controller_info(sk, index);
Johan Hedbergf7b64e62010-12-13 21:07:06 +02002104 break;
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002105 case MGMT_OP_SET_POWERED:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002106 err = set_powered(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergeec8d2b2010-12-16 10:17:38 +02002107 break;
Johan Hedberg73f22f62010-12-29 16:00:25 +02002108 case MGMT_OP_SET_DISCOVERABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002109 err = set_discoverable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg73f22f62010-12-29 16:00:25 +02002110 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002111 case MGMT_OP_SET_CONNECTABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002112 err = set_connectable(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002113 break;
Johan Hedbergc542a062011-01-26 13:11:03 +02002114 case MGMT_OP_SET_PAIRABLE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002115 err = set_pairable(sk, index, buf + sizeof(*hdr), len);
Johan Hedbergc542a062011-01-26 13:11:03 +02002116 break;
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002117 case MGMT_OP_ADD_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002118 err = add_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002119 break;
2120 case MGMT_OP_REMOVE_UUID:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002121 err = remove_uuid(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg2aeb9a12011-01-04 12:08:51 +02002122 break;
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002123 case MGMT_OP_SET_DEV_CLASS:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002124 err = set_dev_class(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002125 break;
2126 case MGMT_OP_SET_SERVICE_CACHE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002127 err = set_service_cache(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg1aff6f02011-01-13 21:56:52 +02002128 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002129 case MGMT_OP_LOAD_LINK_KEYS:
2130 err = load_link_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002131 break;
Johan Hedberg86742e12011-11-07 23:13:38 +02002132 case MGMT_OP_REMOVE_KEYS:
2133 err = remove_keys(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002134 break;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002135 case MGMT_OP_DISCONNECT:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002136 err = disconnect(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002137 break;
Johan Hedberg2784eb42011-01-21 13:56:35 +02002138 case MGMT_OP_GET_CONNECTIONS:
Szymon Janc8ce62842011-03-01 16:55:32 +01002139 err = get_connections(sk, index);
Johan Hedberg2784eb42011-01-21 13:56:35 +02002140 break;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002141 case MGMT_OP_PIN_CODE_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002142 err = pin_code_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002143 break;
2144 case MGMT_OP_PIN_CODE_NEG_REPLY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002145 err = pin_code_neg_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002146 break;
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002147 case MGMT_OP_SET_IO_CAPABILITY:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002148 err = set_io_capability(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg17fa4b92011-01-25 13:28:33 +02002149 break;
Johan Hedberge9a416b2011-02-19 12:05:56 -03002150 case MGMT_OP_PAIR_DEVICE:
Szymon Janc4e51eae2011-02-25 19:05:48 +01002151 err = pair_device(sk, index, buf + sizeof(*hdr), len);
Johan Hedberge9a416b2011-02-19 12:05:56 -03002152 break;
Johan Hedberga5c29682011-02-19 12:05:57 -03002153 case MGMT_OP_USER_CONFIRM_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002154 err = user_confirm_reply(sk, index, buf + sizeof(*hdr), len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002155 break;
2156 case MGMT_OP_USER_CONFIRM_NEG_REPLY:
Brian Gix0df4c182011-11-16 13:53:13 -08002157 err = user_confirm_neg_reply(sk, index, buf + sizeof(*hdr),
2158 len);
Johan Hedberga5c29682011-02-19 12:05:57 -03002159 break;
Brian Gix604086b2011-11-23 08:28:33 -08002160 case MGMT_OP_USER_PASSKEY_REPLY:
2161 err = user_passkey_reply(sk, index, buf + sizeof(*hdr), len);
2162 break;
2163 case MGMT_OP_USER_PASSKEY_NEG_REPLY:
2164 err = user_passkey_neg_reply(sk, index, buf + sizeof(*hdr),
2165 len);
Johan Hedberg55ed8ca12011-01-17 14:41:05 +02002166 break;
Johan Hedbergb312b1612011-03-16 14:29:37 +02002167 case MGMT_OP_SET_LOCAL_NAME:
2168 err = set_local_name(sk, index, buf + sizeof(*hdr), len);
2169 break;
Szymon Jancc35938b2011-03-22 13:12:21 +01002170 case MGMT_OP_READ_LOCAL_OOB_DATA:
2171 err = read_local_oob_data(sk, index);
2172 break;
Szymon Janc2763eda2011-03-22 13:12:22 +01002173 case MGMT_OP_ADD_REMOTE_OOB_DATA:
2174 err = add_remote_oob_data(sk, index, buf + sizeof(*hdr), len);
2175 break;
2176 case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
2177 err = remove_remote_oob_data(sk, index, buf + sizeof(*hdr),
2178 len);
2179 break;
Johan Hedberg14a53662011-04-27 10:29:56 -04002180 case MGMT_OP_START_DISCOVERY:
Johan Hedberg450dfda2011-11-12 11:58:22 +02002181 err = start_discovery(sk, index, buf + sizeof(*hdr), len);
Johan Hedberg14a53662011-04-27 10:29:56 -04002182 break;
2183 case MGMT_OP_STOP_DISCOVERY:
2184 err = stop_discovery(sk, index);
2185 break;
Antti Julku7fbec222011-06-15 12:01:15 +03002186 case MGMT_OP_BLOCK_DEVICE:
2187 err = block_device(sk, index, buf + sizeof(*hdr), len);
2188 break;
2189 case MGMT_OP_UNBLOCK_DEVICE:
2190 err = unblock_device(sk, index, buf + sizeof(*hdr), len);
2191 break;
Antti Julkuf6422ec2011-06-22 13:11:56 +03002192 case MGMT_OP_SET_FAST_CONNECTABLE:
2193 err = set_fast_connectable(sk, index, buf + sizeof(*hdr),
2194 len);
2195 break;
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002196 default:
Johan Hedberg72a734e2010-12-30 00:38:22 +02002197 BT_DBG("Unknown op %u", opcode);
Johan Hedbergca69b792011-11-11 18:10:00 +02002198 err = cmd_status(sk, index, opcode,
2199 MGMT_STATUS_UNKNOWN_COMMAND);
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002200 break;
2201 }
Johan Hedberg72a734e2010-12-30 00:38:22 +02002202
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002203 if (err < 0)
Johan Hedberg72a734e2010-12-30 00:38:22 +02002204 goto done;
2205
Johan Hedberg9fbcbb42010-12-30 00:18:33 +02002206 err = msglen;
2207
2208done:
2209 kfree(buf);
2210 return err;
2211}
2212
Johan Hedbergb24752f2011-11-03 14:40:33 +02002213static void cmd_status_rsp(struct pending_cmd *cmd, void *data)
2214{
2215 u8 *status = data;
2216
2217 cmd_status(cmd->sk, cmd->index, cmd->opcode, *status);
2218 mgmt_pending_remove(cmd);
2219}
2220
Johan Hedberg744cf192011-11-08 20:40:14 +02002221int mgmt_index_added(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002222{
Johan Hedberg744cf192011-11-08 20:40:14 +02002223 return mgmt_event(MGMT_EV_INDEX_ADDED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002224}
2225
Johan Hedberg744cf192011-11-08 20:40:14 +02002226int mgmt_index_removed(struct hci_dev *hdev)
Johan Hedberg03811012010-12-08 00:21:06 +02002227{
Johan Hedbergb24752f2011-11-03 14:40:33 +02002228 u8 status = ENODEV;
2229
Johan Hedberg744cf192011-11-08 20:40:14 +02002230 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002231
Johan Hedberg744cf192011-11-08 20:40:14 +02002232 return mgmt_event(MGMT_EV_INDEX_REMOVED, hdev, NULL, 0, NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002233}
2234
2235struct cmd_lookup {
2236 u8 val;
2237 struct sock *sk;
2238};
2239
2240static void mode_rsp(struct pending_cmd *cmd, void *data)
2241{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002242 struct mgmt_mode *cp = cmd->param;
Johan Hedberg03811012010-12-08 00:21:06 +02002243 struct cmd_lookup *match = data;
2244
2245 if (cp->val != match->val)
2246 return;
2247
2248 send_mode_rsp(cmd->sk, cmd->opcode, cmd->index, cp->val);
2249
2250 list_del(&cmd->list);
2251
2252 if (match->sk == NULL) {
2253 match->sk = cmd->sk;
2254 sock_hold(match->sk);
2255 }
2256
2257 mgmt_pending_free(cmd);
2258}
2259
Johan Hedberg744cf192011-11-08 20:40:14 +02002260int mgmt_powered(struct hci_dev *hdev, u8 powered)
Johan Hedberg03811012010-12-08 00:21:06 +02002261{
2262 struct mgmt_mode ev;
2263 struct cmd_lookup match = { powered, NULL };
2264 int ret;
2265
Johan Hedberg744cf192011-11-08 20:40:14 +02002266 mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, mode_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002267
Johan Hedbergb24752f2011-11-03 14:40:33 +02002268 if (!powered) {
2269 u8 status = ENETDOWN;
Johan Hedberg744cf192011-11-08 20:40:14 +02002270 mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
Johan Hedbergb24752f2011-11-03 14:40:33 +02002271 }
2272
Johan Hedberg03811012010-12-08 00:21:06 +02002273 ev.val = powered;
2274
Johan Hedberg744cf192011-11-08 20:40:14 +02002275 ret = mgmt_event(MGMT_EV_POWERED, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002276
2277 if (match.sk)
2278 sock_put(match.sk);
2279
2280 return ret;
2281}
2282
Johan Hedberg744cf192011-11-08 20:40:14 +02002283int mgmt_discoverable(struct hci_dev *hdev, u8 discoverable)
Johan Hedberg03811012010-12-08 00:21:06 +02002284{
2285 struct mgmt_mode ev;
2286 struct cmd_lookup match = { discoverable, NULL };
2287 int ret;
2288
Johan Hedberg744cf192011-11-08 20:40:14 +02002289 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev, mode_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002290
Johan Hedberg03811012010-12-08 00:21:06 +02002291 ev.val = discoverable;
2292
Johan Hedberg744cf192011-11-08 20:40:14 +02002293 ret = mgmt_event(MGMT_EV_DISCOVERABLE, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002294 match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002295
2296 if (match.sk)
2297 sock_put(match.sk);
2298
2299 return ret;
2300}
2301
Johan Hedberg744cf192011-11-08 20:40:14 +02002302int mgmt_connectable(struct hci_dev *hdev, u8 connectable)
Johan Hedberg03811012010-12-08 00:21:06 +02002303{
2304 struct mgmt_mode ev;
2305 struct cmd_lookup match = { connectable, NULL };
2306 int ret;
2307
Johan Hedberg744cf192011-11-08 20:40:14 +02002308 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev, mode_rsp, &match);
Johan Hedberg03811012010-12-08 00:21:06 +02002309
Johan Hedberg03811012010-12-08 00:21:06 +02002310 ev.val = connectable;
2311
Johan Hedberg744cf192011-11-08 20:40:14 +02002312 ret = mgmt_event(MGMT_EV_CONNECTABLE, hdev, &ev, sizeof(ev), match.sk);
Johan Hedberg03811012010-12-08 00:21:06 +02002313
2314 if (match.sk)
2315 sock_put(match.sk);
2316
2317 return ret;
2318}
2319
Johan Hedberg744cf192011-11-08 20:40:14 +02002320int mgmt_write_scan_failed(struct hci_dev *hdev, u8 scan, u8 status)
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002321{
Johan Hedbergca69b792011-11-11 18:10:00 +02002322 u8 mgmt_err = mgmt_status(status);
2323
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002324 if (scan & SCAN_PAGE)
Johan Hedberg744cf192011-11-08 20:40:14 +02002325 mgmt_pending_foreach(MGMT_OP_SET_CONNECTABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002326 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002327
2328 if (scan & SCAN_INQUIRY)
Johan Hedberg744cf192011-11-08 20:40:14 +02002329 mgmt_pending_foreach(MGMT_OP_SET_DISCOVERABLE, hdev,
Johan Hedbergca69b792011-11-11 18:10:00 +02002330 cmd_status_rsp, &mgmt_err);
Johan Hedberg2d7cee52011-11-07 22:16:03 +02002331
2332 return 0;
2333}
2334
Johan Hedberg744cf192011-11-08 20:40:14 +02002335int mgmt_new_link_key(struct hci_dev *hdev, struct link_key *key,
2336 u8 persistent)
Johan Hedberg03811012010-12-08 00:21:06 +02002337{
Johan Hedberg86742e12011-11-07 23:13:38 +02002338 struct mgmt_ev_new_link_key ev;
Johan Hedberg03811012010-12-08 00:21:06 +02002339
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002340 memset(&ev, 0, sizeof(ev));
Johan Hedberg03811012010-12-08 00:21:06 +02002341
Vinicius Costa Gomesa492cd52011-08-25 20:02:29 -03002342 ev.store_hint = persistent;
2343 bacpy(&ev.key.bdaddr, &key->bdaddr);
2344 ev.key.type = key->type;
2345 memcpy(ev.key.val, key->val, 16);
2346 ev.key.pin_len = key->pin_len;
Johan Hedberg03811012010-12-08 00:21:06 +02002347
Johan Hedberg744cf192011-11-08 20:40:14 +02002348 return mgmt_event(MGMT_EV_NEW_LINK_KEY, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg03811012010-12-08 00:21:06 +02002349}
Johan Hedbergf7520542011-01-20 12:34:39 +02002350
Johan Hedberg48264f02011-11-09 13:58:58 +02002351int mgmt_connected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2352 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002353{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002354 struct mgmt_addr_info ev;
Johan Hedbergf7520542011-01-20 12:34:39 +02002355
Johan Hedbergf7520542011-01-20 12:34:39 +02002356 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002357 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002358
Johan Hedberg744cf192011-11-08 20:40:14 +02002359 return mgmt_event(MGMT_EV_CONNECTED, hdev, &ev, sizeof(ev), NULL);
Johan Hedbergf7520542011-01-20 12:34:39 +02002360}
2361
Johan Hedberg8962ee72011-01-20 12:40:27 +02002362static void disconnect_rsp(struct pending_cmd *cmd, void *data)
2363{
Szymon Jancc68fb7f2011-03-22 13:12:19 +01002364 struct mgmt_cp_disconnect *cp = cmd->param;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002365 struct sock **sk = data;
Johan Hedberga38528f2011-01-22 06:46:43 +02002366 struct mgmt_rp_disconnect rp;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002367
Johan Hedberga38528f2011-01-22 06:46:43 +02002368 bacpy(&rp.bdaddr, &cp->bdaddr);
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002369 rp.status = 0;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002370
Szymon Janc4e51eae2011-02-25 19:05:48 +01002371 cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT, &rp, sizeof(rp));
Johan Hedberg8962ee72011-01-20 12:40:27 +02002372
2373 *sk = cmd->sk;
2374 sock_hold(*sk);
2375
Johan Hedberga664b5b2011-02-19 12:06:02 -03002376 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002377}
2378
Johan Hedberga8a1d192011-11-10 15:54:38 +02002379static void remove_keys_rsp(struct pending_cmd *cmd, void *data)
2380{
2381 u8 *status = data;
2382 struct mgmt_cp_remove_keys *cp = cmd->param;
2383 struct mgmt_rp_remove_keys rp;
2384
2385 memset(&rp, 0, sizeof(rp));
2386 bacpy(&rp.bdaddr, &cp->bdaddr);
2387 if (status != NULL)
2388 rp.status = *status;
2389
2390 cmd_complete(cmd->sk, cmd->index, MGMT_OP_REMOVE_KEYS, &rp,
2391 sizeof(rp));
2392
2393 mgmt_pending_remove(cmd);
2394}
2395
Johan Hedberg48264f02011-11-09 13:58:58 +02002396int mgmt_disconnected(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2397 u8 addr_type)
Johan Hedbergf7520542011-01-20 12:34:39 +02002398{
Johan Hedberg4c659c32011-11-07 23:13:39 +02002399 struct mgmt_addr_info ev;
Johan Hedberg8962ee72011-01-20 12:40:27 +02002400 struct sock *sk = NULL;
2401 int err;
2402
Johan Hedberg744cf192011-11-08 20:40:14 +02002403 mgmt_pending_foreach(MGMT_OP_DISCONNECT, hdev, disconnect_rsp, &sk);
Johan Hedbergf7520542011-01-20 12:34:39 +02002404
Johan Hedbergf7520542011-01-20 12:34:39 +02002405 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002406 ev.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergf7520542011-01-20 12:34:39 +02002407
Johan Hedberg744cf192011-11-08 20:40:14 +02002408 err = mgmt_event(MGMT_EV_DISCONNECTED, hdev, &ev, sizeof(ev), sk);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002409
2410 if (sk)
2411 sock_put(sk);
2412
Johan Hedberga8a1d192011-11-10 15:54:38 +02002413 mgmt_pending_foreach(MGMT_OP_REMOVE_KEYS, hdev, remove_keys_rsp, NULL);
2414
Johan Hedberg8962ee72011-01-20 12:40:27 +02002415 return err;
2416}
2417
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002418int mgmt_disconnect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg8962ee72011-01-20 12:40:27 +02002419{
2420 struct pending_cmd *cmd;
Johan Hedbergca69b792011-11-11 18:10:00 +02002421 u8 mgmt_err = mgmt_status(status);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002422 int err;
2423
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002424 cmd = mgmt_pending_find(MGMT_OP_DISCONNECT, hdev);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002425 if (!cmd)
2426 return -ENOENT;
2427
Johan Hedberg37d9ef72011-11-10 15:54:39 +02002428 if (bdaddr) {
2429 struct mgmt_rp_disconnect rp;
2430
2431 bacpy(&rp.bdaddr, bdaddr);
2432 rp.status = status;
2433
2434 err = cmd_complete(cmd->sk, cmd->index, MGMT_OP_DISCONNECT,
2435 &rp, sizeof(rp));
2436 } else
2437 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_DISCONNECT,
Johan Hedbergca69b792011-11-11 18:10:00 +02002438 mgmt_err);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002439
Johan Hedberga664b5b2011-02-19 12:06:02 -03002440 mgmt_pending_remove(cmd);
Johan Hedberg8962ee72011-01-20 12:40:27 +02002441
2442 return err;
Johan Hedbergf7520542011-01-20 12:34:39 +02002443}
Johan Hedberg17d5c042011-01-22 06:09:08 +02002444
Johan Hedberg48264f02011-11-09 13:58:58 +02002445int mgmt_connect_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2446 u8 addr_type, u8 status)
Johan Hedberg17d5c042011-01-22 06:09:08 +02002447{
2448 struct mgmt_ev_connect_failed ev;
2449
Johan Hedberg4c659c32011-11-07 23:13:39 +02002450 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002451 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedbergca69b792011-11-11 18:10:00 +02002452 ev.status = mgmt_status(status);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002453
Johan Hedberg744cf192011-11-08 20:40:14 +02002454 return mgmt_event(MGMT_EV_CONNECT_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg17d5c042011-01-22 06:09:08 +02002455}
Johan Hedberg980e1a52011-01-22 06:10:07 +02002456
Johan Hedberg744cf192011-11-08 20:40:14 +02002457int mgmt_pin_code_request(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 secure)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002458{
2459 struct mgmt_ev_pin_code_request ev;
2460
Johan Hedberg980e1a52011-01-22 06:10:07 +02002461 bacpy(&ev.bdaddr, bdaddr);
Waldemar Rymarkiewicza770bb52011-04-28 12:07:59 +02002462 ev.secure = secure;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002463
Johan Hedberg744cf192011-11-08 20:40:14 +02002464 return mgmt_event(MGMT_EV_PIN_CODE_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002465 NULL);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002466}
2467
Johan Hedberg744cf192011-11-08 20:40:14 +02002468int mgmt_pin_code_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2469 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002470{
2471 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002472 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002473 int err;
2474
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002475 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002476 if (!cmd)
2477 return -ENOENT;
2478
Johan Hedbergac56fb12011-02-19 12:05:59 -03002479 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002480 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002481
Johan Hedberg744cf192011-11-08 20:40:14 +02002482 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002483 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002484
Johan Hedberga664b5b2011-02-19 12:06:02 -03002485 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002486
2487 return err;
2488}
2489
Johan Hedberg744cf192011-11-08 20:40:14 +02002490int mgmt_pin_code_neg_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2491 u8 status)
Johan Hedberg980e1a52011-01-22 06:10:07 +02002492{
2493 struct pending_cmd *cmd;
Johan Hedbergac56fb12011-02-19 12:05:59 -03002494 struct mgmt_rp_pin_code_reply rp;
Johan Hedberg980e1a52011-01-22 06:10:07 +02002495 int err;
2496
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002497 cmd = mgmt_pending_find(MGMT_OP_PIN_CODE_NEG_REPLY, hdev);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002498 if (!cmd)
2499 return -ENOENT;
2500
Johan Hedbergac56fb12011-02-19 12:05:59 -03002501 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002502 rp.status = mgmt_status(status);
Johan Hedbergac56fb12011-02-19 12:05:59 -03002503
Johan Hedberg744cf192011-11-08 20:40:14 +02002504 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_PIN_CODE_NEG_REPLY, &rp,
Szymon Janc4e51eae2011-02-25 19:05:48 +01002505 sizeof(rp));
Johan Hedberg980e1a52011-01-22 06:10:07 +02002506
Johan Hedberga664b5b2011-02-19 12:06:02 -03002507 mgmt_pending_remove(cmd);
Johan Hedberg980e1a52011-01-22 06:10:07 +02002508
2509 return err;
2510}
Johan Hedberga5c29682011-02-19 12:05:57 -03002511
Johan Hedberg744cf192011-11-08 20:40:14 +02002512int mgmt_user_confirm_request(struct hci_dev *hdev, bdaddr_t *bdaddr,
2513 __le32 value, u8 confirm_hint)
Johan Hedberga5c29682011-02-19 12:05:57 -03002514{
2515 struct mgmt_ev_user_confirm_request ev;
2516
Johan Hedberg744cf192011-11-08 20:40:14 +02002517 BT_DBG("%s", hdev->name);
Johan Hedberga5c29682011-02-19 12:05:57 -03002518
Johan Hedberga5c29682011-02-19 12:05:57 -03002519 bacpy(&ev.bdaddr, bdaddr);
Johan Hedberg55bc1a32011-04-28 11:28:56 -07002520 ev.confirm_hint = confirm_hint;
Johan Hedberga5c29682011-02-19 12:05:57 -03002521 put_unaligned_le32(value, &ev.value);
2522
Johan Hedberg744cf192011-11-08 20:40:14 +02002523 return mgmt_event(MGMT_EV_USER_CONFIRM_REQUEST, hdev, &ev, sizeof(ev),
Szymon Janc4e51eae2011-02-25 19:05:48 +01002524 NULL);
Johan Hedberga5c29682011-02-19 12:05:57 -03002525}
2526
Brian Gix604086b2011-11-23 08:28:33 -08002527int mgmt_user_passkey_request(struct hci_dev *hdev, bdaddr_t *bdaddr)
2528{
2529 struct mgmt_ev_user_passkey_request ev;
2530
2531 BT_DBG("%s", hdev->name);
2532
2533 bacpy(&ev.bdaddr, bdaddr);
2534
2535 return mgmt_event(MGMT_EV_USER_PASSKEY_REQUEST, hdev, &ev, sizeof(ev),
2536 NULL);
2537}
2538
Brian Gix0df4c182011-11-16 13:53:13 -08002539static int user_pairing_resp_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
Johan Hedberg744cf192011-11-08 20:40:14 +02002540 u8 status, u8 opcode)
Johan Hedberga5c29682011-02-19 12:05:57 -03002541{
2542 struct pending_cmd *cmd;
2543 struct mgmt_rp_user_confirm_reply rp;
2544 int err;
2545
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002546 cmd = mgmt_pending_find(opcode, hdev);
Johan Hedberga5c29682011-02-19 12:05:57 -03002547 if (!cmd)
2548 return -ENOENT;
2549
Johan Hedberga5c29682011-02-19 12:05:57 -03002550 bacpy(&rp.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002551 rp.status = mgmt_status(status);
Johan Hedberg744cf192011-11-08 20:40:14 +02002552 err = cmd_complete(cmd->sk, hdev->id, opcode, &rp, sizeof(rp));
Johan Hedberga5c29682011-02-19 12:05:57 -03002553
Johan Hedberga664b5b2011-02-19 12:06:02 -03002554 mgmt_pending_remove(cmd);
Johan Hedberga5c29682011-02-19 12:05:57 -03002555
2556 return err;
2557}
2558
Johan Hedberg744cf192011-11-08 20:40:14 +02002559int mgmt_user_confirm_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2560 u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002561{
Brian Gix0df4c182011-11-16 13:53:13 -08002562 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002563 MGMT_OP_USER_CONFIRM_REPLY);
2564}
2565
Johan Hedberg744cf192011-11-08 20:40:14 +02002566int mgmt_user_confirm_neg_reply_complete(struct hci_dev *hdev,
2567 bdaddr_t *bdaddr, u8 status)
Johan Hedberga5c29682011-02-19 12:05:57 -03002568{
Brian Gix0df4c182011-11-16 13:53:13 -08002569 return user_pairing_resp_complete(hdev, bdaddr, status,
Johan Hedberga5c29682011-02-19 12:05:57 -03002570 MGMT_OP_USER_CONFIRM_NEG_REPLY);
2571}
Johan Hedberg2a611692011-02-19 12:06:00 -03002572
Brian Gix604086b2011-11-23 08:28:33 -08002573int mgmt_user_passkey_reply_complete(struct hci_dev *hdev, bdaddr_t *bdaddr,
2574 u8 status)
2575{
2576 return user_pairing_resp_complete(hdev, bdaddr, status,
2577 MGMT_OP_USER_PASSKEY_REPLY);
2578}
2579
2580int mgmt_user_passkey_neg_reply_complete(struct hci_dev *hdev,
2581 bdaddr_t *bdaddr, u8 status)
2582{
2583 return user_pairing_resp_complete(hdev, bdaddr, status,
2584 MGMT_OP_USER_PASSKEY_NEG_REPLY);
2585}
2586
Johan Hedberg744cf192011-11-08 20:40:14 +02002587int mgmt_auth_failed(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 status)
Johan Hedberg2a611692011-02-19 12:06:00 -03002588{
2589 struct mgmt_ev_auth_failed ev;
2590
Johan Hedberg2a611692011-02-19 12:06:00 -03002591 bacpy(&ev.bdaddr, bdaddr);
Johan Hedbergca69b792011-11-11 18:10:00 +02002592 ev.status = mgmt_status(status);
Johan Hedberg2a611692011-02-19 12:06:00 -03002593
Johan Hedberg744cf192011-11-08 20:40:14 +02002594 return mgmt_event(MGMT_EV_AUTH_FAILED, hdev, &ev, sizeof(ev), NULL);
Johan Hedberg2a611692011-02-19 12:06:00 -03002595}
Johan Hedbergb312b1612011-03-16 14:29:37 +02002596
Johan Hedberg744cf192011-11-08 20:40:14 +02002597int mgmt_set_local_name_complete(struct hci_dev *hdev, u8 *name, u8 status)
Johan Hedbergb312b1612011-03-16 14:29:37 +02002598{
2599 struct pending_cmd *cmd;
2600 struct mgmt_cp_set_local_name ev;
2601 int err;
2602
2603 memset(&ev, 0, sizeof(ev));
2604 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2605
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002606 cmd = mgmt_pending_find(MGMT_OP_SET_LOCAL_NAME, hdev);
Johan Hedbergb312b1612011-03-16 14:29:37 +02002607 if (!cmd)
2608 goto send_event;
2609
2610 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002611 err = cmd_status(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME,
Johan Hedbergca69b792011-11-11 18:10:00 +02002612 mgmt_status(status));
Johan Hedbergb312b1612011-03-16 14:29:37 +02002613 goto failed;
2614 }
2615
Johan Hedberg744cf192011-11-08 20:40:14 +02002616 update_eir(hdev);
Johan Hedberg80a1e1d2011-03-28 14:07:23 +03002617
Johan Hedberg744cf192011-11-08 20:40:14 +02002618 err = cmd_complete(cmd->sk, hdev->id, MGMT_OP_SET_LOCAL_NAME, &ev,
Johan Hedbergb312b1612011-03-16 14:29:37 +02002619 sizeof(ev));
2620 if (err < 0)
2621 goto failed;
2622
2623send_event:
Johan Hedberg744cf192011-11-08 20:40:14 +02002624 err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev, sizeof(ev),
Johan Hedbergb312b1612011-03-16 14:29:37 +02002625 cmd ? cmd->sk : NULL);
2626
2627failed:
2628 if (cmd)
2629 mgmt_pending_remove(cmd);
2630 return err;
2631}
Szymon Jancc35938b2011-03-22 13:12:21 +01002632
Johan Hedberg744cf192011-11-08 20:40:14 +02002633int mgmt_read_local_oob_data_reply_complete(struct hci_dev *hdev, u8 *hash,
2634 u8 *randomizer, u8 status)
Szymon Jancc35938b2011-03-22 13:12:21 +01002635{
2636 struct pending_cmd *cmd;
2637 int err;
2638
Johan Hedberg744cf192011-11-08 20:40:14 +02002639 BT_DBG("%s status %u", hdev->name, status);
Szymon Jancc35938b2011-03-22 13:12:21 +01002640
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002641 cmd = mgmt_pending_find(MGMT_OP_READ_LOCAL_OOB_DATA, hdev);
Szymon Jancc35938b2011-03-22 13:12:21 +01002642 if (!cmd)
2643 return -ENOENT;
2644
2645 if (status) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002646 err = cmd_status(cmd->sk, hdev->id,
Johan Hedbergca69b792011-11-11 18:10:00 +02002647 MGMT_OP_READ_LOCAL_OOB_DATA,
2648 mgmt_status(status));
Szymon Jancc35938b2011-03-22 13:12:21 +01002649 } else {
2650 struct mgmt_rp_read_local_oob_data rp;
2651
2652 memcpy(rp.hash, hash, sizeof(rp.hash));
2653 memcpy(rp.randomizer, randomizer, sizeof(rp.randomizer));
2654
Johan Hedberg744cf192011-11-08 20:40:14 +02002655 err = cmd_complete(cmd->sk, hdev->id,
2656 MGMT_OP_READ_LOCAL_OOB_DATA,
2657 &rp, sizeof(rp));
Szymon Jancc35938b2011-03-22 13:12:21 +01002658 }
2659
2660 mgmt_pending_remove(cmd);
2661
2662 return err;
2663}
Johan Hedberge17acd42011-03-30 23:57:16 +03002664
Johan Hedberg48264f02011-11-09 13:58:58 +02002665int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
2666 u8 addr_type, u8 *dev_class, s8 rssi, u8 *eir)
Johan Hedberge17acd42011-03-30 23:57:16 +03002667{
2668 struct mgmt_ev_device_found ev;
2669
2670 memset(&ev, 0, sizeof(ev));
2671
Johan Hedberg4c659c32011-11-07 23:13:39 +02002672 bacpy(&ev.addr.bdaddr, bdaddr);
Johan Hedberg48264f02011-11-09 13:58:58 +02002673 ev.addr.type = link_to_mgmt(link_type, addr_type);
Johan Hedberge17acd42011-03-30 23:57:16 +03002674 ev.rssi = rssi;
2675
2676 if (eir)
2677 memcpy(ev.eir, eir, sizeof(ev.eir));
2678
Andre Guedesf8523592011-09-09 18:56:26 -03002679 if (dev_class)
2680 memcpy(ev.dev_class, dev_class, sizeof(ev.dev_class));
2681
Johan Hedberg744cf192011-11-08 20:40:14 +02002682 return mgmt_event(MGMT_EV_DEVICE_FOUND, hdev, &ev, sizeof(ev), NULL);
Johan Hedberge17acd42011-03-30 23:57:16 +03002683}
Johan Hedberga88a9652011-03-30 13:18:12 +03002684
Johan Hedberg744cf192011-11-08 20:40:14 +02002685int mgmt_remote_name(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *name)
Johan Hedberga88a9652011-03-30 13:18:12 +03002686{
2687 struct mgmt_ev_remote_name ev;
2688
2689 memset(&ev, 0, sizeof(ev));
2690
2691 bacpy(&ev.bdaddr, bdaddr);
2692 memcpy(ev.name, name, HCI_MAX_NAME_LENGTH);
2693
Johan Hedberg744cf192011-11-08 20:40:14 +02002694 return mgmt_event(MGMT_EV_REMOTE_NAME, hdev, &ev, sizeof(ev), NULL);
Johan Hedberga88a9652011-03-30 13:18:12 +03002695}
Johan Hedberg314b2382011-04-27 10:29:57 -04002696
Andre Guedes7a135102011-11-09 17:14:25 -03002697int mgmt_start_discovery_failed(struct hci_dev *hdev, u8 status)
Johan Hedberg164a6e72011-11-01 17:06:44 +02002698{
2699 struct pending_cmd *cmd;
2700 int err;
2701
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002702 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002703 if (!cmd)
2704 return -ENOENT;
2705
Johan Hedbergca69b792011-11-11 18:10:00 +02002706 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, mgmt_status(status));
Johan Hedberg164a6e72011-11-01 17:06:44 +02002707 mgmt_pending_remove(cmd);
2708
2709 return err;
2710}
2711
Andre Guedese6d465c2011-11-09 17:14:26 -03002712int mgmt_stop_discovery_failed(struct hci_dev *hdev, u8 status)
2713{
2714 struct pending_cmd *cmd;
2715 int err;
2716
2717 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
2718 if (!cmd)
2719 return -ENOENT;
2720
Johan Hedberg03811012010-12-08 00:21:06 +02002721 err = cmd_status(cmd->sk, hdev->id, cmd->opcode, status);
2722 mgmt_pending_remove(cmd);
2723
2724 return err;
2725}
Johan Hedberg314b2382011-04-27 10:29:57 -04002726
Johan Hedberg744cf192011-11-08 20:40:14 +02002727int mgmt_discovering(struct hci_dev *hdev, u8 discovering)
Johan Hedberg314b2382011-04-27 10:29:57 -04002728{
Johan Hedberg164a6e72011-11-01 17:06:44 +02002729 struct pending_cmd *cmd;
2730
2731 if (discovering)
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002732 cmd = mgmt_pending_find(MGMT_OP_START_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002733 else
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002734 cmd = mgmt_pending_find(MGMT_OP_STOP_DISCOVERY, hdev);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002735
2736 if (cmd != NULL) {
Johan Hedberg744cf192011-11-08 20:40:14 +02002737 cmd_complete(cmd->sk, hdev->id, cmd->opcode, NULL, 0);
Johan Hedberg164a6e72011-11-01 17:06:44 +02002738 mgmt_pending_remove(cmd);
2739 }
2740
Johan Hedberg744cf192011-11-08 20:40:14 +02002741 return mgmt_event(MGMT_EV_DISCOVERING, hdev, &discovering,
Johan Hedberg314b2382011-04-27 10:29:57 -04002742 sizeof(discovering), NULL);
2743}
Antti Julku5e762442011-08-25 16:48:02 +03002744
Johan Hedberg744cf192011-11-08 20:40:14 +02002745int mgmt_device_blocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002746{
2747 struct pending_cmd *cmd;
2748 struct mgmt_ev_device_blocked ev;
2749
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002750 cmd = mgmt_pending_find(MGMT_OP_BLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002751
2752 bacpy(&ev.bdaddr, bdaddr);
2753
Johan Hedberg744cf192011-11-08 20:40:14 +02002754 return mgmt_event(MGMT_EV_DEVICE_BLOCKED, hdev, &ev, sizeof(ev),
2755 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002756}
2757
Johan Hedberg744cf192011-11-08 20:40:14 +02002758int mgmt_device_unblocked(struct hci_dev *hdev, bdaddr_t *bdaddr)
Antti Julku5e762442011-08-25 16:48:02 +03002759{
2760 struct pending_cmd *cmd;
2761 struct mgmt_ev_device_unblocked ev;
2762
Johan Hedberg2e58ef32011-11-08 20:40:15 +02002763 cmd = mgmt_pending_find(MGMT_OP_UNBLOCK_DEVICE, hdev);
Antti Julku5e762442011-08-25 16:48:02 +03002764
2765 bacpy(&ev.bdaddr, bdaddr);
2766
Johan Hedberg744cf192011-11-08 20:40:14 +02002767 return mgmt_event(MGMT_EV_DEVICE_UNBLOCKED, hdev, &ev, sizeof(ev),
2768 cmd ? cmd->sk : NULL);
Antti Julku5e762442011-08-25 16:48:02 +03002769}