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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [net/] [bluetooth/] [bnep/] [core.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
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 Krasnyansky <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.20 2002/08/04 21:23:58 maxk Exp $
30
 */
31
 
32
#include <linux/module.h>
33
 
34
#include <linux/kernel.h>
35
#include <linux/sched.h>
36
#include <linux/signal.h>
37
#include <linux/init.h>
38
#include <linux/wait.h>
39
#include <linux/freezer.h>
40
#include <linux/errno.h>
41
#include <linux/net.h>
42
#include <net/sock.h>
43
 
44
#include <linux/socket.h>
45
#include <linux/file.h>
46
 
47
#include <linux/netdevice.h>
48
#include <linux/etherdevice.h>
49
#include <linux/skbuff.h>
50
 
51
#include <asm/unaligned.h>
52
 
53
#include <net/bluetooth/bluetooth.h>
54
#include <net/bluetooth/hci_core.h>
55
#include <net/bluetooth/l2cap.h>
56
 
57
#include "bnep.h"
58
 
59
#ifndef CONFIG_BT_BNEP_DEBUG
60
#undef  BT_DBG
61
#define BT_DBG(D...)
62
#endif
63
 
64
#define VERSION "1.2"
65
 
66
static LIST_HEAD(bnep_session_list);
67
static DECLARE_RWSEM(bnep_session_sem);
68
 
69
static struct bnep_session *__bnep_get_session(u8 *dst)
70
{
71
        struct bnep_session *s;
72
        struct list_head *p;
73
 
74
        BT_DBG("");
75
 
76
        list_for_each(p, &bnep_session_list) {
77
                s = list_entry(p, struct bnep_session, list);
78
                if (!compare_ether_addr(dst, s->eh.h_source))
79
                        return s;
80
        }
81
        return NULL;
82
}
83
 
84
static void __bnep_link_session(struct bnep_session *s)
85
{
86
        /* It's safe to call __module_get() here because sessions are added
87
           by the socket layer which has to hold the refference to this module.
88
         */
89
        __module_get(THIS_MODULE);
90
        list_add(&s->list, &bnep_session_list);
91
}
92
 
93
static void __bnep_unlink_session(struct bnep_session *s)
94
{
95
        list_del(&s->list);
96
        module_put(THIS_MODULE);
97
}
98
 
99
static int bnep_send(struct bnep_session *s, void *data, size_t len)
100
{
101
        struct socket *sock = s->sock;
102
        struct kvec iv = { data, len };
103
 
104
        return kernel_sendmsg(sock, &s->msg, &iv, 1, len);
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
#ifdef CONFIG_BT_BNEP_PROTO_FILTER
117
static inline void bnep_set_default_proto_filter(struct bnep_session *s)
118
{
119
        /* (IPv4, ARP)  */
120
        s->proto_filter[0].start = ETH_P_IP;
121
        s->proto_filter[0].end   = ETH_P_ARP;
122
        /* (RARP, AppleTalk) */
123
        s->proto_filter[1].start = ETH_P_RARP;
124
        s->proto_filter[1].end   = ETH_P_AARP;
125
        /* (IPX, IPv6) */
126
        s->proto_filter[2].start = ETH_P_IPX;
127
        s->proto_filter[2].end   = ETH_P_IPV6;
128
}
129
#endif
130
 
131
static int bnep_ctrl_set_netfilter(struct bnep_session *s, __be16 *data, int len)
132
{
133
        int n;
134
 
135
        if (len < 2)
136
                return -EILSEQ;
137
 
138
        n = ntohs(get_unaligned(data));
139
        data++; len -= 2;
140
 
141
        if (len < n)
142
                return -EILSEQ;
143
 
144
        BT_DBG("filter len %d", n);
145
 
146
#ifdef CONFIG_BT_BNEP_PROTO_FILTER
147
        n /= 4;
148
        if (n <= BNEP_MAX_PROTO_FILTERS) {
149
                struct bnep_proto_filter *f = s->proto_filter;
150
                int i;
151
 
152
                for (i = 0; i < n; i++) {
153
                        f[i].start = ntohs(get_unaligned(data++));
154
                        f[i].end   = ntohs(get_unaligned(data++));
155
 
156
                        BT_DBG("proto filter start %d end %d",
157
                                f[i].start, f[i].end);
158
                }
159
 
160
                if (i < BNEP_MAX_PROTO_FILTERS)
161
                        memset(f + i, 0, sizeof(*f));
162
 
163
                if (n == 0)
164
                        bnep_set_default_proto_filter(s);
165
 
166
                bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_SUCCESS);
167
        } else {
168
                bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_LIMIT_REACHED);
169
        }
170
#else
171
        bnep_send_rsp(s, BNEP_FILTER_NET_TYPE_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
172
#endif
173
        return 0;
174
}
175
 
176
static int bnep_ctrl_set_mcfilter(struct bnep_session *s, u8 *data, int len)
177
{
178
        int n;
179
 
180
        if (len < 2)
181
                return -EILSEQ;
182
 
183
        n = ntohs(get_unaligned((__be16 *) data));
184
        data += 2; len -= 2;
185
 
186
        if (len < n)
187
                return -EILSEQ;
188
 
189
        BT_DBG("filter len %d", n);
190
 
191
#ifdef CONFIG_BT_BNEP_MC_FILTER
192
        n /= (ETH_ALEN * 2);
193
 
194
        if (n > 0) {
195
                s->mc_filter = 0;
196
 
197
                /* Always send broadcast */
198
                set_bit(bnep_mc_hash(s->dev->broadcast), (ulong *) &s->mc_filter);
199
 
200
                /* Add address ranges to the multicast hash */
201
                for (; n > 0; n--) {
202
                        u8 a1[6], *a2;
203
 
204
                        memcpy(a1, data, ETH_ALEN); data += ETH_ALEN;
205
                        a2 = data; data += ETH_ALEN;
206
 
207
                        BT_DBG("mc filter %s -> %s",
208
                                batostr((void *) a1), batostr((void *) a2));
209
 
210
                        #define INCA(a) { int i = 5; while (i >=0 && ++a[i--] == 0); }
211
 
212
                        /* Iterate from a1 to a2 */
213
                        set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
214
                        while (memcmp(a1, a2, 6) < 0 && s->mc_filter != ~0LL) {
215
                                INCA(a1);
216
                                set_bit(bnep_mc_hash(a1), (ulong *) &s->mc_filter);
217
                        }
218
                }
219
        }
220
 
221
        BT_DBG("mc filter hash 0x%llx", s->mc_filter);
222
 
223
        bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_SUCCESS);
224
#else
225
        bnep_send_rsp(s, BNEP_FILTER_MULTI_ADDR_RSP, BNEP_FILTER_UNSUPPORTED_REQ);
226
#endif
227
        return 0;
228
}
229
 
230
static int bnep_rx_control(struct bnep_session *s, void *data, int len)
231
{
232
        u8  cmd = *(u8 *)data;
233
        int err = 0;
234
 
235
        data++; len--;
236
 
237
        switch (cmd) {
238
        case BNEP_CMD_NOT_UNDERSTOOD:
239
        case BNEP_SETUP_CONN_REQ:
240
        case BNEP_SETUP_CONN_RSP:
241
        case BNEP_FILTER_NET_TYPE_RSP:
242
        case BNEP_FILTER_MULTI_ADDR_RSP:
243
                /* Ignore these for now */
244
                break;
245
 
246
        case BNEP_FILTER_NET_TYPE_SET:
247
                err = bnep_ctrl_set_netfilter(s, data, len);
248
                break;
249
 
250
        case BNEP_FILTER_MULTI_ADDR_SET:
251
                err = bnep_ctrl_set_mcfilter(s, data, len);
252
                break;
253
 
254
        default: {
255
                        u8 pkt[3];
256
                        pkt[0] = BNEP_CONTROL;
257
                        pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
258
                        pkt[2] = cmd;
259
                        bnep_send(s, pkt, sizeof(pkt));
260
                }
261
                break;
262
        }
263
 
264
        return err;
265
}
266
 
267
static int bnep_rx_extension(struct bnep_session *s, struct sk_buff *skb)
268
{
269
        struct bnep_ext_hdr *h;
270
        int err = 0;
271
 
272
        do {
273
                h = (void *) skb->data;
274
                if (!skb_pull(skb, sizeof(*h))) {
275
                        err = -EILSEQ;
276
                        break;
277
                }
278
 
279
                BT_DBG("type 0x%x len %d", h->type, h->len);
280
 
281
                switch (h->type & BNEP_TYPE_MASK) {
282
                case BNEP_EXT_CONTROL:
283
                        bnep_rx_control(s, skb->data, skb->len);
284
                        break;
285
 
286
                default:
287
                        /* Unknown extension, skip it. */
288
                        break;
289
                }
290
 
291
                if (!skb_pull(skb, h->len)) {
292
                        err = -EILSEQ;
293
                        break;
294
                }
295
        } while (!err && (h->type & BNEP_EXT_HEADER));
296
 
297
        return err;
298
}
299
 
300
static u8 __bnep_rx_hlen[] = {
301
        ETH_HLEN,     /* BNEP_GENERAL */
302
        0,            /* BNEP_CONTROL */
303
        2,            /* BNEP_COMPRESSED */
304
        ETH_ALEN + 2, /* BNEP_COMPRESSED_SRC_ONLY */
305
        ETH_ALEN + 2  /* BNEP_COMPRESSED_DST_ONLY */
306
};
307
#define BNEP_RX_TYPES   (sizeof(__bnep_rx_hlen) - 1)
308
 
309
static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb)
310
{
311
        struct net_device *dev = s->dev;
312
        struct sk_buff *nskb;
313
        u8 type;
314
 
315
        dev->last_rx = jiffies;
316
        s->stats.rx_bytes += skb->len;
317
 
318
        type = *(u8 *) skb->data; skb_pull(skb, 1);
319
 
320
        if ((type & BNEP_TYPE_MASK) > BNEP_RX_TYPES)
321
                goto badframe;
322
 
323
        if ((type & BNEP_TYPE_MASK) == BNEP_CONTROL) {
324
                bnep_rx_control(s, skb->data, skb->len);
325
                kfree_skb(skb);
326
                return 0;
327
        }
328
 
329
        skb_reset_mac_header(skb);
330
 
331
        /* Verify and pull out header */
332
        if (!skb_pull(skb, __bnep_rx_hlen[type & BNEP_TYPE_MASK]))
333
                goto badframe;
334
 
335
        s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
336
 
337
        if (type & BNEP_EXT_HEADER) {
338
                if (bnep_rx_extension(s, skb) < 0)
339
                        goto badframe;
340
        }
341
 
342
        /* Strip 802.1p header */
343
        if (ntohs(s->eh.h_proto) == 0x8100) {
344
                if (!skb_pull(skb, 4))
345
                        goto badframe;
346
                s->eh.h_proto = get_unaligned((__be16 *) (skb->data - 2));
347
        }
348
 
349
        /* We have to alloc new skb and copy data here :(. Because original skb
350
         * may not be modified and because of the alignment requirements. */
351
        nskb = alloc_skb(2 + ETH_HLEN + skb->len, GFP_KERNEL);
352
        if (!nskb) {
353
                s->stats.rx_dropped++;
354
                kfree_skb(skb);
355
                return -ENOMEM;
356
        }
357
        skb_reserve(nskb, 2);
358
 
359
        /* Decompress header and construct ether frame */
360
        switch (type & BNEP_TYPE_MASK) {
361
        case BNEP_COMPRESSED:
362
                memcpy(__skb_put(nskb, ETH_HLEN), &s->eh, ETH_HLEN);
363
                break;
364
 
365
        case BNEP_COMPRESSED_SRC_ONLY:
366
                memcpy(__skb_put(nskb, ETH_ALEN), s->eh.h_dest, ETH_ALEN);
367
                memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb), ETH_ALEN);
368
                put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
369
                break;
370
 
371
        case BNEP_COMPRESSED_DST_ONLY:
372
                memcpy(__skb_put(nskb, ETH_ALEN), skb_mac_header(skb),
373
                       ETH_ALEN);
374
                memcpy(__skb_put(nskb, ETH_ALEN + 2), s->eh.h_source,
375
                       ETH_ALEN + 2);
376
                break;
377
 
378
        case BNEP_GENERAL:
379
                memcpy(__skb_put(nskb, ETH_ALEN * 2), skb_mac_header(skb),
380
                       ETH_ALEN * 2);
381
                put_unaligned(s->eh.h_proto, (__be16 *) __skb_put(nskb, 2));
382
                break;
383
        }
384
 
385
        skb_copy_from_linear_data(skb, __skb_put(nskb, skb->len), skb->len);
386
        kfree_skb(skb);
387
 
388
        s->stats.rx_packets++;
389
        nskb->ip_summed = CHECKSUM_NONE;
390
        nskb->protocol  = eth_type_trans(nskb, dev);
391
        netif_rx_ni(nskb);
392
        return 0;
393
 
394
badframe:
395
        s->stats.rx_errors++;
396
        kfree_skb(skb);
397
        return 0;
398
}
399
 
400
static u8 __bnep_tx_types[] = {
401
        BNEP_GENERAL,
402
        BNEP_COMPRESSED_SRC_ONLY,
403
        BNEP_COMPRESSED_DST_ONLY,
404
        BNEP_COMPRESSED
405
};
406
 
407
static inline int bnep_tx_frame(struct bnep_session *s, struct sk_buff *skb)
408
{
409
        struct ethhdr *eh = (void *) skb->data;
410
        struct socket *sock = s->sock;
411
        struct kvec iv[3];
412
        int len = 0, il = 0;
413
        u8 type = 0;
414
 
415
        BT_DBG("skb %p dev %p type %d", skb, skb->dev, skb->pkt_type);
416
 
417
        if (!skb->dev) {
418
                /* Control frame sent by us */
419
                goto send;
420
        }
421
 
422
        iv[il++] = (struct kvec) { &type, 1 };
423
        len++;
424
 
425
        if (!compare_ether_addr(eh->h_dest, s->eh.h_source))
426
                type |= 0x01;
427
 
428
        if (!compare_ether_addr(eh->h_source, s->eh.h_dest))
429
                type |= 0x02;
430
 
431
        if (type)
432
                skb_pull(skb, ETH_ALEN * 2);
433
 
434
        type = __bnep_tx_types[type];
435
        switch (type) {
436
        case BNEP_COMPRESSED_SRC_ONLY:
437
                iv[il++] = (struct kvec) { eh->h_source, ETH_ALEN };
438
                len += ETH_ALEN;
439
                break;
440
 
441
        case BNEP_COMPRESSED_DST_ONLY:
442
                iv[il++] = (struct kvec) { eh->h_dest, ETH_ALEN };
443
                len += ETH_ALEN;
444
                break;
445
        }
446
 
447
send:
448
        iv[il++] = (struct kvec) { skb->data, skb->len };
449
        len += skb->len;
450
 
451
        /* FIXME: linearize skb */
452
        {
453
                len = kernel_sendmsg(sock, &s->msg, iv, il, len);
454
        }
455
        kfree_skb(skb);
456
 
457
        if (len > 0) {
458
                s->stats.tx_bytes += len;
459
                s->stats.tx_packets++;
460
                return 0;
461
        }
462
 
463
        return len;
464
}
465
 
466
static int bnep_session(void *arg)
467
{
468
        struct bnep_session *s = arg;
469
        struct net_device *dev = s->dev;
470
        struct sock *sk = s->sock->sk;
471
        struct sk_buff *skb;
472
        wait_queue_t wait;
473
 
474
        BT_DBG("");
475
 
476
        daemonize("kbnepd %s", dev->name);
477
        set_user_nice(current, -15);
478
 
479
        init_waitqueue_entry(&wait, current);
480
        add_wait_queue(sk->sk_sleep, &wait);
481
        while (!atomic_read(&s->killed)) {
482
                set_current_state(TASK_INTERRUPTIBLE);
483
 
484
                // RX
485
                while ((skb = skb_dequeue(&sk->sk_receive_queue))) {
486
                        skb_orphan(skb);
487
                        bnep_rx_frame(s, skb);
488
                }
489
 
490
                if (sk->sk_state != BT_CONNECTED)
491
                        break;
492
 
493
                // TX
494
                while ((skb = skb_dequeue(&sk->sk_write_queue)))
495
                        if (bnep_tx_frame(s, skb))
496
                                break;
497
                netif_wake_queue(dev);
498
 
499
                schedule();
500
        }
501
        set_current_state(TASK_RUNNING);
502
        remove_wait_queue(sk->sk_sleep, &wait);
503
 
504
        /* Cleanup session */
505
        down_write(&bnep_session_sem);
506
 
507
        /* Delete network device */
508
        unregister_netdev(dev);
509
 
510
        /* Release the socket */
511
        fput(s->sock->file);
512
 
513
        __bnep_unlink_session(s);
514
 
515
        up_write(&bnep_session_sem);
516
        free_netdev(dev);
517
        return 0;
518
}
519
 
520
static struct device *bnep_get_device(struct bnep_session *session)
521
{
522
        bdaddr_t *src = &bt_sk(session->sock->sk)->src;
523
        bdaddr_t *dst = &bt_sk(session->sock->sk)->dst;
524
        struct hci_dev *hdev;
525
        struct hci_conn *conn;
526
 
527
        hdev = hci_get_route(dst, src);
528
        if (!hdev)
529
                return NULL;
530
 
531
        conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
532
 
533
        hci_dev_put(hdev);
534
 
535
        return conn ? &conn->dev : NULL;
536
}
537
 
538
int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock)
539
{
540
        struct net_device *dev;
541
        struct bnep_session *s, *ss;
542
        u8 dst[ETH_ALEN], src[ETH_ALEN];
543
        int err;
544
 
545
        BT_DBG("");
546
 
547
        baswap((void *) dst, &bt_sk(sock->sk)->dst);
548
        baswap((void *) src, &bt_sk(sock->sk)->src);
549
 
550
        /* session struct allocated as private part of net_device */
551
        dev = alloc_netdev(sizeof(struct bnep_session),
552
                           (*req->device) ? req->device : "bnep%d",
553
                           bnep_net_setup);
554
        if (!dev)
555
                return -ENOMEM;
556
 
557
        down_write(&bnep_session_sem);
558
 
559
        ss = __bnep_get_session(dst);
560
        if (ss && ss->state == BT_CONNECTED) {
561
                err = -EEXIST;
562
                goto failed;
563
        }
564
 
565
        s = dev->priv;
566
 
567
        /* This is rx header therefore addresses are swapped.
568
         * ie eh.h_dest is our local address. */
569
        memcpy(s->eh.h_dest,   &src, ETH_ALEN);
570
        memcpy(s->eh.h_source, &dst, ETH_ALEN);
571
        memcpy(dev->dev_addr, s->eh.h_dest, ETH_ALEN);
572
 
573
        s->dev   = dev;
574
        s->sock  = sock;
575
        s->role  = req->role;
576
        s->state = BT_CONNECTED;
577
 
578
        s->msg.msg_flags = MSG_NOSIGNAL;
579
 
580
#ifdef CONFIG_BT_BNEP_MC_FILTER
581
        /* Set default mc filter */
582
        set_bit(bnep_mc_hash(dev->broadcast), (ulong *) &s->mc_filter);
583
#endif
584
 
585
#ifdef CONFIG_BT_BNEP_PROTO_FILTER
586
        /* Set default protocol filter */
587
        bnep_set_default_proto_filter(s);
588
#endif
589
 
590
        SET_NETDEV_DEV(dev, bnep_get_device(s));
591
 
592
        err = register_netdev(dev);
593
        if (err) {
594
                goto failed;
595
        }
596
 
597
        __bnep_link_session(s);
598
 
599
        err = kernel_thread(bnep_session, s, CLONE_KERNEL);
600
        if (err < 0) {
601
                /* Session thread start failed, gotta cleanup. */
602
                unregister_netdev(dev);
603
                __bnep_unlink_session(s);
604
                goto failed;
605
        }
606
 
607
        up_write(&bnep_session_sem);
608
        strcpy(req->device, dev->name);
609
        return 0;
610
 
611
failed:
612
        up_write(&bnep_session_sem);
613
        free_netdev(dev);
614
        return err;
615
}
616
 
617
int bnep_del_connection(struct bnep_conndel_req *req)
618
{
619
        struct bnep_session *s;
620
        int  err = 0;
621
 
622
        BT_DBG("");
623
 
624
        down_read(&bnep_session_sem);
625
 
626
        s = __bnep_get_session(req->dst);
627
        if (s) {
628
                /* Wakeup user-space which is polling for socket errors.
629
                 * This is temporary hack untill we have shutdown in L2CAP */
630
                s->sock->sk->sk_err = EUNATCH;
631
 
632
                /* Kill session thread */
633
                atomic_inc(&s->killed);
634
                wake_up_interruptible(s->sock->sk->sk_sleep);
635
        } else
636
                err = -ENOENT;
637
 
638
        up_read(&bnep_session_sem);
639
        return err;
640
}
641
 
642
static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
643
{
644
        memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
645
        strcpy(ci->device, s->dev->name);
646
        ci->flags = s->flags;
647
        ci->state = s->state;
648
        ci->role  = s->role;
649
}
650
 
651
int bnep_get_connlist(struct bnep_connlist_req *req)
652
{
653
        struct list_head *p;
654
        int err = 0, n = 0;
655
 
656
        down_read(&bnep_session_sem);
657
 
658
        list_for_each(p, &bnep_session_list) {
659
                struct bnep_session *s;
660
                struct bnep_conninfo ci;
661
 
662
                s = list_entry(p, struct bnep_session, list);
663
 
664
                __bnep_copy_ci(&ci, s);
665
 
666
                if (copy_to_user(req->ci, &ci, sizeof(ci))) {
667
                        err = -EFAULT;
668
                        break;
669
                }
670
 
671
                if (++n >= req->cnum)
672
                        break;
673
 
674
                req->ci++;
675
        }
676
        req->cnum = n;
677
 
678
        up_read(&bnep_session_sem);
679
        return err;
680
}
681
 
682
int bnep_get_conninfo(struct bnep_conninfo *ci)
683
{
684
        struct bnep_session *s;
685
        int err = 0;
686
 
687
        down_read(&bnep_session_sem);
688
 
689
        s = __bnep_get_session(ci->dst);
690
        if (s)
691
                __bnep_copy_ci(ci, s);
692
        else
693
                err = -ENOENT;
694
 
695
        up_read(&bnep_session_sem);
696
        return err;
697
}
698
 
699
static int __init bnep_init(void)
700
{
701
        char flt[50] = "";
702
 
703
        l2cap_load();
704
 
705
#ifdef CONFIG_BT_BNEP_PROTO_FILTER
706
        strcat(flt, "protocol ");
707
#endif
708
 
709
#ifdef CONFIG_BT_BNEP_MC_FILTER
710
        strcat(flt, "multicast");
711
#endif
712
 
713
        BT_INFO("BNEP (Ethernet Emulation) ver %s", VERSION);
714
        if (flt[0])
715
                BT_INFO("BNEP filters: %s", flt);
716
 
717
        bnep_sock_init();
718
        return 0;
719
}
720
 
721
static void __exit bnep_exit(void)
722
{
723
        bnep_sock_cleanup();
724
}
725
 
726
module_init(bnep_init);
727
module_exit(bnep_exit);
728
 
729
MODULE_AUTHOR("David Libault <david.libault@inventel.fr>, Maxim Krasnyansky <maxk@qualcomm.com>");
730
MODULE_DESCRIPTION("Bluetooth BNEP ver " VERSION);
731
MODULE_VERSION(VERSION);
732
MODULE_LICENSE("GPL");
733
MODULE_ALIAS("bt-proto-4");

powered by: WebSVN 2.1.0

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