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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 * NET3:        Token ring device handling subroutines
3
 *
4
 *              This program is free software; you can redistribute it and/or
5
 *              modify it under the terms of the GNU General Public License
6
 *              as published by the Free Software Foundation; either version
7
 *              2 of the License, or (at your option) any later version.
8
 *
9
 * Fixes:       3 Feb 97 Paul Norton <pnorton@cts.com> Minor routing fixes.
10
 *              Added rif table to /proc/net/tr_rif and rif timeout to
11
 *              /proc/sys/net/token-ring/rif_timeout.
12
 *              22 Jun 98 Paul Norton <p.norton@computer.org> Rearranged
13
 *              tr_header and tr_type_trans to handle passing IPX SNAP and
14
 *              802.2 through the correct layers. Eliminated tr_reformat.
15
 *
16
 */
17
 
18
#include <asm/uaccess.h>
19
#include <asm/system.h>
20
#include <linux/config.h>
21
#include <linux/types.h>
22
#include <linux/kernel.h>
23
#include <linux/sched.h>
24
#include <linux/string.h>
25
#include <linux/mm.h>
26
#include <linux/socket.h>
27
#include <linux/in.h>
28
#include <linux/inet.h>
29
#include <linux/netdevice.h>
30
#include <linux/trdevice.h>
31
#include <linux/skbuff.h>
32
#include <linux/errno.h>
33
#include <linux/timer.h>
34
#include <linux/net.h>
35
#include <linux/proc_fs.h>
36
#include <linux/init.h>
37
#include <net/arp.h>
38
 
39
void tr_source_route(struct sk_buff *skb, struct trh_hdr *trh,
40
                     struct net_device *dev);
41
static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev);
42
static void rif_check_expire(unsigned long dummy);
43
 
44
#define TR_SR_DEBUG 0
45
 
46
typedef struct rif_cache_s *rif_cache;
47
 
48
/*
49
 *      Each RIF entry we learn is kept this way
50
 */
51
 
52
struct rif_cache_s {
53
        unsigned char addr[TR_ALEN];
54
        int iface;
55
        __u16 rcf;
56
        __u16 rseg[8];
57
        rif_cache next;
58
        unsigned long last_used;
59
        unsigned char local_ring;
60
};
61
 
62
#define RIF_TABLE_SIZE 32
63
 
64
/*
65
 *      We hash the RIF cache 32 ways. We do after all have to look it
66
 *      up a lot.
67
 */
68
 
69
static rif_cache rif_table[RIF_TABLE_SIZE];
70
static spinlock_t rif_lock = SPIN_LOCK_UNLOCKED;
71
 
72
#define RIF_TIMEOUT 60*10*HZ
73
#define RIF_CHECK_INTERVAL 60*HZ
74
 
75
/*
76
 *      Garbage disposal timer.
77
 */
78
 
79
static struct timer_list rif_timer;
80
 
81
int sysctl_tr_rif_timeout = RIF_TIMEOUT;
82
 
83
/*
84
 *      Put the headers on a token ring packet. Token ring source routing
85
 *      makes this a little more exciting than on ethernet.
86
 */
87
 
88
int tr_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
89
              void *daddr, void *saddr, unsigned len)
90
{
91
        struct trh_hdr *trh;
92
        int hdr_len;
93
 
94
        /*
95
         * Add the 802.2 SNAP header if IP as the IPv4/IPv6 code calls
96
         * dev->hard_header directly.
97
         */
98
        if (type == ETH_P_IP || type == ETH_P_IPV6 || type == ETH_P_ARP)
99
        {
100
                struct trllc *trllc=(struct trllc *)(trh+1);
101
 
102
                hdr_len = sizeof(struct trh_hdr) + sizeof(struct trllc);
103
                trh = (struct trh_hdr *)skb_push(skb, hdr_len);
104
                trllc = (struct trllc *)(trh+1);
105
                trllc->dsap = trllc->ssap = EXTENDED_SAP;
106
                trllc->llc = UI_CMD;
107
                trllc->protid[0] = trllc->protid[1] = trllc->protid[2] = 0x00;
108
                trllc->ethertype = htons(type);
109
        }
110
        else
111
        {
112
                hdr_len = sizeof(struct trh_hdr);
113
                trh = (struct trh_hdr *)skb_push(skb, hdr_len);
114
        }
115
 
116
        trh->ac=AC;
117
        trh->fc=LLC_FRAME;
118
 
119
        if(saddr)
120
                memcpy(trh->saddr,saddr,dev->addr_len);
121
        else
122
                memcpy(trh->saddr,dev->dev_addr,dev->addr_len);
123
 
124
        /*
125
         *      Build the destination and then source route the frame
126
         */
127
 
128
        if(daddr)
129
        {
130
                memcpy(trh->daddr,daddr,dev->addr_len);
131
                tr_source_route(skb,trh,dev);
132
                return(hdr_len);
133
        }
134
 
135
        return -hdr_len;
136
}
137
 
138
/*
139
 *      A neighbour discovery of some species (eg arp) has completed. We
140
 *      can now send the packet.
141
 */
142
 
143
int tr_rebuild_header(struct sk_buff *skb)
144
{
145
        struct trh_hdr *trh=(struct trh_hdr *)skb->data;
146
        struct trllc *trllc=(struct trllc *)(skb->data+sizeof(struct trh_hdr));
147
        struct net_device *dev = skb->dev;
148
 
149
        /*
150
         *      FIXME: We don't yet support IPv6 over token rings
151
         */
152
 
153
        if(trllc->ethertype != htons(ETH_P_IP)) {
154
                printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(trllc->ethertype));
155
                return 0;
156
        }
157
 
158
#ifdef CONFIG_INET
159
        if(arp_find(trh->daddr, skb)) {
160
                        return 1;
161
        }
162
        else
163
#endif  
164
        {
165
                tr_source_route(skb,trh,dev);
166
                return 0;
167
        }
168
}
169
 
170
/*
171
 *      Some of this is a bit hackish. We intercept RIF information
172
 *      used for source routing. We also grab IP directly and don't feed
173
 *      it via SNAP.
174
 */
175
 
176
unsigned short tr_type_trans(struct sk_buff *skb, struct net_device *dev)
177
{
178
 
179
        struct trh_hdr *trh=(struct trh_hdr *)skb->data;
180
        struct trllc *trllc;
181
        unsigned riflen=0;
182
 
183
        skb->mac.raw = skb->data;
184
 
185
        if(trh->saddr[0] & TR_RII)
186
                riflen = (ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8;
187
 
188
        trllc = (struct trllc *)(skb->data+sizeof(struct trh_hdr)-TR_MAXRIFLEN+riflen);
189
 
190
        skb_pull(skb,sizeof(struct trh_hdr)-TR_MAXRIFLEN+riflen);
191
 
192
        if(*trh->daddr & 0x80)
193
        {
194
                if(!memcmp(trh->daddr,dev->broadcast,TR_ALEN))
195
                        skb->pkt_type=PACKET_BROADCAST;
196
                else
197
                        skb->pkt_type=PACKET_MULTICAST;
198
        }
199
        else if ( (trh->daddr[0] & 0x01) && (trh->daddr[1] & 0x00) && (trh->daddr[2] & 0x5E))
200
        {
201
                skb->pkt_type=PACKET_MULTICAST;
202
        }
203
        else if(dev->flags & IFF_PROMISC)
204
        {
205
                if(memcmp(trh->daddr, dev->dev_addr, TR_ALEN))
206
                        skb->pkt_type=PACKET_OTHERHOST;
207
        }
208
 
209
        if ((skb->pkt_type != PACKET_BROADCAST) &&
210
            (skb->pkt_type != PACKET_MULTICAST))
211
                tr_add_rif_info(trh,dev) ;
212
 
213
        /*
214
         * Strip the SNAP header from ARP packets since we don't
215
         * pass them through to the 802.2/SNAP layers.
216
         */
217
 
218
        if (trllc->dsap == EXTENDED_SAP &&
219
            (trllc->ethertype == ntohs(ETH_P_IP) ||
220
             trllc->ethertype == ntohs(ETH_P_IPV6) ||
221
             trllc->ethertype == ntohs(ETH_P_ARP)))
222
        {
223
                skb_pull(skb, sizeof(struct trllc));
224
                return trllc->ethertype;
225
        }
226
 
227
        return ntohs(ETH_P_802_2);
228
}
229
 
230
/*
231
 *      We try to do source routing...
232
 */
233
 
234
void tr_source_route(struct sk_buff *skb, struct trh_hdr *trh,
235
                     struct net_device *dev)
236
{
237
        int i, slack;
238
        unsigned int hash;
239
        rif_cache entry;
240
        unsigned char *olddata;
241
        unsigned char mcast_func_addr[] = {0xC0,0x00,0x00,0x04,0x00,0x00};
242
        unsigned long flags ;
243
 
244
        spin_lock_irqsave(&rif_lock,flags);
245
 
246
        /*
247
         *      Broadcasts are single route as stated in RFC 1042
248
         */
249
        if( (!memcmp(&(trh->daddr[0]),&(dev->broadcast[0]),TR_ALEN)) ||
250
            (!memcmp(&(trh->daddr[0]),&(mcast_func_addr[0]), TR_ALEN))  )
251
        {
252
                trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK)
253
                               | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
254
                trh->saddr[0]|=TR_RII;
255
        }
256
        else
257
        {
258
                for(i=0,hash=0;i<TR_ALEN;hash+=trh->daddr[i++]);
259
                hash&=RIF_TABLE_SIZE-1;
260
                /*
261
                 *      Walk the hash table and look for an entry
262
                 */
263
                for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->daddr[0]),TR_ALEN);entry=entry->next);
264
 
265
                /*
266
                 *      If we found an entry we can route the frame.
267
                 */
268
                if(entry)
269
                {
270
#if TR_SR_DEBUG
271
printk("source routing for %02X:%02X:%02X:%02X:%02X:%02X\n",trh->daddr[0],
272
                  trh->daddr[1],trh->daddr[2],trh->daddr[3],trh->daddr[4],trh->daddr[5]);
273
#endif
274
                        if(!entry->local_ring && (ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8)
275
                        {
276
                                trh->rcf=entry->rcf;
277
                                memcpy(&trh->rseg[0],&entry->rseg[0],8*sizeof(unsigned short));
278
                                trh->rcf^=htons(TR_RCF_DIR_BIT);
279
                                trh->rcf&=htons(0x1fff);        /* Issam Chehab <ichehab@madge1.demon.co.uk> */
280
 
281
                                trh->saddr[0]|=TR_RII;
282
#if TR_SR_DEBUG
283
                                printk("entry found with rcf %04x\n", entry->rcf);
284
                        }
285
                        else
286
                        {
287
                                printk("entry found but without rcf length, local=%02x\n", entry->local_ring);
288
#endif
289
                        }
290
                        entry->last_used=jiffies;
291
                }
292
                else
293
                {
294
                        /*
295
                         *      Without the information we simply have to shout
296
                         *      on the wire. The replies should rapidly clean this
297
                         *      situation up.
298
                         */
299
                        trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK)
300
                                       | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
301
                        trh->saddr[0]|=TR_RII;
302
#if TR_SR_DEBUG
303
                        printk("no entry in rif table found - broadcasting frame\n");
304
#endif
305
                }
306
        }
307
 
308
        /* Compress the RIF here so we don't have to do it in the driver(s) */
309
        if (!(trh->saddr[0] & 0x80))
310
                slack = 18;
311
        else
312
                slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8);
313
        olddata = skb->data;
314
        spin_unlock_irqrestore(&rif_lock,flags);
315
 
316
        skb_pull(skb, slack);
317
        memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack);
318
}
319
 
320
/*
321
 *      We have learned some new RIF information for our source
322
 *      routing.
323
 */
324
 
325
static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev)
326
{
327
        int i;
328
        unsigned int hash, rii_p = 0;
329
        rif_cache entry;
330
        unsigned long flags;
331
 
332
        spin_lock_irqsave(&rif_lock, flags);
333
 
334
        /*
335
         *      Firstly see if the entry exists
336
         */
337
 
338
        if(trh->saddr[0] & TR_RII)
339
        {
340
                trh->saddr[0]&=0x7f;
341
                if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2)
342
                {
343
                        rii_p = 1;
344
                }
345
        }
346
 
347
        for(i=0,hash=0;i<TR_ALEN;hash+=trh->saddr[i++]);
348
        hash&=RIF_TABLE_SIZE-1;
349
        for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);entry=entry->next);
350
 
351
        if(entry==NULL)
352
        {
353
#if TR_SR_DEBUG
354
printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n",
355
                trh->saddr[0],trh->saddr[1],trh->saddr[2],
356
                trh->saddr[3],trh->saddr[4],trh->saddr[5],
357
                ntohs(trh->rcf));
358
#endif
359
                /*
360
                 *      Allocate our new entry. A failure to allocate loses
361
                 *      use the information. This is harmless.
362
                 *
363
                 *      FIXME: We ought to keep some kind of cache size
364
                 *      limiting and adjust the timers to suit.
365
                 */
366
                entry=kmalloc(sizeof(struct rif_cache_s),GFP_ATOMIC);
367
 
368
                if(!entry)
369
                {
370
                        printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n");
371
                        spin_unlock_irqrestore(&rif_lock,flags);
372
                        return;
373
                }
374
 
375
                memcpy(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);
376
                entry->iface = dev->ifindex;
377
                entry->next=rif_table[hash];
378
                entry->last_used=jiffies;
379
                rif_table[hash]=entry;
380
 
381
                if (rii_p)
382
                {
383
                        entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK);
384
                        memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
385
                        entry->local_ring = 0;
386
                        trh->saddr[0]|=TR_RII; /* put the routing indicator back for tcpdump */
387
                }
388
                else
389
                {
390
                        entry->local_ring = 1;
391
                }
392
        }
393
        else    /* Y. Tahara added */
394
        {
395
                /*
396
                 *      Update existing entries
397
                 */
398
                if (!entry->local_ring)
399
                    if (entry->rcf != (trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK)) &&
400
                         !(trh->rcf & htons(TR_RCF_BROADCAST_MASK)))
401
                    {
402
#if TR_SR_DEBUG
403
printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n",
404
                trh->saddr[0],trh->saddr[1],trh->saddr[2],
405
                trh->saddr[3],trh->saddr[4],trh->saddr[5],
406
                ntohs(trh->rcf));
407
#endif
408
                            entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK);
409
                            memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
410
                    }
411
                entry->last_used=jiffies;
412
        }
413
        spin_unlock_irqrestore(&rif_lock,flags);
414
}
415
 
416
/*
417
 *      Scan the cache with a timer and see what we need to throw out.
418
 */
419
 
420
static void rif_check_expire(unsigned long dummy)
421
{
422
        int i;
423
        unsigned long now=jiffies;
424
        unsigned long flags ;
425
 
426
        spin_lock_irqsave(&rif_lock,flags);
427
 
428
        for(i=0; i < RIF_TABLE_SIZE;i++)
429
        {
430
                rif_cache entry, *pentry=rif_table+i;
431
                while((entry=*pentry))
432
                {
433
                        /*
434
                         *      Out it goes
435
                         */
436
                        if((now-entry->last_used) > sysctl_tr_rif_timeout)
437
                        {
438
                                *pentry=entry->next;
439
                                kfree(entry);
440
                        }
441
                        else
442
                                pentry=&entry->next;
443
                }
444
        }
445
 
446
        spin_unlock_irqrestore(&rif_lock,flags);
447
 
448
        /*
449
         *      Reset the timer
450
         */
451
 
452
        mod_timer(&rif_timer, jiffies+sysctl_tr_rif_timeout);
453
 
454
}
455
 
456
/*
457
 *      Generate the /proc/net information for the token ring RIF
458
 *      routing.
459
 */
460
 
461
#ifndef CONFIG_PROC_FS
462
static int rif_get_info(char *buffer,char **start, off_t offset, int length)  { return 0;}
463
#else
464
static int rif_get_info(char *buffer,char **start, off_t offset, int length)
465
{
466
        int len=0;
467
        off_t begin=0;
468
        off_t pos=0;
469
        int size,i,j,rcf_len,segment,brdgnmb;
470
        unsigned long now=jiffies;
471
        unsigned long flags;
472
 
473
        rif_cache entry;
474
 
475
        size=sprintf(buffer,
476
                     "if     TR address       TTL   rcf   routing segments\n");
477
        pos+=size;
478
        len+=size;
479
 
480
        spin_lock_irqsave(&rif_lock, flags);
481
        for(i=0;i < RIF_TABLE_SIZE;i++)
482
        {
483
                for(entry=rif_table[i];entry;entry=entry->next) {
484
                        struct net_device *dev = __dev_get_by_index(entry->iface);
485
 
486
                        size=sprintf(buffer+len,"%s %02X:%02X:%02X:%02X:%02X:%02X %7li ",
487
                                     dev?dev->name:"?",entry->addr[0],entry->addr[1],entry->addr[2],entry->addr[3],entry->addr[4],entry->addr[5],
488
                                     sysctl_tr_rif_timeout-(now-entry->last_used));
489
                        len+=size;
490
                        pos=begin+len;
491
                        if (entry->local_ring)
492
                                size=sprintf(buffer+len,"local\n");
493
                        else {
494
                                size=sprintf(buffer+len,"%04X", ntohs(entry->rcf));
495
                                rcf_len = ((ntohs(entry->rcf) & TR_RCF_LEN_MASK)>>8)-2;
496
                                if (rcf_len)
497
                                        rcf_len >>= 1;
498
                                for(j = 1; j < rcf_len; j++) {
499
                                        if(j==1) {
500
                                                segment=ntohs(entry->rseg[j-1])>>4;
501
                                                len+=size;
502
                                                pos=begin+len;
503
                                                size=sprintf(buffer+len,"  %03X",segment);
504
                                        };
505
                                        segment=ntohs(entry->rseg[j])>>4;
506
                                        brdgnmb=ntohs(entry->rseg[j-1])&0x00f;
507
                                        len+=size;
508
                                        pos=begin+len;
509
                                        size=sprintf(buffer+len,"-%01X-%03X",brdgnmb,segment);
510
                                }
511
                                len+=size;
512
                                pos=begin+len;
513
                                size=sprintf(buffer+len,"\n");
514
                        }
515
                        len+=size;
516
                        pos=begin+len;
517
 
518
                        if(pos<offset)
519
                        {
520
                                len=0;
521
                                begin=pos;
522
                        }
523
                        if(pos>offset+length)
524
                                break;
525
                }
526
                if(pos>offset+length)
527
                        break;
528
        }
529
        spin_unlock_irqrestore(&rif_lock,flags);
530
 
531
        *start=buffer+(offset-begin); /* Start of wanted data */
532
        len-=(offset-begin);    /* Start slop */
533
        if(len>length)
534
                len=length;    /* Ending slop */
535
        if (len<0)
536
                len=0;
537
        return len;
538
}
539
#endif
540
 
541
/*
542
 *      Called during bootup.  We don't actually have to initialise
543
 *      too much for this.
544
 */
545
 
546
static int __init rif_init(void)
547
{
548
        rif_timer.expires  = RIF_TIMEOUT;
549
        rif_timer.data     = 0L;
550
        rif_timer.function = rif_check_expire;
551
        init_timer(&rif_timer);
552
        add_timer(&rif_timer);
553
 
554
        proc_net_create("tr_rif",0,rif_get_info);
555
        return 0;
556
}
557
 
558
module_init(rif_init);

powered by: WebSVN 2.1.0

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