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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
   BNEP implementation for Linux Bluetooth stack (BlueZ).
3
   Copyright (C) 2001-2002 Inventel Systemes
4
   Written 2001-2002 by
5
        Clément Moreau <clement.moreau@inventel.fr>
6
        David Libault  <david.libault@inventel.fr>
7
 
8
   Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>
9
 
10
   This program is free software; you can redistribute it and/or modify
11
   it under the terms of the GNU General Public License version 2 as
12
   published by the Free Software Foundation;
13
 
14
   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS.
17
   IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY
18
   CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES
19
   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20
   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
21
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
 
23
   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
24
   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
25
   SOFTWARE IS DISCLAIMED.
26
*/
27
 
28
/*
29
 * $Id: core.c,v 1.1.1.1 2004-04-15 01:17:08 phoenix Exp $
30
 */
31
 
32
#define __KERNEL_SYSCALLS__
33
 
34
#include <linux/config.h>
35
#include <linux/module.h>
36
 
37
#include <linux/kernel.h>
38
#include <linux/sched.h>
39
#include <linux/signal.h>
40
#include <linux/init.h>
41
#include <linux/wait.h>
42
#include <linux/errno.h>
43
#include <linux/smp_lock.h>
44
#include <linux/net.h>
45
#include <net/sock.h>
46
 
47
#include <linux/socket.h>
48
#include <linux/file.h>
49
 
50
#include <linux/netdevice.h>
51
#include <linux/etherdevice.h>
52
#include <linux/skbuff.h>
53
 
54
#include <asm/unaligned.h>
55
 
56
#include <net/bluetooth/bluetooth.h>
57
#include <net/bluetooth/l2cap.h>
58
 
59
#include "bnep.h"
60
 
61
#ifndef CONFIG_BLUEZ_BNEP_DEBUG
62
#undef  BT_DBG
63
#define BT_DBG(D...)
64
#endif
65
 
66
#define VERSION "1.1"
67
 
68
static LIST_HEAD(bnep_session_list);
69
static DECLARE_RWSEM(bnep_session_sem);
70
 
71
static struct bnep_session *__bnep_get_session(u8 *dst)
72
{
73
        struct bnep_session *s;
74
        struct list_head *p;
75
 
76
        BT_DBG("");
77
 
78
        list_for_each(p, &bnep_session_list) {
79
                s = list_entry(p, struct bnep_session, list);
80
                if (!memcmp(dst, s->eh.h_source, ETH_ALEN))
81
                        return s;
82
        }
83
        return NULL;
84
}
85
 
86
static void __bnep_link_session(struct bnep_session *s)
87
{
88
        MOD_INC_USE_COUNT;
89
        list_add(&s->list, &bnep_session_list);
90
}
91
 
92
static void __bnep_unlink_session(struct bnep_session *s)
93
{
94
        list_del(&s->list);
95
        MOD_DEC_USE_COUNT;
96
}
97
 
98
static int bnep_send(struct bnep_session *s, void *data, size_t len)
99
{
100
        struct socket *sock = s->sock;
101
        struct iovec iv = { data, len };
102
        s->msg.msg_iov    = &iv;
103
        s->msg.msg_iovlen = 1;
104
        return sock->ops->sendmsg(sock, &s->msg, len, NULL);
105
}
106
 
107
static int bnep_send_rsp(struct bnep_session *s, u8 ctrl, u16 resp)
108
{
109
        struct bnep_control_rsp rsp;
110
        rsp.type = BNEP_CONTROL;
111
        rsp.ctrl = ctrl;
112
        rsp.resp = htons(resp);
113
        return bnep_send(s, &rsp, sizeof(rsp));
114
}
115
 
116
static int bnep_ctrl_set_netfilter(struct bnep_session *s, u16 *data, int len)
117
{
118
        int n;
119
 
120
        if (len < 2)
121
                return -EILSEQ;
122
 
123
        n = ntohs(get_unaligned(data));
124
        data++; len -= 2;
125
 
126
        if (len < n)
127
                return -EILSEQ;
128
 
129
        BT_DBG("filter len %d", n);
130
 
131
#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
132
        n /= 4;
133
        if (n <= BNEP_MAX_PROTO_FILTERS) {
134
                struct bnep_proto_filter *f = s->proto_filter;
135
                int i;
136
 
137
                for (i = 0; i < n; i++) {
138
                        f[i].start = get_unaligned(data++);
139
                        f[i].end   = get_unaligned(data++);
140
 
141
                        BT_DBG("proto filter start %d end %d",
142
                                f[i].start, f[i].end);
143
                }
144
                if (i < BNEP_MAX_PROTO_FILTERS)
145
                        memset(f + i, 0, sizeof(*f));
146
 
147
                bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
148
        } else {
149
                bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
150
        }
151
#else
152
        bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
153
#endif
154
        return 0;
155
}
156
 
157
static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
158
{
159
        int n;
160
 
161
        if (len < 2)
162
                return -EILSEQ;
163
 
164
        n = ntohs(get_unaligned((u16 *) data));
165
        data += 2; len -= 2;
166
 
167
        if (len < n)
168
                return -EILSEQ;
169
 
170
        BT_DBG("filter len %d", n);
171
 
172
#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
173
        n /= (ETH_ALEN * 2);
174
 
175
        if (n > 0) {
176
                s->mc_filter = 0;
177
 
178
                /* Always send broadcast */
179
                set_bit(bnep_mc_hash(s->dev.broadcast), &s->mc_filter);
180
 
181
                /* Add address ranges to the multicast hash */
182
                for (; n > 0; n--) {
183
                        u8 a1[6], *a2;
184
 
185
                        memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
186
                        a2 = data; data += ETH_ALEN;
187
 
188
                        BT_DBG("mc filter %s -> %s",
189
                                batostr((void *) a1), batostr((void *) a2));
190
 
191
                        #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
192
 
193
                        /* Iterate from a1 to a2 */
194
                        set_bit(bnep_mc_hash(a1), &s->mc_filter);
195
                        while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
196
                                INCA(a1);
197
                                set_bit(bnep_mc_hash(a1), &s->mc_filter);
198
                        }
199
                }
200
        }
201
 
202
        BT_DBG("mc filter hash 0x%llx", s->mc_filter);
203
 
204
        bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
205
#else
206
        bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
207
#endif
208
        return 0;
209
}
210
 
211
static int bnep_rx_control(struct bnep_session *s, void *data, int len)
212
{
213
        u8  cmd = *(u8 *)data;
214
        int err = 0;
215
 
216
        data++; len--;
217
 
218
        switch (cmd) {
219
        case BNEP_CMD_NOT_UNDERSTOOD:
220
        case BNEP_SETUP_CONN_REQ:
221
        case BNEP_SETUP_CONN_RSP:
222
        case BNEP_FILTER_NET_TYPE_RSP:
223
        case BNEP_FILTER_MULTI_ADDR_RSP:
224
                /* Ignore these for now */
225
                break;
226
 
227
        case BNEP_FILTER_NET_TYPE_SET:
228
                err = bnep_ctrl_set_netfilter(s, data, len);
229
                break;
230
 
231
        case BNEP_FILTER_MULTI_ADDR_SET:
232
                err = bnep_ctrl_set_mcfilter(s, data, len);
233
                break;
234
 
235
        default: {
236
                        u8 pkt[3];
237
                        pkt[0] = BNEP_CONTROL;
238
                        pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
239
                        pkt[2] = cmd;
240
                        bnep_send(s, pkt, sizeof(pkt));
241
                }
242
                break;
243
        }
244
 
245
        return err;
246
}
247
 
248
static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
249
{
250
        struct bnep_ext_hdr *h;
251
        int err = 0;
252
 
253
        do {
254
                h = (void *) skb->data;
255
                if (!skb_pull(skb, sizeof(*h))) {
256
                        err = -EILSEQ;
257
                        break;
258
                }
259
 
260
                BT_DBG("type 0x%x len %d", h->type, h->len);
261
 
262
                switch (h->type & BNEP_TYPE_MASK) {
263
                case BNEP_EXT_CONTROL:
264
                        bnep_rx_control(s, skb->data, skb->len);
265
                        break;
266
 
267
                default:
268
                        /* Unknown extension, skip it. */
269
                        break;
270
                }
271
 
272
                if (!skb_pull(skb, h->len)) {
273
                        err = -EILSEQ;
274
                        break;
275
                }
276
        } while (!err && (h->type & BNEP_EXT_HEADER));
277
 
278
        return err;
279
}
280
 
281
static u8 __bnep_rx_hlen[] = {
282
        ETH_HLEN,     /* BNEP_GENERAL */
283
        0,            /* BNEP_CONTROL */
284
        2,            /* BNEP_COMPRESSED */
285
        ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
286
        ETH_ALEN + 2  /* BNEP_COMPRESSED_DST_ONLY */
287
};
288
#define BNEP_RX_TYPES   (sizeof(__bnep_rx_hlen) - 1)
289
 
290
static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
291
{
292
        struct net_device *dev = &s->dev;
293
        struct sk_buff *nskb;
294
        u8 type;
295
 
296
        dev->last_rx = jiffies;
297
        s->stats.rx_bytes += skb->len;
298
 
299
        type = *(u8 *) skb->data; skb_pull(skb, 1);
300
 
301
        if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
302
                goto badframe;
303
 
304
        if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
305
                bnep_rx_control(s, skb->data, skb->len);
306
                kfree_skb(skb);
307
                return 0;
308
        }
309
 
310
        skb->mac.raw = skb->data;
311
 
312
        /* Verify and pull out header */
313
        if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
314
                goto badframe;
315
 
316
        s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
317
 
318
        if (type & BNEP_EXT_HEADER) {
319
                if (bnep_rx_extension(s, skb) < 0)
320
                        goto badframe;
321
        }
322
 
323
        /* Strip 802.1p header */
324
        if (ntohs(s->eh.h_proto) == 0x8100) {
325
                if (!skb_pull(skb, 4))
326
                        goto badframe;
327
                s->eh.h_proto = get_unaligned((u16 *) (skb->data - 2));
328
        }
329
 
330
        /* We have to alloc new skb and copy data here :(. Because original skb
331
         * may not be modified and because of the alignment requirements. */
332
        nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
333
        if (!nskb) {
334
                s->stats.rx_dropped++;
335
                kfree_skb(skb);
336
                return -ENOMEM;
337
        }
338
        skb_reserve(nskb, 2);
339
 
340
        /* Decompress header and construct ether frame */
341
        switch (type & BNEP_TYPE_MASK) {
342
        case BNEP_COMPRESSED:
343
                memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
344
                break;
345
 
346
        case BNEP_COMPRESSED_SRC_ONLY:
347
                memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
348
                memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
349
                put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
350
                break;
351
 
352
        case BNEP_COMPRESSED_DST_ONLY:
353
                memcpy(__skb_put(nskb, ETH_ALEN), skb->mac.raw, ETH_ALEN);
354
                memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source, ETH_ALEN + 2);
355
                break;
356
 
357
        case BNEP_GENERAL:
358
                memcpy(__skb_put(nskb, ETH_ALEN * 2), skb->mac.raw, ETH_ALEN * 2);
359
                put_unaligned(s->eh.h_proto, (u16 *) __skb_put(nskb, 2));
360
                break;
361
        }
362
 
363
        memcpy(__skb_put(nskb, skb->len), skb->data, skb->len);
364
        kfree_skb(skb);
365
 
366
        s->stats.rx_packets++;
367
        nskb->dev       = dev;
368
        nskb->ip_summed = CHECKSUM_UNNECESSARY;
369
        nskb->protocol  = eth_type_trans(nskb, dev);
370
        netif_rx_ni(nskb);
371
        return 0;
372
 
373
badframe:
374
        s->stats.rx_errors++;
375
        kfree_skb(skb);
376
        return 0;
377
}
378
 
379
static u8 __bnep_tx_types[] = {
380
        BNEP_GENERAL,
381
        BNEP_COMPRESSED_SRC_ONLY,
382
        BNEP_COMPRESSED_DST_ONLY,
383
        BNEP_COMPRESSED
384
};
385
 
386
static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
387
{
388
        struct ethhdr *eh = (void *) skb->data;
389
        struct socket *sock = s->sock;
390
        struct iovec iv[3];
391
        int len = 0, il = 0;
392
        u8 type = 0;
393
 
394
        BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
395
 
396
        if (!skb->dev) {
397
                /* Control frame sent by us */
398
                goto send;
399
        }
400
 
401
        iv[il++] = (struct iovec) { &type, 1 };
402
        len++;
403
 
404
        if (!memcmp(eh->h_dest, s->eh.h_source, ETH_ALEN))
405
                type |= 0x01;
406
 
407
        if (!memcmp(eh->h_source, s->eh.h_dest, ETH_ALEN))
408
                type |= 0x02;
409
 
410
        if (type)
411
                skb_pull(skb, ETH_ALEN * 2);
412
 
413
        type = __bnep_tx_types[type];
414
        switch (type) {
415
        case BNEP_COMPRESSED_SRC_ONLY:
416
                iv[il++] = (struct iovec) { eh->h_source, ETH_ALEN };
417
                len += ETH_ALEN;
418
                break;
419
 
420
        case BNEP_COMPRESSED_DST_ONLY:
421
                iv[il++] = (struct iovec) { eh->h_dest, ETH_ALEN };
422
                len += ETH_ALEN;
423
                break;
424
        }
425
 
426
send:
427
        iv[il++] = (struct iovec) { skb->data, skb->len };
428
        len += skb->len;
429
 
430
        /* FIXME: linearize skb */
431
 
432
        s->msg.msg_iov    = iv;
433
        s->msg.msg_iovlen = il;
434
        len = sock->ops->sendmsg(sock, &s->msg, len, NULL);
435
        kfree_skb(skb);
436
 
437
        if (len > 0) {
438
                s->stats.tx_bytes += len;
439
                s->stats.tx_packets++;
440
                return 0;
441
        }
442
 
443
        return len;
444
}
445
 
446
static int bnep_session(void *arg)
447
{
448
        struct bnep_session *s = arg;
449
        struct net_device *dev = &s->dev;
450
        struct sock *sk = s->sock->sk;
451
        struct sk_buff *skb;
452
        wait_queue_t wait;
453
 
454
        BT_DBG("");
455
 
456
        daemonize(); reparent_to_init();
457
 
458
        sprintf(current->comm, "kbnepd %s", dev->name);
459
 
460
        sigfillset(&current->blocked);
461
        flush_signals(current);
462
 
463
        current->nice = -15;
464
 
465
        set_fs(KERNEL_DS);
466
 
467
        init_waitqueue_entry(&wait, current);
468
        add_wait_queue(sk->sleep, &wait);
469
        while (!atomic_read(&s->killed)) {
470
                set_current_state(TASK_INTERRUPTIBLE);
471
 
472
                // RX
473
                while ((skb = skb_dequeue(&sk->receive_queue))) {
474
                        skb_orphan(skb);
475
                        bnep_rx_frame(s, skb);
476
                }
477
 
478
                if (sk->state != BT_CONNECTED)
479
                        break;
480
 
481
                // TX
482
                while ((skb = skb_dequeue(&sk->write_queue)))
483
                        if (bnep_tx_frame(s, skb))
484
                                break;
485
                netif_wake_queue(dev);
486
 
487
                schedule();
488
        }
489
        set_current_state(TASK_RUNNING);
490
        remove_wait_queue(sk->sleep, &wait);
491
 
492
        /* Cleanup session */
493
        down_write(&bnep_session_sem);
494
 
495
        /* Delete network device */
496
        unregister_netdev(dev);
497
 
498
        /* Release the socket */
499
        fput(s->sock->file);
500
 
501
        __bnep_unlink_session(s);
502
 
503
        up_write(&bnep_session_sem);
504
        kfree(s);
505
        return 0;
506
}
507
 
508
int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
509
{
510
        struct net_device *dev;
511
        struct bnep_session *s, *ss;
512
        u8 dst[ETH_ALEN], src[ETH_ALEN];
513
        int err;
514
 
515
        BT_DBG("");
516
 
517
        baswap((void *) dst, &bluez_pi(sock->sk)->dst);
518
        baswap((void *) src, &bluez_pi(sock->sk)->src);
519
 
520
        s = kmalloc(sizeof(struct bnep_session), GFP_KERNEL);
521
        if (!s)
522
                return -ENOMEM;
523
        memset(s, 0, sizeof(struct bnep_session));
524
 
525
        down_write(&bnep_session_sem);
526
 
527
        ss = __bnep_get_session(dst);
528
        if (ss && ss->state == BT_CONNECTED) {
529
                err = -EEXIST;
530
                goto failed;
531
        }
532
 
533
        dev = &s->dev;
534
 
535
        if (*req->device)
536
                strcpy(dev->name, req->device);
537
        else
538
                strcpy(dev->name, "bnep%d");
539
 
540
        memset(dev->broadcast, 0xff, ETH_ALEN);
541
 
542
        /* This is rx header therefor addresses are swaped.
543
         * ie eh.h_dest is our local address. */
544
        memcpy(s->eh.h_dest,   &src, ETH_ALEN);
545
        memcpy(s->eh.h_source, &dst, ETH_ALEN);
546
 
547
        s->sock  = sock;
548
        s->role  = req->role;
549
        s->state = BT_CONNECTED;
550
 
551
        s->msg.msg_flags = MSG_NOSIGNAL;
552
 
553
#ifdef CONFIG_BLUEZ_BNEP_MC_FILTER
554
        /* Set default mc filter */
555
        set_bit(bnep_mc_hash(dev->broadcast), &s->mc_filter);
556
#endif
557
 
558
#ifdef CONFIG_BLUEZ_BNEP_PROTO_FILTER
559
        /* Set default protocol filter */
560
 
561
        /* (IPv4, ARP)  */
562
        s->proto_filter[0].start = htons(0x0800);
563
        s->proto_filter[0].end   = htons(0x0806);
564
        /* (RARP, AppleTalk) */
565
        s->proto_filter[1].start = htons(0x8035);
566
        s->proto_filter[1].end   = htons(0x80F3);
567
        /* (IPX, IPv6) */
568
        s->proto_filter[2].start = htons(0x8137);
569
        s->proto_filter[2].end   = htons(0x86DD);
570
#endif
571
 
572
        dev->init = bnep_net_init;
573
        dev->priv = s;
574
        err = register_netdev(dev);
575
        if (err) {
576
                goto failed;
577
        }
578
 
579
        __bnep_link_session(s);
580
 
581
        err = kernel_thread(bnep_session, s, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
582
        if (err < 0) {
583
                /* Session thread start failed, gotta cleanup. */
584
                unregister_netdev(dev);
585
                __bnep_unlink_session(s);
586
                goto failed;
587
        }
588
 
589
        up_write(&bnep_session_sem);
590
        strcpy(req->device, dev->name);
591
        return 0;
592
 
593
failed:
594
        up_write(&bnep_session_sem);
595
        kfree(s);
596
        return err;
597
}
598
 
599
int bnep_del_connection(struct bnep_conndel_req *req)
600
{
601
        struct bnep_session *s;
602
        int  err = 0;
603
 
604
        BT_DBG("");
605
 
606
        down_read(&bnep_session_sem);
607
 
608
        s = __bnep_get_session(req->dst);
609
        if (s) {
610
                /* Wakeup user-space which is polling for socket errors.
611
                 * This is temporary hack untill we have shutdown in L2CAP */
612
                s->sock->sk->err = EUNATCH;
613
 
614
                /* Kill session thread */
615
                atomic_inc(&s->killed);
616
                wake_up_interruptible(s->sock->sk->sleep);
617
        } else
618
                err = -ENOENT;
619
 
620
        up_read(&bnep_session_sem);
621
        return err;
622
}
623
 
624
static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
625
{
626
        memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
627
        strcpy(ci->device, s->dev.name);
628
        ci->flags = s->flags;
629
        ci->state = s->state;
630
        ci->role  = s->role;
631
}
632
 
633
int bnep_get_connlist(struct bnep_connlist_req *req)
634
{
635
        struct list_head *p;
636
        int err = 0, n = 0;
637
 
638
        down_read(&bnep_session_sem);
639
 
640
        list_for_each(p, &bnep_session_list) {
641
                struct bnep_session *s;
642
                struct bnep_conninfo ci;
643
 
644
                s = list_entry(p, struct bnep_session, list);
645
 
646
                __bnep_copy_ci(&ci, s);
647
 
648
                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
649
                        err = -EFAULT;
650
                        break;
651
                }
652
 
653
                if (++n >= req->cnum)
654
                        break;
655
 
656
                req->ci++;
657
        }
658
        req->cnum = n;
659
 
660
        up_read(&bnep_session_sem);
661
        return err;
662
}
663
 
664
int bnep_get_conninfo(struct bnep_conninfo *ci)
665
{
666
        struct bnep_session *s;
667
        int err = 0;
668
 
669
        down_read(&bnep_session_sem);
670
 
671
        s = __bnep_get_session(ci->dst);
672
        if (s)
673
                __bnep_copy_ci(ci, s);
674
        else
675
                err = -ENOENT;
676
 
677
        up_read(&bnep_session_sem);
678
        return err;
679
}
680
 
681
static int __init bnep_init_module(void)
682
{
683
        l2cap_load();
684
 
685
        bnep_sock_init();
686
 
687
        BT_INFO("BlueZ BNEP ver %s", VERSION);
688
        BT_INFO("Copyright (C) 2001,2002 Inventel Systemes");
689
        BT_INFO("Written 2001,2002 by Clement Moreau <clement.moreau@inventel.fr>");
690
        BT_INFO("Written 2001,2002 by David Libault <david.libault@inventel.fr>");
691
        BT_INFO("Copyright (C) 2002 Maxim Krasnyanskiy <maxk@qualcomm.com>");
692
 
693
        return 0;
694
}
695
 
696
static void __exit bnep_cleanup_module(void)
697
{
698
        bnep_sock_cleanup();
699
}
700
 
701
module_init(bnep_init_module);
702
module_exit(bnep_cleanup_module);
703
 
704
MODULE_DESCRIPTION("BlueZ BNEP ver " VERSION);
705
MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyanskiy <maxk@qualcomm.com>");
706
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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