OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [net/] [bluetooth/] [hci_conn.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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
/*
26
 * HCI Connection handling.
27
 *
28
 * $Id: hci_conn.c,v 1.1.1.1 2004-04-15 01:17:03 phoenix Exp $
29
 */
30
 
31
#include <linux/config.h>
32
#include <linux/module.h>
33
 
34
#include <linux/types.h>
35
#include <linux/errno.h>
36
#include <linux/kernel.h>
37
#include <linux/major.h>
38
#include <linux/sched.h>
39
#include <linux/slab.h>
40
#include <linux/poll.h>
41
#include <linux/fcntl.h>
42
#include <linux/init.h>
43
#include <linux/skbuff.h>
44
#include <linux/interrupt.h>
45
#include <linux/notifier.h>
46
#include <net/sock.h>
47
 
48
#include <asm/system.h>
49
#include <asm/uaccess.h>
50
#include <asm/unaligned.h>
51
 
52
#include <net/bluetooth/bluetooth.h>
53
#include <net/bluetooth/hci_core.h>
54
 
55
#ifndef HCI_CORE_DEBUG
56
#undef  BT_DBG
57
#define BT_DBG( A... )
58
#endif
59
 
60
void hci_acl_connect(struct hci_conn *conn)
61
{
62
        struct hci_dev *hdev = conn->hdev;
63
        struct inquiry_entry *ie;
64
        create_conn_cp cp;
65
 
66
        BT_DBG("%p", conn);
67
 
68
        conn->state = BT_CONNECT;
69
        conn->out   = 1;
70
        conn->link_mode = HCI_LM_MASTER;
71
 
72
        memset(&cp, 0, sizeof(cp));
73
        bacpy(&cp.bdaddr, &conn->dst);
74
        cp.pscan_rep_mode = 0x02;
75
 
76
        if ((ie = inquiry_cache_lookup(hdev, &conn->dst)) &&
77
                        inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
78
                cp.pscan_rep_mode = ie->info.pscan_rep_mode;
79
                cp.pscan_mode     = ie->info.pscan_mode;
80
                cp.clock_offset   = ie->info.clock_offset | __cpu_to_le16(0x8000);
81
        }
82
 
83
        cp.pkt_type = __cpu_to_le16(hdev->pkt_type & ACL_PTYPE_MASK);
84
        if (lmp_rswitch_capable(hdev) && !(hdev->link_mode & HCI_LM_MASTER))
85
                cp.role_switch  = 0x01;
86
        else
87
                cp.role_switch  = 0x00;
88
 
89
        hci_send_cmd(hdev, OGF_LINK_CTL, OCF_CREATE_CONN,
90
                                CREATE_CONN_CP_SIZE, &cp);
91
}
92
 
93
void hci_acl_disconn(struct hci_conn *conn, __u8 reason)
94
{
95
        disconnect_cp cp;
96
 
97
        BT_DBG("%p", conn);
98
 
99
        conn->state = BT_DISCONN;
100
 
101
        cp.handle = __cpu_to_le16(conn->handle);
102
        cp.reason = reason;
103
        hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_DISCONNECT,
104
                                DISCONNECT_CP_SIZE, &cp);
105
}
106
 
107
void hci_add_sco(struct hci_conn *conn, __u16 handle)
108
{
109
        struct hci_dev *hdev = conn->hdev;
110
        add_sco_cp cp;
111
 
112
        BT_DBG("%p", conn);
113
 
114
        conn->state = BT_CONNECT;
115
        conn->out = 1;
116
 
117
        cp.pkt_type = __cpu_to_le16(hdev->pkt_type & SCO_PTYPE_MASK);
118
        cp.handle   = __cpu_to_le16(handle);
119
 
120
        hci_send_cmd(hdev, OGF_LINK_CTL, OCF_ADD_SCO, ADD_SCO_CP_SIZE, &cp);
121
}
122
 
123
static void hci_conn_timeout(unsigned long arg)
124
{
125
        struct hci_conn *conn = (void *)arg;
126
        struct hci_dev  *hdev = conn->hdev;
127
 
128
        BT_DBG("conn %p state %d", conn, conn->state);
129
 
130
        if (atomic_read(&conn->refcnt))
131
                return;
132
 
133
        hci_dev_lock(hdev);
134
        if (conn->state == BT_CONNECTED)
135
                hci_acl_disconn(conn, 0x13);
136
        else
137
                conn->state = BT_CLOSED;
138
        hci_dev_unlock(hdev);
139
        return;
140
}
141
 
142
static void hci_conn_init_timer(struct hci_conn *conn)
143
{
144
        init_timer(&conn->timer);
145
        conn->timer.function = hci_conn_timeout;
146
        conn->timer.data = (unsigned long)conn;
147
}
148
 
149
struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
150
{
151
        struct hci_conn *conn;
152
 
153
        BT_DBG("%s dst %s", hdev->name, batostr(dst));
154
 
155
        if (!(conn = kmalloc(sizeof(struct hci_conn), GFP_ATOMIC)))
156
                return NULL;
157
        memset(conn, 0, sizeof(struct hci_conn));
158
 
159
        bacpy(&conn->dst, dst);
160
        conn->type   = type;
161
        conn->hdev   = hdev;
162
        conn->state  = BT_OPEN;
163
 
164
        skb_queue_head_init(&conn->data_q);
165
        hci_conn_init_timer(conn);
166
 
167
        atomic_set(&conn->refcnt, 0);
168
 
169
        hci_dev_hold(hdev);
170
 
171
        tasklet_disable(&hdev->tx_task);
172
        conn_hash_add(hdev, conn);
173
        tasklet_enable(&hdev->tx_task);
174
 
175
        return conn;
176
}
177
 
178
int hci_conn_del(struct hci_conn *conn)
179
{
180
        struct hci_dev  *hdev = conn->hdev;
181
 
182
        BT_DBG("%s conn %p handle %d", hdev->name, conn, conn->handle);
183
 
184
        hci_conn_del_timer(conn);
185
 
186
        if (conn->type == SCO_LINK) {
187
                struct hci_conn *acl = conn->link;
188
                if (acl) {
189
                        acl->link = NULL;
190
                        hci_conn_put(acl);
191
                }
192
        } else {
193
                struct hci_conn *sco = conn->link;
194
                if (sco)
195
                        sco->link = NULL;
196
 
197
                /* Unacked frames */
198
                hdev->acl_cnt += conn->sent;
199
        }
200
 
201
        tasklet_disable(&hdev->tx_task);
202
        conn_hash_del(hdev, conn);
203
        tasklet_enable(&hdev->tx_task);
204
 
205
        skb_queue_purge(&conn->data_q);
206
 
207
        hci_dev_put(hdev);
208
 
209
        kfree(conn);
210
        return 0;
211
}
212
 
213
struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src)
214
{
215
        int use_src = bacmp(src, BDADDR_ANY);
216
        struct hci_dev *hdev = NULL;
217
        struct list_head *p;
218
 
219
        BT_DBG("%s -> %s", batostr(src), batostr(dst));
220
 
221
        read_lock_bh(&hdev_list_lock);
222
 
223
        list_for_each(p, &hdev_list) {
224
                struct hci_dev *d;
225
                d = list_entry(p, struct hci_dev, list);
226
 
227
                if (!test_bit(HCI_UP, &d->flags))
228
                        continue;
229
 
230
                /* Simple routing:
231
                 *      No source address - find interface with bdaddr != dst
232
                 *      Source address    - find interface with bdaddr == src
233
                 */
234
 
235
                if (use_src) {
236
                        if (!bacmp(&d->bdaddr, src)) {
237
                                hdev = d; break;
238
                        }
239
                } else {
240
                        if (bacmp(&d->bdaddr, dst)) {
241
                                hdev = d; break;
242
                        }
243
                }
244
        }
245
 
246
        if (hdev)
247
                hci_dev_hold(hdev);
248
 
249
        read_unlock_bh(&hdev_list_lock);
250
        return hdev;
251
}
252
 
253
/* Create SCO or ACL connection.
254
 * Device _must_ be locked */
255
struct hci_conn * hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst)
256
{
257
        struct hci_conn *acl;
258
 
259
        BT_DBG("%s dst %s", hdev->name, batostr(dst));
260
 
261
        if (!(acl = conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
262
                if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
263
                        return NULL;
264
        }
265
 
266
        hci_conn_hold(acl);
267
 
268
        if (acl->state == BT_OPEN || acl->state == BT_CLOSED)
269
                hci_acl_connect(acl);
270
 
271
        if (type == SCO_LINK) {
272
                struct hci_conn *sco;
273
 
274
                if (!(sco = conn_hash_lookup_ba(hdev, SCO_LINK, dst))) {
275
                        if (!(sco = hci_conn_add(hdev, SCO_LINK, dst))) {
276
                                hci_conn_put(acl);
277
                                return NULL;
278
                        }
279
                }
280
                acl->link = sco;
281
                sco->link = acl;
282
 
283
                hci_conn_hold(sco);
284
 
285
                if (acl->state == BT_CONNECTED &&
286
                                (sco->state == BT_OPEN || sco->state == BT_CLOSED))
287
                        hci_add_sco(sco, acl->handle);
288
 
289
                return sco;
290
        } else {
291
                return acl;
292
        }
293
}
294
 
295
/* Authenticate remote device */
296
int hci_conn_auth(struct hci_conn *conn)
297
{
298
        BT_DBG("conn %p", conn);
299
 
300
        if (conn->link_mode & HCI_LM_AUTH)
301
                return 1;
302
 
303
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
304
                auth_requested_cp ar;
305
                ar.handle = __cpu_to_le16(conn->handle);
306
                hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
307
                                AUTH_REQUESTED_CP_SIZE, &ar);
308
        }
309
        return 0;
310
}
311
 
312
/* Enable encryption */
313
int hci_conn_encrypt(struct hci_conn *conn)
314
{
315
        BT_DBG("conn %p", conn);
316
 
317
        if (conn->link_mode & HCI_LM_ENCRYPT)
318
                return 1;
319
 
320
        if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
321
                return 0;
322
 
323
        if (hci_conn_auth(conn)) {
324
                set_conn_encrypt_cp ce;
325
                ce.handle  = __cpu_to_le16(conn->handle);
326
                ce.encrypt = 1;
327
                hci_send_cmd(conn->hdev, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT,
328
                                SET_CONN_ENCRYPT_CP_SIZE, &ce);
329
        }
330
        return 0;
331
}
332
 
333
/* Drop all connection on the device */
334
void hci_conn_hash_flush(struct hci_dev *hdev)
335
{
336
        struct conn_hash *h = &hdev->conn_hash;
337
        struct list_head *p;
338
 
339
        BT_DBG("hdev %s", hdev->name);
340
 
341
        p = h->list.next;
342
        while (p != &h->list) {
343
                struct hci_conn *c;
344
 
345
                c = list_entry(p, struct hci_conn, list);
346
                p = p->next;
347
 
348
                c->state = BT_CLOSED;
349
 
350
                hci_proto_disconn_ind(c, 0x16);
351
                hci_conn_del(c);
352
        }
353
}
354
 
355
int hci_get_conn_list(unsigned long arg)
356
{
357
        struct hci_conn_list_req req, *cl;
358
        struct hci_conn_info *ci;
359
        struct hci_dev *hdev;
360
        struct list_head *p;
361
        int n = 0, size, err;
362
 
363
        if (copy_from_user(&req, (void *) arg, sizeof(req)))
364
                return -EFAULT;
365
 
366
        if (!req.conn_num || req.conn_num > (PAGE_SIZE * 2) / sizeof(*ci))
367
                return -EINVAL;
368
 
369
        size = sizeof(req) + req.conn_num * sizeof(*ci);
370
 
371
        if (!(cl = (void *) kmalloc(size, GFP_KERNEL)))
372
                return -ENOMEM;
373
 
374
        if (!(hdev = hci_dev_get(req.dev_id))) {
375
                kfree(cl);
376
                return -ENODEV;
377
        }
378
 
379
        ci = cl->conn_info;
380
 
381
        hci_dev_lock_bh(hdev);
382
        list_for_each(p, &hdev->conn_hash.list) {
383
                register struct hci_conn *c;
384
                c = list_entry(p, struct hci_conn, list);
385
 
386
                bacpy(&(ci + n)->bdaddr, &c->dst);
387
                (ci + n)->handle = c->handle;
388
                (ci + n)->type  = c->type;
389
                (ci + n)->out   = c->out;
390
                (ci + n)->state = c->state;
391
                (ci + n)->link_mode = c->link_mode;
392
                if (++n >= req.conn_num)
393
                        break;
394
        }
395
        hci_dev_unlock_bh(hdev);
396
 
397
        cl->dev_id = hdev->id;
398
        cl->conn_num = n;
399
        size = sizeof(req) + n * sizeof(*ci);
400
 
401
        hci_dev_put(hdev);
402
 
403
        err = copy_to_user((void *) arg, cl, size);
404
        kfree(cl);
405
 
406
        return err ? -EFAULT : 0;
407
}
408
 
409
int hci_get_conn_info(struct hci_dev *hdev, unsigned long arg)
410
{
411
        struct hci_conn_info_req req;
412
        struct hci_conn_info ci;
413
        struct hci_conn *conn;
414
        char *ptr = (void *) arg + sizeof(req);
415
 
416
        if (copy_from_user(&req, (void *) arg, sizeof(req)))
417
                return -EFAULT;
418
 
419
        hci_dev_lock_bh(hdev);
420
        conn = conn_hash_lookup_ba(hdev, req.type, &req.bdaddr);
421
        if (conn) {
422
                bacpy(&ci.bdaddr, &conn->dst);
423
                ci.handle = conn->handle;
424
                ci.type  = conn->type;
425
                ci.out   = conn->out;
426
                ci.state = conn->state;
427
                ci.link_mode = conn->link_mode;
428
        }
429
        hci_dev_unlock_bh(hdev);
430
 
431
        if (!conn)
432
                return -ENOENT;
433
 
434
        return copy_to_user(ptr, &ci, sizeof(ci)) ? -EFAULT : 0;
435
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.