[ospfd/isisd] Switch to lib/ Fletcher checksum, fixing bug in isisd

2008-08-13 Jingjing Duan <Jingjing.Duan@sun.com>

	* ospfd/: Remove the old checksum implementation and
	  use the consolidated version.
	* isisd/: ditto, thus fixing isisd checksuming on big-endian.

Signed-off-by: Paul Jakma <paul@quagga.net>
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 1a4deb1..48e3147 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -33,6 +33,7 @@
 #include "command.h"
 #include "hash.h"
 #include "if.h"
+#include "checksum.h"
 
 #include "isisd/dict.h"
 #include "isisd/isis_constants.h"
@@ -45,7 +46,6 @@
 #include "isisd/isis_dynhn.h"
 #include "isisd/isis_misc.h"
 #include "isisd/isis_flags.h"
-#include "isisd/iso_checksum.h"
 #include "isisd/isis_csm.h"
 #include "isisd/isis_adjacency.h"
 #include "isisd/isis_spf.h"
@@ -314,7 +314,7 @@
     newseq = seq_num++;
 
   lsp->lsp_header->seq_num = htonl (newseq);
-  iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
+  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
 		   ntohs (lsp->lsp_header->pdu_len) - 12, 12);
 
   return;
@@ -1803,7 +1803,7 @@
     tlv_add_is_neighs (lsp->tlv_data.es_neighs, lsp->pdu);
 
   lsp->lsp_header->pdu_len = htons (stream_get_endp (lsp->pdu));
-  iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
+  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
 		   ntohs (lsp->lsp_header->pdu_len) - 12, 12);
 
   list_delete (adj_list);
@@ -2071,7 +2071,7 @@
       lsp->lsp_header->pdu_len =
 	htons (ISIS_FIXED_HDR_LEN + ISIS_LSP_HDR_LEN);
       lsp->purged = 0;
-      iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
+      fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
 		       ntohs (lsp->lsp_header->pdu_len) - 12, 12);
       ISIS_FLAGS_SET_ALL (lsp->SRMflags);
     }
diff --git a/isisd/isis_pdu.c b/isisd/isis_pdu.c
index 6fcc5ed..4311a90 100644
--- a/isisd/isis_pdu.c
+++ b/isisd/isis_pdu.c
@@ -32,6 +32,7 @@
 #include "hash.c"
 #include "prefix.h"
 #include "if.h"
+#include "checksum.h"
 
 #include "isisd/dict.h"
 #include "isisd/include-netbsd/iso.h"
@@ -1121,7 +1122,7 @@
 		  if (isis->debugs & DEBUG_UPDATE_PACKETS)
 		    zlog_debug ("LSP LEN: %d",
 				ntohs (lsp->lsp_header->pdu_len));
-		  iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
+		  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
 				   ntohs (lsp->lsp_header->pdu_len) - 12, 12);
 		  ISIS_FLAGS_SET_ALL (lsp->SRMflags);
 		  if (isis->debugs & DEBUG_UPDATE_PACKETS)
@@ -1164,7 +1165,7 @@
 	  /* 7.3.16.1  */
 	  lsp->lsp_header->seq_num = htonl (ntohl (hdr->seq_num) + 1);
 
-	  iso_csum_create (STREAM_DATA (lsp->pdu) + 12,
+	  fletcher_checksum (STREAM_DATA (lsp->pdu) + 12,
 			   ntohs (lsp->lsp_header->pdu_len) - 12, 12);
 
 	  ISIS_FLAGS_SET_ALL (lsp->SRMflags);
diff --git a/isisd/iso_checksum.c b/isisd/iso_checksum.c
index 16f18e5..294fe99 100644
--- a/isisd/iso_checksum.c
+++ b/isisd/iso_checksum.c
@@ -23,6 +23,7 @@
 
 #include <zebra.h>
 #include "iso_checksum.h"
+#include "checksum.h"
 
 /*
  * Calculations of the OSI checksum.
@@ -47,14 +48,10 @@
 int
 iso_csum_verify (u_char * buffer, int len, uint16_t * csum)
 {
-  u_int8_t *p;
+  u_int16_t checksum;
   u_int32_t c0;
   u_int32_t c1;
-  u_int16_t checksum;
-  int i, partial_len;
 
-  p = buffer;
-  checksum = 0;
   c0 = *csum & 0xff00;
   c1 = *csum & 0x00ff;
 
@@ -70,124 +67,11 @@
   if (c0 == 0 || c1 == 0)
     return 1;
 
-  /*
-   * Otherwise initialize to zero and calculate...
-   */
-  c0 = 0;
-  c1 = 0;
+  /* Offset of checksum from the start of the buffer */
+  int offset = (u_char *) csum - buffer;
 
-  while (len)
-    {
-      partial_len = MIN(len, 5803);
-
-      for (i = 0; i < partial_len; i++)
-	{
-	  c0 = c0 + *(p++);
-	  c1 += c0;
-	}
-
-      c0 = c0 % 255;
-      c1 = c1 % 255;
-
-      len -= partial_len;
-    }
-
-  if (c0 == 0 && c1 == 0)
+  checksum = fletcher_checksum(buffer, len, offset);
+  if (checksum == *csum)
     return 0;
-
   return 1;
 }
