patch-2.1.26 linux/net/802/tr.c

Next file: linux/net/core/sock.c
Previous file: linux/net/802/sysctl_net_802.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.25/linux/net/802/tr.c linux/net/802/tr.c
@@ -6,7 +6,10 @@
  *		as published by the Free Software Foundation; either version
  *		2 of the License, or (at your option) any later version.
  *
- * Fixes:
+ * Fixes:       3 Feb 97 Paul Norton <pnorton@cts.com> Minor routing fixes.
+ *              Added rif table to /proc/net/tr_rif and rif timeout to
+ *              /proc/sys/net/token-ring/rif_timeout.
+ *        
  */
 
 #include <asm/uaccess.h>
@@ -26,31 +29,35 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/net.h>
+#include <linux/proc_fs.h>
 #include <net/arp.h>
 
-static void tr_source_route(struct trh_hdr *trh,struct device *dev);
-static void tr_add_rif_info(struct trh_hdr *trh);
+static void tr_source_route(struct trh_hdr *trh, struct device *dev);
+static void tr_add_rif_info(struct trh_hdr *trh, struct device *dev);
 static void rif_check_expire(unsigned long dummy);
 
+#define TR_SR_DEBUG 0
+
 typedef struct rif_cache_s *rif_cache;
 
 /*
  *	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];
-	 rif_cache next;
-	 unsigned long last_used;
+struct rif_cache_s {	
+	unsigned char addr[TR_ALEN];
+	unsigned char iface[5];
+	__u16 rcf;
+	__u8 rseg[8];
+	rif_cache next;
+	unsigned long last_used;
+	unsigned char local_ring;
 };
 
-#define RIF_TABLE_SIZE 16
+#define RIF_TABLE_SIZE 32
 
 /*
- *	We hash the RIF cache 16 ways. We do after all have to look it
+ *	We hash the RIF cache 32 ways. We do after all have to look it
  *	up a lot.
  */
  
@@ -63,11 +70,9 @@
  *	Garbage disposal timer.
  */
  
-static struct timer_list rif_timer=
-{
-	NULL,NULL,RIF_CHECK_INTERVAL,0L,rif_check_expire
-};
+static struct timer_list rif_timer;
 
+int sysctl_tr_rif_timeout = RIF_TIMEOUT;
 
 /*
  *	Put the headers on a token ring packet. Token ring source routing
@@ -130,7 +135,7 @@
 	 */
 	 
 	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));
+		printk("tr_rebuild_header: Don't know how to resolve type %04X addresses ?\n",(unsigned int)htons(trllc->ethertype));
 		return 0;
 	}
 
@@ -160,8 +165,7 @@
 	
 	skb_pull(skb,dev->hard_header_len);
 	
-	if(trh->saddr[0] & TR_RII)
-		tr_add_rif_info(trh);
+	tr_add_rif_info(trh, dev);
 
 	if(*trh->daddr & 1) 
 	{
@@ -214,11 +218,11 @@
 		 */
 		if(entry) 
 		{
-#if 0
+#if TR_SR_DEBUG
 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(!entry->local_ring && (ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8)
 			{
 				trh->rcf=entry->rcf;
 				memcpy(&trh->rseg[0],&entry->rseg[0],8*sizeof(unsigned short));
@@ -226,8 +230,15 @@
 				trh->rcf&=htons(0x1fff);	/* Issam Chehab <ichehab@madge1.demon.co.uk> */
 
 				trh->saddr[0]|=TR_RII;
-				entry->last_used=jiffies;
+#if TR_SR_DEBUG
+				printk("entry found with rcf %04x\n", entry->rcf);
+			}
+			else
+			{
+				printk("entry found but without rcf length, local=%02x\n", entry->local_ring);
+#endif
 			}
+			entry->last_used=jiffies;
 		}
 		else 
 		{
@@ -239,6 +250,7 @@
 			trh->rcf=htons((((sizeof(trh->rcf)) << 8) & TR_RCF_LEN_MASK)  
 				       | TR_RCF_FRAME2K | TR_RCF_LIMITED_BROADCAST);
 			trh->saddr[0]|=TR_RII;
+			printk("no entry in rif table found - broadcasting frame\n");
 		}
 	}
 }
@@ -248,27 +260,36 @@
  *	routing.
  */
  
-static void tr_add_rif_info(struct trh_hdr *trh) 
+static void tr_add_rif_info(struct trh_hdr *trh, struct device *dev)
 {
 	int i;
-	unsigned int hash;
+	unsigned int hash, rii_p = 0;
 	rif_cache entry;
 
 	/*
 	 *	Firstly see if the entry exists
 	 */
-	trh->saddr[0]&=0x7f;
+
+       	if(trh->saddr[0] & TR_RII)
+	{
+		trh->saddr[0]&=0x7f;
+		if (((ntohs(trh->rcf) & TR_RCF_LEN_MASK) >> 8) > 2)
+		{
+			rii_p = 1;
+	        }
+	}
+
 	for(i=0,hash=0;i<TR_ALEN;hash+=trh->saddr[i++]);
 	hash&=RIF_TABLE_SIZE-1;
 	for(entry=rif_table[hash];entry && memcmp(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);entry=entry->next);
 
 	if(entry==NULL) 
 	{
-#if 0
+#if TR_SR_DEBUG
 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);
+		ntohs(trh->rcf));
 #endif
 		/*
 		 *	Allocate our new entry. A failure to allocate loses
@@ -278,14 +299,26 @@
 		 *	limiting and adjust the timers to suit.
 		 */
 		entry=kmalloc(sizeof(struct rif_cache_s),GFP_ATOMIC);
+
 		if(!entry) 
 		{
 			printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n");
 			return;
 		}
-		entry->rcf=trh->rcf;
-		memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
+
+		if (rii_p)
+		{
+			entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK);
+			memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
+			entry->local_ring = 0;
+		}
+		else
+		{
+			entry->local_ring = 1;
+		}
+
 		memcpy(&(entry->addr[0]),&(trh->saddr[0]),TR_ALEN);
+		memcpy(&(entry->iface[0]),dev->name,5);
 		entry->next=rif_table[hash];
 		entry->last_used=jiffies;
 		rif_table[hash]=entry;
@@ -295,21 +328,20 @@
 		/*
 		 *	Update existing entries
 		 */
-		if ( entry->rcf != trh->rcf ) 
-		{ 
-			if (!(trh->rcf & htons(TR_RCF_BROADCAST_MASK))) 
-			{
-#if 0
+		if (!entry->local_ring) 
+		    if (entry->rcf != (trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK)) &&
+			 !(trh->rcf & htons(TR_RCF_BROADCAST_MASK)))
+		    {
+#if TR_SR_DEBUG
 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);
+		ntohs(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 & htons((unsigned short)~TR_RCF_BROADCAST_MASK);
+        		    memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short));
+		    }                                         
+           	entry->last_used=jiffies;               
 	}
 }
 
@@ -333,7 +365,7 @@
 			/*
 			 *	Out it goes
 			 */
-			if((now-entry->last_used) > RIF_TIMEOUT) 
+			if((now-entry->last_used) > sysctl_tr_rif_timeout) 
 			{
 				*pentry=entry->next;
 				kfree_s(entry,sizeof(struct rif_cache_s));
@@ -349,7 +381,7 @@
 	 */
 	 
 	del_timer(&rif_timer);
-	rif_timer.expires=jiffies+RIF_CHECK_INTERVAL;
+	rif_timer.expires = jiffies + sysctl_tr_rif_timeout;
 	add_timer(&rif_timer);
 
 }
@@ -359,27 +391,46 @@
  *	routing.
  */
  
-int rif_get_info(char *buffer,char **start, off_t offset, int length) 
+#ifdef CONFIG_PROC_FS
+int rif_get_info(char *buffer,char **start, off_t offset, int length, int dummy) 
 {
 	int len=0;
 	off_t begin=0;
 	off_t pos=0;
-	int size,i;
+	int size,i,j,rcf_len;
+	unsigned long now=jiffies;
 
 	rif_cache entry;
 
 	size=sprintf(buffer,
-		"   TR address     rcf             routing segments             TTL\n\n");
+		     "if     TR address       TTL   rcf   routing segments\n\n");
 	pos+=size;
 	len+=size;
 
 	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],
-								entry->rcf,entry->rseg[0],entry->rseg[1],entry->rseg[2],entry->rseg[3],
-								entry->rseg[4],entry->rseg[5],entry->rseg[6],entry->rseg[7],jiffies-entry->last_used); 
+			size=sprintf(buffer+len,"%s %02X:%02X:%02X:%02X:%02X:%02X %7li ",
+				     entry->iface,entry->addr[0],entry->addr[1],entry->addr[2],entry->addr[3],entry->addr[4],entry->addr[5],
+				     sysctl_tr_rif_timeout-(now-entry->last_used));
+			len+=size;
+			pos=begin+len;
+			if (entry->local_ring)
+			        size=sprintf(buffer+len,"local\n");
+			else {
+			        size=sprintf(buffer+len,"%04X", ntohs(entry->rcf));
+				rcf_len = ((ntohs(entry->rcf) & TR_RCF_LEN_MASK)>>8)-2; 
+				if (rcf_len)
+				        rcf_len >>= 1;
+				for(j = 0; j < rcf_len; j++) {
+				        len+=size;
+				        pos=begin+len;
+			                size=sprintf(buffer+len," %04X",ntohs(entry->rseg[j]));
+				}
+				len+=size;
+				pos=begin+len;
+			        size=sprintf(buffer+len,"\n");
+			}
 			len+=size;
 			pos=begin+len;
 
@@ -401,15 +452,28 @@
 		len=length;    /* Ending slop */
 	return len;
 }
+#endif
 
 /*
  *	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.
+ *	too much for this.
  */
  
 void rif_init(struct net_proto *unused) 
 {
+
+	rif_timer.expires  = RIF_TIMEOUT;
+	rif_timer.data     = 0L;
+	rif_timer.function = rif_check_expire;
+	init_timer(&rif_timer);
 	add_timer(&rif_timer);
-}
 
+#ifdef CONFIG_PROC_FS
+	proc_net_register(&(struct proc_dir_entry) {
+	  PROC_NET_TR_RIF, 6, "tr_rif",
+	    S_IFREG | S_IRUGO, 1, 0, 0,
+	    0, &proc_net_inode_operations,
+	    rif_get_info
+        });   
+#endif
+}

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov