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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
Experimental ethernet netdevice using ATM AAL5 as underlying carrier
3
(RFC1483 obsoleted by RFC2684) for Linux 2.4
4
Author: Marcell GAL, 2000, XDSL Ltd, Hungary
5
*/
6
 
7
#include <linux/module.h>
8
#include <linux/config.h>
9
#include <linux/init.h>
10
#include <linux/kernel.h>
11
#include <linux/list.h>
12
#include <linux/netdevice.h>
13
#include <linux/skbuff.h>
14
#include <linux/etherdevice.h>
15
#include <linux/rtnetlink.h>
16
#include <linux/ip.h>
17
#include <asm/uaccess.h>
18
#include <net/arp.h>
19
#include <linux/atm.h>
20
#include <linux/atmdev.h>
21
 
22
#include <linux/atmbr2684.h>
23
 
24
#include "common.h"
25
#include "ipcommon.h"
26
 
27
/*
28
 * Define this to use a version of the code which interacts with the higher
29
 * layers in a more intellegent way, by always reserving enough space for
30
 * our header at the begining of the packet.  However, there may still be
31
 * some problems with programs like tcpdump.  In 2.5 we'll sort out what
32
 * we need to do to get this perfect.  For now we just will copy the packet
33
 * if we need space for the header
34
 */
35
/* #define FASTER_VERSION */
36
 
37
#ifdef DEBUG
38
#define DPRINTK(format, args...) printk(KERN_DEBUG "br2684: " format, ##args)
39
#else
40
#define DPRINTK(format, args...)
41
#endif
42
 
43
#ifdef SKB_DEBUG
44
static void skb_debug(const struct sk_buff *skb)
45
{
46
#define NUM2PRINT 50
47
        char buf[NUM2PRINT * 3 + 1];    /* 3 chars per byte */
48
        int i = 0;
49
        for (i = 0; i < skb->len && i < NUM2PRINT; i++) {
50
                sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
51
        }
52
        printk(KERN_DEBUG "br2684: skb: %s\n", buf);
53
}
54
#else
55
#define skb_debug(skb)  do {} while (0)
56
#endif
57
 
58
static unsigned char llc_oui_pid_pad[] =
59
    { 0xAA, 0xAA, 0x03, 0x00, 0x80, 0xC2, 0x00, 0x07, 0x00, 0x00 };
60
#define PADLEN  (2)
61
 
62
enum br2684_encaps {
63
        e_vc  = BR2684_ENCAPS_VC,
64
        e_llc = BR2684_ENCAPS_LLC,
65
};
66
 
67
struct br2684_vcc {
68
        struct atm_vcc  *atmvcc;
69
        struct br2684_dev *brdev;
70
        /* keep old push,pop functions for chaining */
71
        void (*old_push)(struct atm_vcc *vcc,struct sk_buff *skb);
72
        /* void (*old_pop)(struct atm_vcc *vcc,struct sk_buff *skb); */
73
        enum br2684_encaps encaps;
74
        struct list_head brvccs;
75
#ifdef CONFIG_ATM_BR2684_IPFILTER
76
        struct br2684_filter filter;
77
#endif /* CONFIG_ATM_BR2684_IPFILTER */
78
#ifndef FASTER_VERSION
79
        unsigned copies_needed, copies_failed;
80
#endif /* FASTER_VERSION */
81
};
82
 
83
struct br2684_dev {
84
        struct net_device net_dev;
85
        struct list_head br2684_devs;
86
        int number;
87
        struct list_head brvccs; /* one device <=> one vcc (before xmas) */
88
        struct net_device_stats stats;
89
        int mac_was_set;
90
};
91
 
92
/*
93
 * This lock should be held for writing any time the list of devices or
94
 * their attached vcc's could be altered.  It should be held for reading
95
 * any time these are being queried.  Note that we sometimes need to
96
 * do read-locking under interrupt context, so write locking must block
97
 * the current CPU's interrupts
98
 */
99
static rwlock_t devs_lock = RW_LOCK_UNLOCKED;
100
 
101
static LIST_HEAD(br2684_devs);
102
 
103
static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev)
104
{
105
        return (struct br2684_dev *) ((char *) (net_dev) -
106
            (unsigned long) (&((struct br2684_dev *) 0)->net_dev));
107
}
108
 
109
static inline struct br2684_dev *list_entry_brdev(const struct list_head *le)
110
{
111
        return list_entry(le, struct br2684_dev, br2684_devs);
112
}
113
 
114
static inline struct br2684_vcc *BR2684_VCC(const struct atm_vcc *atmvcc)
115
{
116
        return (struct br2684_vcc *) (atmvcc->user_back);
117
}
118
 
119
static inline struct br2684_vcc *list_entry_brvcc(const struct list_head *le)
120
{
121
        return list_entry(le, struct br2684_vcc, brvccs);
122
}
123
 
124
/* Caller should hold read_lock(&devs_lock) */
125
static struct br2684_dev *br2684_find_dev(const struct br2684_if_spec *s)
126
{
127
        struct list_head *lh;
128
        struct br2684_dev *brdev;
129
        switch (s->method) {
130
        case BR2684_FIND_BYNUM:
131
                list_for_each(lh, &br2684_devs) {
132
                        brdev = list_entry_brdev(lh);
133
                        if (brdev->number == s->spec.devnum)
134
                                return brdev;
135
                }
136
                break;
137
        case BR2684_FIND_BYIFNAME:
138
                list_for_each(lh, &br2684_devs) {
139
                        brdev = list_entry_brdev(lh);
140
                        if (!strncmp(brdev->net_dev.name, s->spec.ifname,
141
                            sizeof brdev->net_dev.name))
142
                                return brdev;
143
                }
144
                break;
145
        }
146
        return NULL;
147
}
148
 
149
/*
150
 * Send a packet out a particular vcc.  Not to useful right now, but paves
151
 * the way for multiple vcc's per itf.  Returns true if we can send,
152
 * otherwise false
153
 */
154
static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
155
        struct br2684_vcc *brvcc)
156
{
157
        struct atm_vcc *atmvcc;
158
#ifdef FASTER_VERSION
159
        if (brvcc->encaps == e_llc)
160
                memcpy(skb_push(skb, 8), llc_oui_pid_pad, 8);
161
        /* last 2 bytes of llc_oui_pid_pad are managed by header routines;
162
           yes, you got it: 8 + 2 = sizeof(llc_oui_pid_pad)
163
         */
164
#else
165
        int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2;
166
        if (skb_headroom(skb) < minheadroom) {
167
                struct sk_buff *skb2 = skb_realloc_headroom(skb, minheadroom);
168
                brvcc->copies_needed++;
169
                dev_kfree_skb(skb);
170
                if (skb2 == NULL) {
171
                        brvcc->copies_failed++;
172
                        return 0;
173
                }
174
                skb = skb2;
175
        }
176
        skb_push(skb, minheadroom);
177
        if (brvcc->encaps == e_llc)
178
                memcpy(skb->data, llc_oui_pid_pad, 10);
179
        else
180
                memset(skb->data, 0, 2);
181
#endif /* FASTER_VERSION */
182
        skb_debug(skb);
183
 
184
        ATM_SKB(skb)->vcc = atmvcc = brvcc->atmvcc;
185
        DPRINTK("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, atmvcc, atmvcc->dev);
186
        if (!atm_may_send(atmvcc, skb->truesize)) {
187
                /* we free this here for now, because we cannot know in a higher
188
                        layer whether the skb point it supplied wasn't freed yet.
189
                        now, it always is.
190
                */
191
                dev_kfree_skb(skb);
192
                return 0;
193
                }
194
        atomic_add(skb->truesize, &atmvcc->sk->wmem_alloc);
195
        ATM_SKB(skb)->atm_options = atmvcc->atm_options;
196
        brdev->stats.tx_packets++;
197
        brdev->stats.tx_bytes += skb->len;
198
        atmvcc->send(atmvcc, skb);
199
        return 1;
200
}
201
 
202
static inline struct br2684_vcc *pick_outgoing_vcc(struct sk_buff *skb,
203
        struct br2684_dev *brdev)
204
{
205
        return list_empty(&brdev->brvccs) ? NULL :
206
            list_entry_brvcc(brdev->brvccs.next); /* 1 vcc/dev right now */
207
}
208
 
209
static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
210
{
211
        struct br2684_dev *brdev = BRPRIV(dev);
212
        struct br2684_vcc *brvcc;
213
 
214
        DPRINTK("br2684_start_xmit, skb->dst=%p\n", skb->dst);
215
        read_lock(&devs_lock);
216
        brvcc = pick_outgoing_vcc(skb, brdev);
217
        if (brvcc == NULL) {
218
                DPRINTK("no vcc attached to dev %s\n", dev->name);
219
                brdev->stats.tx_errors++;
220
                brdev->stats.tx_carrier_errors++;
221
                /* netif_stop_queue(dev); */
222
                dev_kfree_skb(skb);
223
                read_unlock(&devs_lock);
224
                return -EUNATCH;
225
        }
226
        if (!br2684_xmit_vcc(skb, brdev, brvcc)) {
227
                /*
228
                 * We should probably use netif_*_queue() here, but that
229
                 * involves added complication.  We need to walk before
230
                 * we can run
231
                 */
232
                /* don't free here! this pointer might be no longer valid!
233
                dev_kfree_skb(skb);
234
                */
235
                brdev->stats.tx_errors++;
236
                brdev->stats.tx_fifo_errors++;
237
        }
238
        read_unlock(&devs_lock);
239
        return 0;
240
}
241
 
242
static struct net_device_stats *br2684_get_stats(struct net_device *dev)
243
{
244
        DPRINTK("br2684_get_stats\n");
245
        return &BRPRIV(dev)->stats;
246
}
247
 
248
#ifdef FASTER_VERSION
249
/*
250
 * These mirror eth_header and eth_header_cache.  They are not usually
251
 * exported for use in modules, so we grab them from net_device
252
 * after ether_setup() is done with it.  Bit of a hack.
253
 */
254
static int (*my_eth_header)(struct sk_buff *, struct net_device *,
255
        unsigned short, void *, void *, unsigned);
256
static int (*my_eth_header_cache)(struct neighbour *, struct hh_cache *);
257
 
258
static int
259
br2684_header(struct sk_buff *skb, struct net_device *dev,
260
              unsigned short type, void *daddr, void *saddr, unsigned len)
261
{
262
        u16 *pad_before_eth;
263
        int t = my_eth_header(skb, dev, type, daddr, saddr, len);
264
        if (t > 0) {
265
                pad_before_eth = (u16 *) skb_push(skb, 2);
266
                *pad_before_eth = 0;
267
                return dev->hard_header_len;    /* or return 16; ? */
268
        } else
269
                return t;
270
}
271
 
272
static int
273
br2684_header_cache(struct neighbour *neigh, struct hh_cache *hh)
274
{
275
/* hh_data is 16 bytes long. if encaps is ether-llc we need 24, so
276
xmit will add the additional header part in that case */
277
        u16 *pad_before_eth = (u16 *)(hh->hh_data);
278
        int t = my_eth_header_cache(neigh, hh);
279
        DPRINTK("br2684_header_cache, neigh=%p, hh_cache=%p\n", neigh, hh);
280
        if (t < 0)
281
                return t;
282
        else {
283
                *pad_before_eth = 0;
284
                hh->hh_len = PADLEN + ETH_HLEN;
285
        }
286
        return 0;
287
}
288
 
289
/*
290
 * This is similar to eth_type_trans, which cannot be used because of
291
 * our dev->hard_header_len
292
 */
293
static inline unsigned short br_type_trans(struct sk_buff *skb,
294
                                               struct net_device *dev)
295
{
296
        struct ethhdr *eth;
297
        unsigned char *rawp;
298
        eth = skb->mac.ethernet;
299
 
300
        if (*eth->h_dest & 1) {
301
                if (memcmp(eth->h_dest, dev->broadcast, ETH_ALEN) == 0)
302
                        skb->pkt_type = PACKET_BROADCAST;
303
                else
304
                        skb->pkt_type = PACKET_MULTICAST;
305
        }
306
 
307
        else if (memcmp(eth->h_dest, dev->dev_addr, ETH_ALEN))
308
                skb->pkt_type = PACKET_OTHERHOST;
309
 
310
        if (ntohs(eth->h_proto) >= 1536)
311
                return eth->h_proto;
312
 
313
        rawp = skb->data;
314
 
315
        /*
316
         * This is a magic hack to spot IPX packets. Older Novell breaks
317
         * the protocol design and runs IPX over 802.3 without an 802.2 LLC
318
         * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
319
         * won't work for fault tolerant netware but does for the rest.
320
         */
321
        if (*(unsigned short *) rawp == 0xFFFF)
322
                return htons(ETH_P_802_3);
323
 
324
        /*
325
         * Real 802.2 LLC
326
         */
327
        return htons(ETH_P_802_2);
328
}
329
#endif /* FASTER_VERSION */
330
 
331
/*
332
 * We remember when the MAC gets set, so we don't override it later with
333
 * the ESI of the ATM card of the first VC
334
 */
335
static int (*my_eth_mac_addr)(struct net_device *, void *);
336
static int br2684_mac_addr(struct net_device *dev, void *p)
337
{
338
        int err = my_eth_mac_addr(dev, p);
339
        if (!err)
340
                BRPRIV(dev)->mac_was_set = 1;
341
        return err;
342
}
343
 
344
#ifdef CONFIG_ATM_BR2684_IPFILTER
345
/* this IOCTL is experimental. */
346
static int br2684_setfilt(struct atm_vcc *atmvcc, unsigned long arg)
347
{
348
        struct br2684_vcc *brvcc;
349
        struct br2684_filter_set fs;
350
 
351
        if (copy_from_user(&fs, (void *) arg, sizeof fs))
352
                return -EFAULT;
353
        if (fs.ifspec.method != BR2684_FIND_BYNOTHING) {
354
                /*
355
                 * This is really a per-vcc thing, but we can also search
356
                 * by device
357
                 */
358
                struct br2684_dev *brdev;
359
                read_lock(&devs_lock);
360
                brdev = br2684_find_dev(&fs.ifspec);
361
                if (brdev == NULL || list_empty(&brdev->brvccs) ||
362
                    brdev->brvccs.next != brdev->brvccs.prev)  /* >1 VCC */
363
                        brvcc = NULL;
364
                else
365
                        brvcc = list_entry_brvcc(brdev->brvccs.next);
366
                read_unlock(&devs_lock);
367
                if (brvcc == NULL)
368
                        return -ESRCH;
369
        } else
370
                brvcc = BR2684_VCC(atmvcc);
371
        memcpy(&brvcc->filter, &fs.filter, sizeof(brvcc->filter));
372
        return 0;
373
}
374
 
375
/* Returns 1 if packet should be dropped */
376
static inline int
377
packet_fails_filter(u16 type, struct br2684_vcc *brvcc, struct sk_buff *skb)
378
{
379
        if (brvcc->filter.netmask == 0)
380
                return 0;                        /* no filter in place */
381
        if (type == __constant_htons(ETH_P_IP) &&
382
            (((struct iphdr *) (skb->data))->daddr & brvcc->filter.
383
             netmask) == brvcc->filter.prefix)
384
                return 0;
385
        if (type == __constant_htons(ETH_P_ARP))
386
                return 0;
387
        /* TODO: we should probably filter ARPs too.. don't want to have
388
         *   them returning values that don't make sense, or is that ok?
389
         */
390
        return 1;               /* drop */
391
}
392
#endif /* CONFIG_ATM_BR2684_IPFILTER */
393
 
394
static void br2684_close_vcc(struct br2684_vcc *brvcc)
395
{
396
        DPRINTK("removing VCC %p from dev %p\n", brvcc, brvcc->brdev);
397
        write_lock_irq(&devs_lock);
398
        list_del(&brvcc->brvccs);
399
        write_unlock_irq(&devs_lock);
400
        brvcc->atmvcc->user_back = NULL;        /* what about vcc->recvq ??? */
401
        brvcc->old_push(brvcc->atmvcc, NULL);   /* pass on the bad news */
402
        kfree(brvcc);
403
        MOD_DEC_USE_COUNT;
404
}
405
 
406
/* when AAL5 PDU comes in: */
407
static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
408
{
409
        struct br2684_vcc *brvcc = BR2684_VCC(atmvcc);
410
        struct br2684_dev *brdev = brvcc->brdev;
411
        int plen = sizeof(llc_oui_pid_pad) + ETH_HLEN;
412
 
413
        DPRINTK("br2684_push\n");
414
 
415
        if (skb == NULL) {      /* skb==NULL means VCC is being destroyed */
416
                br2684_close_vcc(brvcc);
417
                if (list_empty(&brdev->brvccs)) {
418
                        read_lock(&devs_lock);
419
                        list_del(&brdev->br2684_devs);
420
                        read_unlock(&devs_lock);
421
                        unregister_netdev(&brdev->net_dev);
422
                        kfree(brdev);
423
                }
424
                return;
425
        }
426
 
427
        skb_debug(skb);
428
        atm_return(atmvcc, skb->truesize);
429
        DPRINTK("skb from brdev %p\n", brdev);
430
        if (brvcc->encaps == e_llc) {
431
                /* let us waste some time for checking the encapsulation.
432
                   Note, that only 7 char is checked so frames with a valid FCS
433
                   are also accepted (but FCS is not checked of course) */
434
                if (memcmp(skb->data, llc_oui_pid_pad, 7)) {
435
                        brdev->stats.rx_errors++;
436
                        dev_kfree_skb(skb);
437
                        return;
438
                }
439
 
440
                /* Strip FCS if present */
441
                if (skb->len > 7 && skb->data[7] == 0x01)
442
                        __skb_trim(skb, skb->len - 4);
443
        } else {
444
                plen = PADLEN + ETH_HLEN;       /* pad, dstmac,srcmac, ethtype */
445
                /* first 2 chars should be 0 */
446
                if (*((u16 *) (skb->data)) != 0) {
447
                        brdev->stats.rx_errors++;
448
                        dev_kfree_skb(skb);
449
                        return;
450
                }
451
        }
452
        if (skb->len < plen) {
453
                brdev->stats.rx_errors++;
454
                dev_kfree_skb(skb);     /* dev_ not needed? */
455
                return;
456
        }
457
 
458
#ifdef FASTER_VERSION
459
        /* FIXME: tcpdump shows that pointer to mac header is 2 bytes earlier,
460
           than should be. What else should I set? */
461
        skb_pull(skb, plen);
462
        skb->mac.raw = ((char *) (skb->data)) - ETH_HLEN;
463
        skb->pkt_type = PACKET_HOST;
464
#ifdef CONFIG_BR2684_FAST_TRANS
465
        skb->protocol = ((u16 *) skb->data)[-1];
466
#else                           /* some protocols might require this: */
467
        skb->protocol = br_type_trans(skb, &brdev->net_dev);
468
#endif /* CONFIG_BR2684_FAST_TRANS */
469
#else
470
        skb_pull(skb, plen - ETH_HLEN);
471
        skb->protocol = eth_type_trans(skb, &brdev->net_dev);
472
#endif /* FASTER_VERSION */
473
#ifdef CONFIG_ATM_BR2684_IPFILTER
474
        if (packet_fails_filter(skb->protocol, brvcc, skb)) {
475
                brdev->stats.rx_dropped++;
476
                dev_kfree_skb(skb);
477
                return;
478
        }
479
#endif /* CONFIG_ATM_BR2684_IPFILTER */
480
        skb->dev = &brdev->net_dev;
481
        ATM_SKB(skb)->vcc = atmvcc;     /* needed ? */
482
        DPRINTK("received packet's protocol: %x\n", ntohs(skb->protocol));
483
        skb_debug(skb);
484
        if (!(brdev->net_dev.flags & IFF_UP)) { /* sigh, interface is down */
485
                brdev->stats.rx_dropped++;
486
                dev_kfree_skb(skb);
487
                return;
488
        }
489
        brdev->stats.rx_packets++;
490
        brdev->stats.rx_bytes += skb->len;
491
        memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
492
        netif_rx(skb);
493
}
494
 
495
static int br2684_regvcc(struct atm_vcc *atmvcc, unsigned long arg)
496
{
497
/* assign a vcc to a dev
498
Note: we do not have explicit unassign, but look at _push()
499
*/
500
        int err;
501
        struct br2684_vcc *brvcc;
502
        struct sk_buff_head copy;
503
        struct sk_buff *skb;
504
        struct br2684_dev *brdev;
505
        struct atm_backend_br2684 be;
506
 
507
        MOD_INC_USE_COUNT;
508
        if (copy_from_user(&be, (void *) arg, sizeof be)) {
509
                MOD_DEC_USE_COUNT;
510
                return -EFAULT;
511
        }
512
        write_lock_irq(&devs_lock);
513
        brdev = br2684_find_dev(&be.ifspec);
514
        if (brdev == NULL) {
515
                printk(KERN_ERR
516
                    "br2684: tried to attach to non-existant device\n");
517
                err = -ENXIO;
518
                goto error;
519
        }
520
        if (atmvcc->push == NULL) {
521
                err = -EBADFD;
522
                goto error;
523
        }
524
        if (!list_empty(&brdev->brvccs)) {      /* Only 1 VCC/dev right now */
525
                err = -EEXIST;
526
                goto error;
527
        }
528
        if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO ||
529
            be.fcs_auto || be.has_vpiid || be.send_padding || (be.encaps !=
530
            BR2684_ENCAPS_VC && be.encaps != BR2684_ENCAPS_LLC) ||
531
            be.min_size != 0) {
532
                err = -EINVAL;
533
                goto error;
534
        }
535
        brvcc = kmalloc(sizeof(struct br2684_vcc), GFP_KERNEL);
536
        if (!brvcc) {
537
                err = -ENOMEM;
538
                goto error;
539
        }
540
        memset(brvcc, 0, sizeof(struct br2684_vcc));
541
        DPRINTK("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps,
542
                brvcc);
543
        if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) {
544
                unsigned char *esi = atmvcc->dev->esi;
545
                if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5])
546
                        memcpy(brdev->net_dev.dev_addr, esi,
547
                            brdev->net_dev.addr_len);
548
                else
549
                        brdev->net_dev.dev_addr[2] = 1;
550
        }
551
        list_add(&brvcc->brvccs, &brdev->brvccs);
552
        write_unlock_irq(&devs_lock);
553
        brvcc->brdev = brdev;
554
        brvcc->atmvcc = atmvcc;
555
        atmvcc->user_back = brvcc;
556
        brvcc->encaps = (enum br2684_encaps) be.encaps;
557
        brvcc->old_push = atmvcc->push;
558
        barrier();
559
        atmvcc->push = br2684_push;
560
        skb_queue_head_init(&copy);
561
        skb_migrate(&atmvcc->sk->receive_queue, &copy);
562
        while ((skb = skb_dequeue(&copy))) {
563
                BRPRIV(skb->dev)->stats.rx_bytes -= skb->len;
564
                BRPRIV(skb->dev)->stats.rx_packets--;
565
                br2684_push(atmvcc, skb);
566
        }
567
        return 0;
568
    error:
569
        write_unlock_irq(&devs_lock);
570
        MOD_DEC_USE_COUNT;
571
        return err;
572
}
573
 
574
static int br2684_create(unsigned long arg)
575
{
576
        int err;
577
        struct br2684_dev *brdev;
578
        struct atm_newif_br2684 ni;
579
 
580
        DPRINTK("br2684_create\n");
581
        /*
582
         * We track module use by vcc's NOT the devices they're on.  We're
583
         * protected here against module death by the kernel_lock, but if
584
         * we need to sleep we should make sure that the module doesn't
585
         * disappear under us.
586
         */
587
        MOD_INC_USE_COUNT;
588
        if (copy_from_user(&ni, (void *) arg, sizeof ni)) {
589
                MOD_DEC_USE_COUNT;
590
                return -EFAULT;
591
        }
592
        if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) {
593
                MOD_DEC_USE_COUNT;
594
                return -EINVAL;
595
        }
596
        if ((brdev = kmalloc(sizeof(struct br2684_dev), GFP_KERNEL)) == NULL) {
597
                MOD_DEC_USE_COUNT;
598
                return -ENOMEM;
599
        }
600
        memset(brdev, 0, sizeof(struct br2684_dev));
601
        INIT_LIST_HEAD(&brdev->brvccs);
602
 
603
        write_lock_irq(&devs_lock);
604
        brdev->number = list_empty(&br2684_devs) ? 1 :
605
            list_entry_brdev(br2684_devs.prev)->number + 1;
606
        list_add_tail(&brdev->br2684_devs, &br2684_devs);
607
        write_unlock_irq(&devs_lock);
608
 
609
        if (ni.ifname[0] != '\0') {
610
                memcpy(brdev->net_dev.name, ni.ifname,
611
                    sizeof(brdev->net_dev.name));
612
                brdev->net_dev.name[sizeof(brdev->net_dev.name) - 1] = '\0';
613
        } else
614
                sprintf(brdev->net_dev.name, "nas%d", brdev->number);
615
        DPRINTK("registered netdev %s\n", brdev->net_dev.name);
616
        ether_setup(&brdev->net_dev);
617
        brdev->mac_was_set = 0;
618
#ifdef FASTER_VERSION
619
        my_eth_header = brdev->net_dev.hard_header;
620
        brdev->net_dev.hard_header = br2684_header;
621
        my_eth_header_cache = brdev->net_dev.hard_header_cache;
622
        brdev->net_dev.hard_header_cache = br2684_header_cache;
623
        brdev->net_dev.hard_header_len = sizeof(llc_oui_pid_pad) + ETH_HLEN;    /* 10 + 14 */
624
#endif
625
        my_eth_mac_addr = brdev->net_dev.set_mac_address;
626
        brdev->net_dev.set_mac_address = br2684_mac_addr;
627
        brdev->net_dev.hard_start_xmit = br2684_start_xmit;
628
        brdev->net_dev.get_stats = br2684_get_stats;
629
 
630
        /* open, stop, do_ioctl ? */
631
        err = register_netdev(&brdev->net_dev);
632
        MOD_DEC_USE_COUNT;
633
        if (err < 0) {
634
                printk(KERN_ERR "br2684_create: register_netdev failed\n");
635
                write_lock_irq(&devs_lock);
636
                list_del(&brdev->br2684_devs);
637
                write_unlock_irq(&devs_lock);
638
                kfree(brdev);
639
                return err;
640
        }
641
        return 0;
642
}
643
 
644
/*
645
 * This handles ioctls actually performed on our vcc - we must return
646
 * -ENOIOCTLCMD for any unrecognized ioctl
647
 */
648
static int br2684_ioctl(struct atm_vcc *atmvcc, unsigned int cmd,
649
        unsigned long arg)
650
{
651
        int err;
652
        switch(cmd) {
653
        case ATM_SETBACKEND:
654
        case ATM_NEWBACKENDIF: {
655
                atm_backend_t b;
656
                MOD_INC_USE_COUNT;
657
                err = get_user(b, (atm_backend_t *) arg);
658
                MOD_DEC_USE_COUNT;
659
                if (err)
660
                        return -EFAULT;
661
                if (b != ATM_BACKEND_BR2684)
662
                        return -ENOIOCTLCMD;
663
                if (!capable(CAP_NET_ADMIN))
664
                        return -EPERM;
665
                if (cmd == ATM_SETBACKEND)
666
                        return br2684_regvcc(atmvcc, arg);
667
                else
668
                        return br2684_create(arg);
669
                }
670
#ifdef CONFIG_ATM_BR2684_IPFILTER
671
        case BR2684_SETFILT:
672
                if (atmvcc->push != br2684_push)
673
                        return -ENOIOCTLCMD;
674
                if (!capable(CAP_NET_ADMIN))
675
                        return -EPERM;
676
                MOD_INC_USE_COUNT;
677
                err = br2684_setfilt(atmvcc, arg);
678
                MOD_DEC_USE_COUNT;
679
                return err;
680
#endif /* CONFIG_ATM_BR2684_IPFILTER */
681
        }
682
        return -ENOIOCTLCMD;
683
}
684
 
685
#ifdef CONFIG_PROC_FS
686
/* Never put more than 256 bytes in at once */
687
static int br2684_proc_engine(loff_t pos, char *buf)
688
{
689
        struct list_head *lhd, *lhc;
690
        struct br2684_dev *brdev;
691
        struct br2684_vcc *brvcc;
692
        list_for_each(lhd, &br2684_devs) {
693
                brdev = list_entry_brdev(lhd);
694
                if (pos-- == 0)
695
                        return sprintf(buf, "dev %.16s: num=%d, mac=%02X:%02X:"
696
                            "%02X:%02X:%02X:%02X (%s)\n", brdev->net_dev.name,
697
                            brdev->number,
698
                            brdev->net_dev.dev_addr[0],
699
                            brdev->net_dev.dev_addr[1],
700
                            brdev->net_dev.dev_addr[2],
701
                            brdev->net_dev.dev_addr[3],
702
                            brdev->net_dev.dev_addr[4],
703
                            brdev->net_dev.dev_addr[5],
704
                            brdev->mac_was_set ? "set" : "auto");
705
                list_for_each(lhc, &brdev->brvccs) {
706
                        brvcc = list_entry_brvcc(lhc);
707
                        if (pos-- == 0)
708
                                return sprintf(buf, "  vcc %d.%d.%d: encaps=%s"
709
#ifndef FASTER_VERSION
710
                                    ", failed copies %u/%u"
711
#endif /* FASTER_VERSION */
712
                                    "\n", brvcc->atmvcc->dev->number,
713
                                    brvcc->atmvcc->vpi, brvcc->atmvcc->vci,
714
                                    (brvcc->encaps == e_llc) ? "LLC" : "VC"
715
#ifndef FASTER_VERSION
716
                                    , brvcc->copies_failed
717
                                    , brvcc->copies_needed
718
#endif /* FASTER_VERSION */
719
                                    );
720
#ifdef CONFIG_ATM_BR2684_IPFILTER
721
#define b1(var, byte)   ((u8 *) &brvcc->filter.var)[byte]
722
#define bs(var)         b1(var, 0), b1(var, 1), b1(var, 2), b1(var, 3)
723
                        if (brvcc->filter.netmask != 0 && pos-- == 0)
724
                                return sprintf(buf, "    filter=%d.%d.%d.%d/"
725
                                    "%d.%d.%d.%d\n", bs(prefix), bs(netmask));
726
#undef bs
727
#undef b1
728
#endif /* CONFIG_ATM_BR2684_IPFILTER */
729
                }
730
        }
731
        return 0;
732
}
733
 
734
static ssize_t br2684_proc_read(struct file *file, char *buf, size_t count,
735
        loff_t *pos)
736
{
737
        unsigned long page;
738
        int len = 0, x, left;
739
        page = get_free_page(GFP_KERNEL);
740
        if (!page)
741
                return -ENOMEM;
742
        left = PAGE_SIZE - 256;
743
        if (count < left)
744
                left = count;
745
        read_lock(&devs_lock);
746
        for (;;) {
747
                x = br2684_proc_engine(*pos, &((char *) page)[len]);
748
                if (x == 0)
749
                        break;
750
                if (x > left)
751
                        /*
752
                         * This should only happen if the user passed in
753
                         * a "count" too small for even one line
754
                         */
755
                        x = -EINVAL;
756
                if (x < 0) {
757
                        len = x;
758
                        break;
759
                }
760
                len += x;
761
                left -= x;
762
                (*pos)++;
763
                if (left < 256)
764
                        break;
765
        }
766
        read_unlock(&devs_lock);
767
        if (len > 0 && copy_to_user(buf, (char *) page, len))
768
                len = -EFAULT;
769
        free_page(page);
770
        return len;
771
}
772
 
773
static struct file_operations br2684_proc_operations = {
774
        read: br2684_proc_read,
775
};
776
 
777
extern struct proc_dir_entry *atm_proc_root;    /* from proc.c */
778
#endif /* CONFIG_PROC_FS */
779
 
780
/* the following avoids some spurious warnings from the compiler */
781
#define UNUSED __attribute__((unused))
782
 
783
static int __init UNUSED br2684_init(void)
784
{
785
#ifdef CONFIG_PROC_FS
786
        struct proc_dir_entry *p;
787
        if ((p = create_proc_entry("br2684", 0, atm_proc_root)) == NULL)
788
                return -ENOMEM;
789
        p->proc_fops = &br2684_proc_operations;
790
#endif /* CONFIG_PROC_FS */
791
        br2684_ioctl_set(br2684_ioctl);
792
        return 0;
793
}
794
 
795
static void __exit UNUSED br2684_exit(void)
796
{
797
        struct br2684_dev *brdev;
798
        br2684_ioctl_set(NULL);
799
#ifdef CONFIG_PROC_FS
800
        remove_proc_entry("br2684", atm_proc_root);
801
#endif /* CONFIG_PROC_FS */
802
        while (!list_empty(&br2684_devs)) {
803
                brdev = list_entry_brdev(br2684_devs.next);
804
                unregister_netdev(&brdev->net_dev);
805
                list_del(&brdev->br2684_devs);
806
                kfree(brdev);
807
        }
808
}
809
 
810
module_init(br2684_init);
811
module_exit(br2684_exit);
812
 
813
MODULE_AUTHOR("Marcell GAL");
814
MODULE_DESCRIPTION("RFC2684 bridged protocols over ATM/AAL5");
815
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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