-
-/*
- * Creates the checksum. *csum points to the position of the checksum in the 
- * PDU. 
- * Based on Annex C.4 of ISO/IEC 8473
- */
-#define FIXED_CODE
-u_int16_t
-iso_csum_create (u_char * buffer, int len, u_int16_t n)
-{
-
-  u_int8_t *p;
-  int x;
-  int y;
-  u_int32_t mul;
-  u_int32_t c0;
-  u_int32_t c1;
-  u_int16_t checksum;
-  u_int16_t *csum;
-  int i, init_len, partial_len;
-
-  checksum = 0;
-
-  /*
-   * Zero the csum in the packet.
-   */
-  csum = (u_int16_t *) (buffer + n);
-  *(csum) = checksum;
-
-  p = buffer;
-  c0 = 0;
-  c1 = 0;
-  init_len = len;
-
-  while (len != 0)
-    {
-      partial_len = MIN(len, 5803);
-
-      for (i = 0; i < partial_len; i++)
-	{
-	  c0 = c0 + *(p++);
-	  c1 += c0;
-	}
-
-      c0 = c0 % 255;
-      c1 = c1 % 255;
-
-      len -= partial_len;
-    }
-
-  mul = (init_len - n)*(c0);
-
-#ifdef FIXED_CODE
-  x = mul - c0 - c1;
-  y = c1 - mul - 1;
-
-  if (y > 0)
-    y++;
-  if (x < 0)
-    x--;
-
-  x %= 255;
-  y %= 255;
-
-  if (x == 0)
-    x = 255;
-  if (y == 0)
-    y = 1;
-
-  checksum = (y << 8) | (x & 0xFF);
-
-#else
-  x = mul - c0 - c1;
-  x %= 255;
-
-  y = c1 - mul - 1;
-  y %= 255;
-
-  if (x == 0)
-    x = 255;
-  if (y == 0)
-    y = 255;
-
-  checksum = ((y << 8) | x);
-#endif
-
-  /*
-   * Now we write this to the packet
-   */
-  *(csum) = checksum;
-
-  /* return the checksum for user usage */
-  return checksum;
-}
diff --git a/isisd/iso_checksum.h b/isisd/iso_checksum.h
index ba0d198..5f8d41f 100644
--- a/isisd/iso_checksum.h
+++ b/isisd/iso_checksum.h
@@ -24,6 +24,5 @@
 #define _ZEBRA_ISO_CSUM_H
 
 int iso_csum_verify (u_char * buffer, int len, uint16_t * csum);
-u_int16_t iso_csum_create (u_char * buffer, int len, u_int16_t n);
 
 #endif /* _ZEBRA_ISO_CSUM_H */
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 243928f..f453353 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -32,6 +32,7 @@
 #include "thread.h"
 #include "hash.h"
 #include "sockunion.h"		/* for inet_aton() */
+#include "checksum.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_interface.h"
@@ -172,46 +173,23 @@
 
 
 /* Fletcher Checksum -- Refer to RFC1008. */
-#define MODX                 4102
-#define LSA_CHECKSUM_OFFSET    15
 
+/* All the offsets are zero-based. The offsets in the RFC1008 are 
+   one-based. */
 u_int16_t
 ospf_lsa_checksum (struct lsa_header *lsa)
 {
-  u_char *sp, *ep, *p, *q;
-  int c0 = 0, c1 = 0;
-  int x, y;
-  u_int16_t length;
+  u_char *buffer = (u_char *) &lsa->options;
+  int options_offset = buffer - (u_char *) &lsa->ls_age; /* should be 2 */
 
-  lsa->checksum = 0;
-  length = ntohs (lsa->length) - 2;
-  sp = (u_char *) &lsa->options;
+  /* Skip the AGE field */
+  u_int16_t len = ntohs(lsa->length) - options_offset; 
 
-  for (ep = sp + length; sp < ep; sp = q)
-    {
-      q = sp + MODX;
-      if (q > ep)
-        q = ep;
-      for (p = sp; p < q; p++)
-        {
-          c0 += *p;
-          c1 += c0;
-        }
-      c0 %= 255;
-      c1 %= 255;
-    }
+  /* Checksum offset starts from "options" field, not the beginning of the
+     lsa_header struct. The offset is 14, rather than 16. */
+  int checksum_offset = (u_char *) &lsa->checksum - buffer;
 
-  x = (((int)length - LSA_CHECKSUM_OFFSET) * c0 - c1) % 255;
-  if (x <= 0)
-    x += 255;
-  y = 510 - c0 - x;
-  if (y > 255)
-    y -= 255;
-
-  /* take care endian issue. */
-  lsa->checksum = htons ((x << 8) + y);
-
-  return (lsa->checksum);
+  return fletcher_checksum(buffer, len, checksum_offset);
 }