[PATCH] IPv6 over token ring updated and bug fixes for 2.3.39

From: Mike Phillips (phillips@okpcm.com)
Date: Fri Jan 14 2000 - 09:59:09 EST


Attached is the patch for IPv6 over token ring now including the
necessary changes to the olympic driver as well. (The olympic changes do
not conflict with the recent smp changes to olympic - both patches
should apply clean with each other).

The previous patch contained a couple of subtle bugs, everything worked
fine if you were using only token ring and ip, but things got a little
interesting once ethernet and/or different protocols were thrown into
the mix.

Mike Phillips
Linux Token Ring Project
http://www.linxutr.net

diff -ur linux-2.3.39.orig/drivers/net/tokenring/ibmtr.c linux-2.3.39.ipv6/drivers/net/tokenring/ibmtr.c
--- linux-2.3.39.orig/drivers/net/tokenring/ibmtr.c Tue Jan 11 13:48:55 2000
+++ linux-2.3.39.ipv6/drivers/net/tokenring/ibmtr.c Thu Jan 13 15:29:07 2000
@@ -1651,7 +1651,7 @@
                ti->tr_stats.rx_packets++;
 
         skb->protocol = tr_type_trans(skb,dev);
- if (IPv4_p){
+ if (IPv4_p && (skb->protocol == ETH_P_IP)) {
                 skb->csum = chksum;
                 skb->ip_summed = 1;
         }
diff -ur linux-2.3.39.orig/drivers/net/tokenring/olympic.c linux-2.3.39.ipv6/drivers/net/tokenring/olympic.c
--- linux-2.3.39.orig/drivers/net/tokenring/olympic.c Tue Jan 11 13:48:55 2000
+++ linux-2.3.39.ipv6/drivers/net/tokenring/olympic.c Fri Jan 14 09:08:03 2000
@@ -202,7 +202,6 @@
 
                         olympic_priv->olympic_ring_speed = ringspeed[card_no] ;
                         olympic_priv->olympic_message_level = message_level[card_no] ;
- olympic_priv->olympic_multicast_set = 0 ;
         
                         if(olympic_init(dev)==-1) {
                                 unregister_netdevice(dev);
@@ -936,9 +935,11 @@
 {
         struct olympic_private *olympic_priv = (struct olympic_private *) dev->priv ;
            __u8 *olympic_mmio = olympic_priv->olympic_mmio ;
- __u8 options = 0, set_mc_list = 0 ;
- __u8 *srb, *ata ;
+ __u8 options = 0;
+ __u8 *srb;
         struct dev_mc_list *dmi ;
+ unsigned char dev_mc_address[4] ;
+ int i ;
 
         writel(olympic_priv->srb,olympic_mmio+LAPA);
         srb=olympic_priv->olympic_lap + (olympic_priv->srb & (~0xf800));
@@ -949,10 +950,6 @@
         else
                 options &= ~(3<<5) ;
 
- if (dev->mc_count) {
- set_mc_list = 1 ;
- }
-
         /* Only issue the srb if there is a change in options */
 
         if ((options ^ olympic_priv->olympic_copy_all_options)) {
@@ -975,60 +972,30 @@
                 return ;
         }
 
- if (set_mc_list ^ olympic_priv->olympic_multicast_set) { /* Multicast options have changed */
+ /* Set the functional addresses we need for multicast */
 
- dmi = dev->mc_list ;
-
- if (set_mc_list) { /* Turn multicast on */
-
- /* RFC 1469 Says we must support using the functional address C0 00 00 04 00 00
- * We do this with a set functional address mask.
- */
-
- ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
- if (!(readb(ata+11) & 0x04)) { /* Hmmm, need to set the functional mask */
- writeb(SRB_SET_FUNC_ADDRESS,srb+0);
- writeb(0,srb+1);
- writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
- writeb(0,srb+3);
- writeb(0,srb+4);
- writeb(0,srb+5);
- writeb(readb(ata+10),srb+6);
- writeb(readb(ata+11)|4,srb+7);
- writeb(readb(ata+12),srb+8);
- writeb(readb(ata+13),srb+9);
-
- olympic_priv->srb_queued = 2 ;
- writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-
- olympic_priv->olympic_multicast_set = 1 ;
- }
-
-
- } else { /* Turn multicast off */
-
- ata=olympic_priv->olympic_lap + (olympic_priv->olympic_addr_table_addr) ;
- if ((readb(ata+11) & 0x04)) { /* Hmmm, need to reset the functional mask */
- writeb(SRB_SET_FUNC_ADDRESS,srb+0);
- writeb(0,srb+1);
- writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
- writeb(0,srb+3);
- writeb(0,srb+4);
- writeb(0,srb+5);
- writeb(readb(ata+10),srb+6);
- writeb(readb(ata+11) & ~4,srb+7);
- writeb(readb(ata+12),srb+8);
- writeb(readb(ata+13),srb+9);
-
- olympic_priv->srb_queued = 2 ;
- writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
-
- olympic_priv->olympic_multicast_set = 0 ;
- }
- }
+ dev_mc_address[0] = dev_mc_address[1] = dev_mc_address[2] = dev_mc_address[3] = 0 ;
 
+ for (i=0,dmi=dev->mc_list;i < dev->mc_count; i++,dmi = dmi->next) {
+ dev_mc_address[0] |= dmi->dmi_addr[2] ;
+ dev_mc_address[1] |= dmi->dmi_addr[3] ;
+ dev_mc_address[2] |= dmi->dmi_addr[4] ;
+ dev_mc_address[3] |= dmi->dmi_addr[5] ;
         }
 
+ writeb(SRB_SET_FUNC_ADDRESS,srb+0);
+ writeb(0,srb+1);
+ writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
+ writeb(0,srb+3);
+ writeb(0,srb+4);
+ writeb(0,srb+5);
+ writeb(dev_mc_address[0],srb+6);
+ writeb(dev_mc_address[1],srb+7);
+ writeb(dev_mc_address[2],srb+8);
+ writeb(dev_mc_address[3],srb+9);
+
+ olympic_priv->srb_queued = 2 ;
+ writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
 
 }
 
@@ -1069,7 +1036,6 @@
                 case SRB_SET_GROUP_ADDRESS:
                         switch (readb(srb+2)) {
                                 case 0x00:
- olympic_priv->olympic_multicast_set = 1 ;
                                         break ;
                                 case 0x01:
                                         printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ;
@@ -1097,7 +1063,6 @@
                 case SRB_RESET_GROUP_ADDRESS:
                         switch (readb(srb+2)) {
                                 case 0x00:
- olympic_priv->olympic_multicast_set = 0 ;
                                         break ;
                                 case 0x01:
                                         printk(KERN_WARNING "%s: Unrecognized srb command \n",dev->name) ;
diff -ur linux-2.3.39.orig/drivers/net/tokenring/olympic.h linux-2.3.39.ipv6/drivers/net/tokenring/olympic.h
--- linux-2.3.39.orig/drivers/net/tokenring/olympic.h Tue Jan 11 13:48:55 2000
+++ linux-2.3.39.ipv6/drivers/net/tokenring/olympic.h Thu Jan 13 15:22:04 2000
@@ -265,7 +265,6 @@
         __u8 olympic_ring_speed ;
         __u16 pkt_buf_sz ;
         __u8 olympic_receive_options, olympic_copy_all_options, olympic_message_level;
- __u8 olympic_multicast_set ;
         __u16 olympic_addr_table_addr, olympic_parms_addr ;
         __u8 olympic_laa[6] ;
 };
diff -ur linux-2.3.39.orig/drivers/net/tokenring/tms380tr.c linux-2.3.39.ipv6/drivers/net/tokenring/tms380tr.c
--- linux-2.3.39.orig/drivers/net/tokenring/tms380tr.c Tue Jan 11 13:48:55 2000
+++ linux-2.3.39.ipv6/drivers/net/tokenring/tms380tr.c Thu Jan 13 15:30:45 2000
@@ -2470,7 +2470,8 @@
                                 tp->RplHead = SaveHead;
                                 break; /* Return to tms380tr_interrupt */
                         }
-
+#if 0 /* This might happen for multicast or broadcast packets.
+ The upper layers are expected to handle this, not here */
                         /* Drop frames sent by myself */
                         if(tms380tr_chk_frame(dev, rpl->MData))
                         {
@@ -2480,6 +2481,7 @@
                                         dev_kfree_skb(rpl->Skb);
                         }
                         else
+#endif
                         {
                           tms380tr_update_rcv_stats(tp,ReceiveDataPtr,Length);
                           
diff -ur linux-2.3.39.orig/include/net/if_inet6.h linux-2.3.39.ipv6/include/net/if_inet6.h
--- linux-2.3.39.orig/include/net/if_inet6.h Tue Jan 11 13:48:46 2000
+++ linux-2.3.39.ipv6/include/net/if_inet6.h Fri Jan 14 09:18:28 2000
@@ -119,5 +119,59 @@
 
         memcpy(buf + 2, &addr->s6_addr32[3], sizeof(__u32));
 }
+
+extern __inline__ void ipv6_tr_mc_map(struct in6_addr *addr, char *buf)
+{
+ /* All nodes FF01::1, FF02::1, FF02::1:FFxx:xxxx */
+
+ if (((addr->s6_addr[0] == 0xFF) &&
+ ((addr->s6_addr[1] == 0x01) || (addr->s6_addr[1] == 0x02)) &&
+ (addr->s6_addr16[1] == 0) &&
+ (addr->s6_addr32[1] == 0) &&
+ (addr->s6_addr32[2] == 0) &&
+ (addr->s6_addr16[6] == 0) &&
+ (addr->s6_addr[15] == 1)) ||
+ ((addr->s6_addr[0] == 0xFF) &&
+ (addr->s6_addr[1] == 0x02) &&
+ (addr->s6_addr16[1] == 0) &&
+ (addr->s6_addr32[1] == 0) &&
+ (addr->s6_addr16[4] == 0) &&
+ (addr->s6_addr[10] == 0) &&
+ (addr->s6_addr[11] == 1) &&
+ (addr->s6_addr[12] == 0xff)))
+ {
+ buf[0]=0xC0;
+ buf[1]=0x00;
+ buf[2]=0x01;
+ buf[3]=0x00;
+ buf[4]=0x00;
+ buf[5]=0x00;
+ /* All routers FF0x::2 */
+ } else if ((addr->s6_addr[0] ==0xff) &&
+ ((addr->s6_addr[1] & 0xF0) == 0) &&
+ (addr->s6_addr16[1] == 0) &&
+ (addr->s6_addr32[1] == 0) &&
+ (addr->s6_addr32[2] == 0) &&
+ (addr->s6_addr16[6] == 0) &&
+ (addr->s6_addr[15] == 2))
+ {
+ buf[0]=0xC0;
+ buf[1]=0x00;
+ buf[2]=0x02;
+ buf[3]=0x00;
+ buf[4]=0x00;
+ buf[5]=0x00;
+ } else {
+ unsigned char i ;
+
+ i = addr->s6_addr[15] & 7 ;
+ buf[0]=0xC0;
+ buf[1]=0x00;
+ buf[2]=0x00;
+ buf[3]=0x01 << i ;
+ buf[4]=0x00;
+ buf[5]=0x00;
+ }
+}
 #endif
 #endif
diff -ur linux-2.3.39.orig/net/ipv6/addrconf.c linux-2.3.39.ipv6/net/ipv6/addrconf.c
--- linux-2.3.39.orig/net/ipv6/addrconf.c Tue Jan 11 13:48:51 2000
+++ linux-2.3.39.ipv6/net/ipv6/addrconf.c Thu Jan 13 15:41:55 2000
@@ -670,6 +670,7 @@
 {
         switch (dev->type) {
         case ARPHRD_ETHER:
+ case ARPHRD_IEEE802_TR:
                 if (dev->addr_len != ETH_ALEN)
                         return -1;
                 memcpy(eui, dev->dev_addr, 3);
@@ -1191,7 +1192,8 @@
 
         ASSERT_RTNL();
 
- if (dev->type != ARPHRD_ETHER) {
+ if ((dev->type != ARPHRD_ETHER) &&
+ (dev->type != ARPHRD_IEEE802_TR)) {
                 /* Alas, we support only Ethernet autoconfiguration. */
                 return;
         }
@@ -1990,7 +1992,8 @@
                 case ARPHRD_LOOPBACK:
                         init_loopback(dev);
                         break;
- case ARPHRD_ETHER:
+ case ARPHRD_ETHER:
+ case ARPHRD_IEEE802_TR:
                         addrconf_dev_config(dev);
                         break;
                 default:
diff -ur linux-2.3.39.orig/net/ipv6/ndisc.c linux-2.3.39.ipv6/net/ipv6/ndisc.c
--- linux-2.3.39.orig/net/ipv6/ndisc.c Tue Jan 11 13:48:51 2000
+++ linux-2.3.39.ipv6/net/ipv6/ndisc.c Fri Jan 14 09:21:56 2000
@@ -161,6 +161,9 @@
         case ARPHRD_FDDI:
                 ipv6_eth_mc_map(addr, buf);
                 return 0;
+ case ARPHRD_IEEE802_TR:
+ ipv6_tr_mc_map(addr,buf);
+ return 0;
         default:
                 if (dir) {
                         memcpy(buf, dev->broadcast, dev->addr_len);
@@ -968,9 +971,22 @@
                                    does DAD, otherwise we ignore solicitations
                                    until DAD timer expires.
                                  */
- if (addr_type == IPV6_ADDR_ANY)
- addrconf_dad_failure(ifp);
- else
+ if (addr_type == IPV6_ADDR_ANY) {
+ if (dev->type == ARPHRD_IEEE802_TR) {
+ unsigned char *sadr = skb->mac.raw ;
+ if (((sadr[8] &0x7f) != (dev->dev_addr[0] & 0x7f)) ||
+ (sadr[9] != dev->dev_addr[1]) ||
+ (sadr[10] != dev->dev_addr[2]) ||
+ (sadr[11] != dev->dev_addr[3]) ||
+ (sadr[12] != dev->dev_addr[4]) ||
+ (sadr[13] != dev->dev_addr[5]))
+ {
+ addrconf_dad_failure(ifp) ;
+ }
+ } else {
+ addrconf_dad_failure(ifp);
+ }
+ } else
                                         in6_ifa_put(ifp);
                                 return 0;
                         }

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sat Jan 15 2000 - 21:00:23 EST