patch-2.1.20 linux/net/802/tr.c
Next file: linux/net/Config.in
Previous file: linux/net/802/sysctl_net_802.c
Back to the patch index
Back to the overall index
- Lines: 425
- Date:
Thu Jan 2 15:13:27 1997
- Orig file:
v2.1.19/linux/net/802/tr.c
- Orig date:
Thu Dec 12 19:37:21 1996
diff -u --recursive --new-file v2.1.19/linux/net/802/tr.c linux/net/802/tr.c
@@ -1,3 +1,14 @@
+/*
+ * NET3: Token ring device handling subroutines
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Fixes:
+ */
+
#include <asm/uaccess.h>
#include <asm/system.h>
#include <linux/types.h>
@@ -23,7 +34,12 @@
typedef struct rif_cache_s *rif_cache;
-struct rif_cache_s {
+/*
+ * Each RIF entry we learn is kept this way
+ */
+
+struct rif_cache_s
+{
unsigned char addr[TR_ALEN];
unsigned short rcf;
unsigned short rseg[8];
@@ -32,12 +48,32 @@
};
#define RIF_TABLE_SIZE 16
+
+/*
+ * We hash the RIF cache 16 ways. We do after all have to look it
+ * up a lot.
+ */
+
rif_cache rif_table[RIF_TABLE_SIZE]={ NULL, };
#define RIF_TIMEOUT 60*10*HZ
#define RIF_CHECK_INTERVAL 60*HZ
-static struct timer_list rif_timer={ NULL,NULL,RIF_CHECK_INTERVAL,0L,rif_check_expire };
+/*
+ * Garbage disposal timer.
+ */
+
+static struct timer_list rif_timer=
+{
+ NULL,NULL,RIF_CHECK_INTERVAL,0L,rif_check_expire
+};
+
+
+/*
+ * Put the headers on a token ring packet. Token ring source routing
+ * makes this a little more exciting than on ethernet.
+ */
+
int tr_header(struct sk_buff *skb, struct device *dev, unsigned short type,
void *daddr, void *saddr, unsigned len)
{
@@ -53,13 +89,23 @@
else
memset(trh->saddr,0,dev->addr_len); /* Adapter fills in address */
+ /*
+ * This is the stuff needed for IP encoding - IP over 802.2
+ * with SNAP.
+ */
+
trllc->dsap=trllc->ssap=EXTENDED_SAP;
trllc->llc=UI_CMD;
trllc->protid[0]=trllc->protid[1]=trllc->protid[2]=0x00;
trllc->ethertype=htons(type);
- if(daddr) {
+ /*
+ * Build the destination and then source route the frame
+ */
+
+ if(daddr)
+ {
memcpy(trh->daddr,daddr,dev->addr_len);
tr_source_route(trh,dev);
return(dev->hard_header_len);
@@ -68,12 +114,21 @@
}
-int tr_rebuild_header(struct sk_buff *skb) {
-
+/*
+ * A neighbour discovery of some species (eg arp) has completed. We
+ * can now send the packet.
+ */
+
+int tr_rebuild_header(struct sk_buff *skb)
+{
struct trh_hdr *trh=(struct trh_hdr *)skb->data;
struct trllc *trllc=(struct trllc *)(skb->data+sizeof(struct trh_hdr));
struct device *dev = skb->dev;
+ /*
+ * FIXME: We don't yet support IPv6 over token rings
+ */
+
if(trllc->ethertype != htons(ETH_P_IP)) {
printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons( trllc->ethertype));
return 0;
@@ -82,13 +137,21 @@
if(arp_find(trh->daddr, skb)) {
return 1;
}
- else {
+ else
+ {
tr_source_route(trh,dev);
return 0;
}
}
-unsigned short tr_type_trans(struct sk_buff *skb, struct device *dev) {
+/*
+ * Some of this is a bit hackish. We intercept RIF information
+ * used for source routing. We also grab IP directly and don't feed
+ * it via SNAP.
+ */
+
+unsigned short tr_type_trans(struct sk_buff *skb, struct device *dev)
+{
struct trh_hdr *trh=(struct trh_hdr *)skb->data;
struct trllc *trllc=(struct trllc *)(skb->data+sizeof(struct trh_hdr));
@@ -117,31 +180,46 @@
return trllc->ethertype;
}
-/* We try to do source routing... */
+/*
+ * We try to do source routing...
+ */
-static void tr_source_route(struct trh_hdr *trh,struct device *dev) {
+static void tr_source_route(struct trh_hdr *trh,struct device *dev)
+{
int i;
unsigned int hash;
rif_cache entry;
- /* Broadcasts are single route as stated in RFC 1042 */
- if(!memcmp(&(trh->daddr[0]),&(dev->broadcast[0]),TR_ALEN)) {
+ /*
+ * Broadcasts are single route as stated in RFC 1042
+ */
+ if(!memcmp(&(trh->daddr[0]),&(dev->broadcast[0]),TR_ALEN))
+ {
trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK)
| TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
trh->saddr[0]|=TR_RII;
}
- else {
+ else
+ {
for(i=0,hash=0;i<TR_ALEN;hash+=trh->daddr[i++]);
hash&=RIF_TABLE_SIZE-1;
+ /*
+ * Walk the hash table and look for an entry
+ */
for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->daddr[0]),TR_ALEN);entry=entry->next);
- if(entry) {
+ /*
+ * If we found an entry we can route the frame.
+ */
+ if(entry)
+ {
#if 0
printk("source routing for %02X %02X %02X %02X %02X %02X\n",trh->daddr[0],
trh->daddr[1],trh->daddr[2],trh->daddr[3],trh->daddr[4],trh->daddr[5]);
#endif
- if((ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8) {
+ if((ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8)
+ {
trh->rcf=entry->rcf;
memcpy(&trh->rseg[0],&entry->rseg[0],8*sizeof(unsigned short));
trh->rcf^=htons(TR_RCF_DIR_BIT);
@@ -151,40 +229,58 @@
entry->last_used=jiffies;
}
}
- else {
+ else
+ {
+ /*
+ * Without the information we simply have to shout
+ * on the wire. The replies should rapidly clean this
+ * situation up.
+ */
trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK)
| TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
trh->saddr[0]|=TR_RII;
}
}
-
}
-static void tr_add_rif_info(struct trh_hdr *trh) {
-
+/*
+ * We have learned some new RIF information for our source
+ * routing.
+ */
+
+static void tr_add_rif_info(struct trh_hdr *trh)
+{
int i;
unsigned int hash;
rif_cache entry;
-
+ /*
+ * Firstly see if the entry exists
+ */
trh->saddr[0]&=0x7f;
for(i=0,hash=0;i<TR_ALEN;hash+=trh->saddr[i++]);
hash&=RIF_TABLE_SIZE-1;
-#if 0
- printk("hash: %d\n",hash);
-#endif
for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);entry=entry->next);
- if(entry==NULL) {
+ if(entry==NULL)
+ {
#if 0
printk("adding rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n",
trh->saddr[0],trh->saddr[1],trh->saddr[2],
trh->saddr[3],trh->saddr[4],trh->saddr[5],
trh->rcf);
#endif
+ /*
+ * Allocate our new entry. A failure to allocate loses
+ * use the information. This is harmless.
+ *
+ * FIXME: We ought to keep some kind of cache size
+ * limiting and adjust the timers to suit.
+ */
entry=kmalloc(sizeof(struct rif_cache_s),GFP_ATOMIC);
- if(!entry) {
- printk("tr.c: Couldn't malloc rif cache entry !\n");
+ if(!entry)
+ {
+ printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n");
return;
}
entry->rcf=trh->rcf;
@@ -193,69 +289,92 @@
entry->next=rif_table[hash];
entry->last_used=jiffies;
rif_table[hash]=entry;
- }
-/* Y. Tahara added */
- else {
- if ( entry->rcf != trh->rcf ) {
- if (!(trh->rcf & htons(TR_RCF_BROADCAST_MASK))) {
+ }
+ else /* Y. Tahara added */
+ {
+ /*
+ * Update existing entries
+ */
+ if ( entry->rcf != trh->rcf )
+ {
+ if (!(trh->rcf & htons(TR_RCF_BROADCAST_MASK)))
+ {
#if 0
printk("updating rif_entry: addr:%02X:%02X:%02X:%02X:%02X:%02X rcf:%04X\n",
trh->saddr[0],trh->saddr[1],trh->saddr[2],
trh->saddr[3],trh->saddr[4],trh->saddr[5],
trh->rcf);
#endif
- entry->rcf = trh->rcf;
- memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
- entry->last_used=jiffies;
- }
+ entry->rcf = trh->rcf;
+ memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
+ entry->last_used=jiffies;
+ }
}
}
-
}
-static void rif_check_expire(unsigned long dummy) {
+/*
+ * Scan the cache with a timer and see what we need to throw out.
+ */
+static void rif_check_expire(unsigned long dummy)
+{
int i;
unsigned long now=jiffies,flags;
save_flags(flags);
cli();
- for(i=0; i < RIF_TABLE_SIZE;i++) {
-
- rif_cache entry, *pentry=rif_table+i;
-
+ for(i=0; i < RIF_TABLE_SIZE;i++)
+ {
+ rif_cache entry, *pentry=rif_table+i;
while((entry=*pentry))
- if((now-entry->last_used) > RIF_TIMEOUT) {
+ {
+ /*
+ * Out it goes
+ */
+ if((now-entry->last_used) > RIF_TIMEOUT)
+ {
*pentry=entry->next;
kfree_s(entry,sizeof(struct rif_cache_s));
}
else
- pentry=&entry->next;
+ pentry=&entry->next;
+ }
}
restore_flags(flags);
+ /*
+ * Reset the timer
+ */
+
del_timer(&rif_timer);
rif_timer.expires=jiffies+RIF_CHECK_INTERVAL;
add_timer(&rif_timer);
}
-int rif_get_info(char *buffer,char **start, off_t offset, int length) {
-
- int len=0;
- off_t begin=0;
- off_t pos=0;
- int size,i;
+/*
+ * Generate the /proc/net information for the token ring RIF
+ * routing.
+ */
+
+int rif_get_info(char *buffer,char **start, off_t offset, int length)
+{
+ int len=0;
+ off_t begin=0;
+ off_t pos=0;
+ int size,i;
- rif_cache entry;
+ rif_cache entry;
size=sprintf(buffer,
-" TR address rcf routing segments TTL\n\n");
- pos+=size;
- len+=size;
+ " TR address rcf routing segments TTL\n\n");
+ pos+=size;
+ len+=size;
- for(i=0;i < RIF_TABLE_SIZE;i++) {
+ for(i=0;i < RIF_TABLE_SIZE;i++)
+ {
for(entry=rif_table[i];entry;entry=entry->next) {
size=sprintf(buffer+len,"%02X:%02X:%02X:%02X:%02X:%02X %04X %04X %04X %04X %04X %04X %04X %04X %04X %lu\n",
entry->addr[0],entry->addr[1],entry->addr[2],entry->addr[3],entry->addr[4],entry->addr[5],
@@ -264,27 +383,33 @@
len+=size;
pos=begin+len;
- if(pos<offset) {
+ if(pos<offset)
+ {
len=0;
begin=pos;
}
if(pos>offset+length)
break;
- }
+ }
if(pos>offset+length)
break;
}
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Start slop */
- if(len>length)
- len=length; /* Ending slop */
- return len;
+ *start=buffer+(offset-begin); /* Start of wanted data */
+ len-=(offset-begin); /* Start slop */
+ if(len>length)
+ len=length; /* Ending slop */
+ return len;
}
-void rif_init(struct net_proto *unused) {
-
+/*
+ * Called during bootup. We don't actually have to initialise
+ * too much for this. The timer structure is setup statically. Thats
+ * probably NOT a good thing if we change the structure.
+ */
+
+void rif_init(struct net_proto *unused)
+{
add_timer(&rif_timer);
-
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov