aboutsummaryrefslogtreecommitdiffstats
path: root/net/bluetooth/hci_conn.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /net/bluetooth/hci_conn.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'net/bluetooth/hci_conn.c')
-rw-r--r--net/bluetooth/hci_conn.c471
1 files changed, 471 insertions, 0 deletions
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
new file mode 100644
index 000000000000..71762d7e9970
--- /dev/null
+++ b/net/bluetooth/hci_conn.c
@@ -0,0 +1,471 @@
1/*
2 BlueZ - Bluetooth protocol stack for Linux
3 Copyright (C) 2000-2001 Qualcomm Incorporated
4
5 Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation;
10
11 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
12 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
13 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
14 IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
15 CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
16 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19
20 ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
21 COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
22 SOFTWARE IS DISCLAIMED.
23*/
24
25/* Bluetooth HCI connection handling. */
26
27#include <linux/config.h>
28#include <linux/module.h>
29
30#include <linux/types.h>
31#include <linux/errno.h>
32#include <linux/kernel.h>
33#include <linux/major.h>
34#include <linux/sched.h>
35#include <linux/slab.h>
36#include <linux/poll.h>
37#include <linux/fcntl.h>
38#include <linux/init.h>
39#include <linux/skbuff.h>
40#include <linux/interrupt.h>
41#include <linux/notifier.h>
42#include <net/sock.h>
43
44#include <asm/system.h>
45#include <asm/uaccess.h>
46#include <asm/unaligned.h>
47
48#include <net/bluetooth/bluetooth.h>
49#include <net/bluetooth/hci_core.h>
50
51#ifndef CONFIG_BT_HCI_CORE_DEBUG
52#undef BT_DBG
53#define BT_DBG(D...)
54#endif
55
56static void hci_acl_connect(struct hci_conn *conn)
57{
58 struct hci_dev *hdev = conn->hdev;
59 struct inquiry_entry *ie;
60 struct hci_cp_create_conn cp;
61
62 BT_DBG("%p", conn);
63
64 conn->state = BT_CONNECT;
65 conn->out = 1;
66 conn->link_mode = HCI_LM_MASTER;
67
68 memset(&cp, 0, sizeof(cp));
69 bacpy(&cp.bdaddr, &conn->dst);
70 cp.pscan_rep_mode = 0x02;
71
72 if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst)) &&
73 inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
74 cp.pscan_rep_mode = ie->data.pscan_rep_mode;
75 cp.pscan_mode = ie->data.pscan_mode;
76 cp.clock_offset = ie->data.clock_offset | __cpu_to_le16(0x8000);
77 memcpy(conn->dev_class, ie->data.dev_class, 3);
78 }
79
80 cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
81 if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
82 cp.role_switch = 0x01;
83 else
84 cp.role_switch = 0x00;
85
86 hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN, sizeof(cp), &cp);
87}
88
89void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
90{
91 struct hci_cp_disconnect cp;
92
93 BT_DBG("%p", conn);
94
95 conn->state = BT_DISCONN;
96
97 cp.handle = __cpu_to_le16(conn->handle);
98 cp.reason = reason;
99 hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT, sizeof(cp), &cp);
100}
101
102void hci_add_sco(struct hci_conn *conn, __u16 handle)
103{
104 struct hci_dev *hdev = conn->hdev;
105 struct hci_cp_add_sco cp;
106
107 BT_DBG("%p", conn);
108
109 conn->state = BT_CONNECT;
110 conn->out = 1;
111
112 cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
113 cp.handle = __cpu_to_le16(handle);
114
115 hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, sizeof(cp), &cp);
116}
117
118static void hci_conn_timeout(unsigned long arg)
119{
120 struct hci_conn *conn = (void *)arg;
121 struct hci_dev *hdev = conn->hdev;
122
123 BT_DBG("conn %p state %d", conn, conn->state);
124
125 if (atomic_read(&conn->refcnt))
126 return;
127
128 hci_dev_lock(hdev);
129 if (conn->state == BT_CONNECTED)
130 hci_acl_disconn(conn, 0x13);
131 else
132 conn->state = BT_CLOSED;
133 hci_dev_unlock(hdev);
134 return;
135}
136
137static void hci_conn_init_timer(struct hci_conn *conn)
138{
139 init_timer(&conn->timer);
140 conn->timer.function = hci_conn_timeout;
141 conn->timer.data = (unsigned long)conn;
142}
143
144struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
145{
146 struct hci_conn *conn;
147
148 BT_DBG("%s dst %s", hdev->name, batostr(dst));
149
150 if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
151 return NULL;
152 memset(conn, 0, sizeof(struct hci_conn));
153
154 bacpy(&conn->dst, dst);
155 conn->type = type;
156 conn->hdev = hdev;
157 conn->state = BT_OPEN;
158
159 skb_queue_head_init(&conn->data_q);
160 hci_conn_init_timer(conn);
161
162 atomic_set(&conn->refcnt, 0);
163
164 hci_dev_hold(hdev);
165
166 tasklet_disable(&hdev->tx_task);
167
168 hci_conn_hash_add(hdev, conn);
169 if (hdev->notify)
170 hdev->notify(hdev, HCI_NOTIFY_CONN_ADD);
171
172 tasklet_enable(&hdev->tx_task);
173
174 return conn;
175}
176
177int hci_conn_del(struct hci_conn *conn)
178{
179 struct hci_dev *hdev = conn->hdev;
180
181 BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
182
183 hci_conn_del_timer(conn);
184
185 if (conn->type == SCO_LINK) {
186 struct hci_conn *acl = conn->link;
187 if (acl) {
188 acl->link = NULL;
189 hci_conn_put(acl);
190 }
191 } else {
192 struct hci_conn *sco = conn->link;
193 if (sco)
194 sco->link = NULL;
195
196 /* Unacked frames */
197 hdev->acl_cnt += conn->sent;
198 }
199
200 tasklet_disable(&hdev->tx_task);
201
202 hci_conn_hash_del(hdev, conn);
203 if (hdev->notify)
204 hdev->notify(hdev, HCI_NOTIFY_CONN_DEL);
205
206 tasklet_enable(&hdev->tx_task);
207
208 skb_queue_purge(&conn->data_q);
209
210 hci_dev_put(hdev);
211
212 kfree(conn);
213 return 0;
214}
215
216struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
217{
218 int use_src = bacmp(src, BDADDR_ANY);
219 struct hci_dev *hdev = NULL;
220 struct list_head *p;
221
222 BT_DBG("%s -> %s", batostr(src), batostr(dst));
223
224 read_lock_bh(&hci_dev_list_lock);
225
226 list_for_each(p, &hci_dev_list) {
227 struct hci_dev *d = list_entry(p, struct hci_dev, list);
228
229 if (!test_bit(HCI_UP, &d->flags) || test_bit(HCI_RAW, &d->flags))
230 continue;
231
232 /* Simple routing:
233 * No source address - find interface with bdaddr != dst
234 * Source address - find interface with bdaddr == src
235 */
236
237 if (use_src) {
238 if (!bacmp(&d->bdaddr, src)) {
239 hdev = d; break;
240 }
241 } else {
242 if (bacmp(&d->bdaddr, dst)) {
243 hdev = d; break;
244 }
245 }
246 }
247
248 if (hdev)
249 hdev = hci_dev_hold(hdev);
250
251 read_unlock_bh(&hci_dev_list_lock);
252 return hdev;
253}
254EXPORT_SYMBOL(hci_get_route);
255
256/* Create SCO or ACL connection.
257 * Device _must_ be locked */
258struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
259{
260 struct hci_conn *acl;
261
262 BT_DBG("%s dst %s", hdev->name, batostr(dst));
263
264 if (!(acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
265 if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
266 return NULL;
267 }
268
269 hci_conn_hold(acl);
270
271 if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
272 hci_acl_connect(acl);
273
274 if (type == SCO_LINK) {
275 struct hci_conn *sco;
276
277 if (!(sco = hci_conn_hash_lookup_ba(hdev, SCO_LINK, dst))) {
278 if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) {
279 hci_conn_put(acl);
280 return NULL;
281 }
282 }
283 acl->link = sco;
284 sco->link = acl;
285
286 hci_conn_hold(sco);
287
288 if (acl->state == BT_CONNECTED &&
289 (sco->state == BT_OPEN || sco->state == BT_CLOSED))
290 hci_add_sco(sco, acl->handle);
291
292 return sco;
293 } else {
294 return acl;
295 }
296}
297EXPORT_SYMBOL(hci_connect);
298
299/* Authenticate remote device */
300int hci_conn_auth(struct hci_conn *conn)
301{
302 BT_DBG("conn %p", conn);
303
304 if (conn->link_mode & HCI_LM_AUTH)
305 return 1;
306
307 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
308 struct hci_cp_auth_requested cp;
309 cp.handle = __cpu_to_le16(conn->handle);
310 hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED, sizeof(cp), &cp);
311 }
312 return 0;
313}
314EXPORT_SYMBOL(hci_conn_auth);
315
316/* Enable encryption */
317int hci_conn_encrypt(struct hci_conn *conn)
318{
319 BT_DBG("conn %p", conn);
320
321 if (conn->link_mode & HCI_LM_ENCRYPT)
322 return 1;
323
324 if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
325 return 0;
326
327 if (hci_conn_auth(conn)) {
328 struct hci_cp_set_conn_encrypt cp;
329 cp.handle = __cpu_to_le16(conn->handle);
330 cp.encrypt = 1;
331 hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT, sizeof(cp), &cp);
332 }
333 return 0;
334}
335EXPORT_SYMBOL(hci_conn_encrypt);
336
337/* Change link key */
338int hci_conn_change_link_key(struct hci_conn *conn)
339{
340 BT_DBG("conn %p", conn);
341
342 if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
343 struct hci_cp_change_conn_link_key cp;
344 cp.handle = __cpu_to_le16(conn->handle);
345 hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_CHANGE_CONN_LINK_KEY, sizeof(cp), &cp);
346 }
347 return 0;
348}
349EXPORT_SYMBOL(hci_conn_change_link_key);
350
351/* Switch role */
352int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
353{
354 BT_DBG("conn %p", conn);
355
356 if (!role && conn->link_mode & HCI_LM_MASTER)
357 return 1;
358
359 if (!test_and_set_bit(HCI_CONN_RSWITCH_PEND, &conn->pend)) {
360 struct hci_cp_switch_role cp;
361 bacpy(&cp.bdaddr, &conn->dst);
362 cp.role = role;
363 hci_send_cmd(conn->hdev, OGF_LINK_POLICY, OCF_SWITCH_ROLE, sizeof(cp), &cp);
364 }
365 return 0;
366}
367EXPORT_SYMBOL(hci_conn_switch_role);
368
369/* Drop all connection on the device */
370void hci_conn_hash_flush(struct hci_dev *hdev)
371{
372 struct hci_conn_hash *h = &hdev->conn_hash;
373 struct list_head *p;
374
375 BT_DBG("hdev %s", hdev->name);
376
377 p = h->list.next;
378 while (p != &h->list) {
379 struct hci_conn *c;
380
381 c = list_entry(p, struct hci_conn, list);
382 p = p->next;
383
384 c->state = BT_CLOSED;
385
386 hci_proto_disconn_ind(c, 0x16);
387 hci_conn_del(c);
388 }
389}
390
391int hci_get_conn_list(void __user *arg)
392{
393 struct hci_conn_list_req req, *cl;
394 struct hci_conn_info *ci;
395 struct hci_dev *hdev;
396 struct list_head *p;
397 int n = 0, size, err;
398
399 if (copy_from_user(&req, arg, sizeof(req)))
400 return -EFAULT;
401
402 if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci))
403 return -EINVAL;
404
405 size = sizeof(req) + req.conn_num * sizeof(*ci);
406
407 if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
408 return -ENOMEM;
409
410 if (!(hdev = hci_dev_get(req.dev_id))) {
411 kfree(cl);
412 return -ENODEV;
413 }
414
415 ci = cl->conn_info;
416
417 hci_dev_lock_bh(hdev);
418 list_for_each(p, &hdev->conn_hash.list) {
419 register struct hci_conn *c;
420 c = list_entry(p, struct hci_conn, list);
421
422 bacpy(&(ci + n)->bdaddr, &c->dst);
423 (ci + n)->handle = c->handle;
424 (ci + n)->type = c->type;
425 (ci + n)->out = c->out;
426 (ci + n)->state = c->state;
427 (ci + n)->link_mode = c->link_mode;
428 if (++n >= req.conn_num)
429 break;
430 }
431 hci_dev_unlock_bh(hdev);
432
433 cl->dev_id = hdev->id;
434 cl->conn_num = n;
435 size = sizeof(req) + n * sizeof(*ci);
436
437 hci_dev_put(hdev);
438
439 err = copy_to_user(arg, cl, size);
440 kfree(cl);
441
442 return err ? -EFAULT : 0;
443}
444
445int hci_get_conn_info(struct hci_dev *hdev, void __user *arg)
446{
447 struct hci_conn_info_req req;
448 struct hci_conn_info ci;
449 struct hci_conn *conn;
450 char __user *ptr = arg + sizeof(req);
451
452 if (copy_from_user(&req, arg, sizeof(req)))
453 return -EFAULT;
454
455 hci_dev_lock_bh(hdev);
456 conn = hci_conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
457 if (conn) {
458 bacpy(&ci.bdaddr, &conn->dst);
459 ci.handle = conn->handle;
460 ci.type = conn->type;
461 ci.out = conn->out;
462 ci.state = conn->state;
463 ci.link_mode = conn->link_mode;
464 }
465 hci_dev_unlock_bh(hdev);
466
467 if (!conn)
468 return -ENOENT;
469
470 return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
471}