2004-09-24 Paul Jakma <paul@dishone.st>

	* ospf_packet.c: (ospf_write) ifdef fragmentation support.
          move actual fragmentation out to a new, similarly ifdefed, function.
	  (ospf_write_frags) fragmented write support, moved from previous.
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 111ee09..5952d18 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -507,6 +507,70 @@
   iph->ip_id = ntohs(iph->ip_id);
 }
 
+#ifdef WANT_OSPF_WRITE_FRAGMENT
+void
+ospf_write_frags (struct ospf_packet *op, struct ip *ip, struct msghdr *msg, 
+                  struct iovec *iov, int maxdatasize);
+{
+#define OSPF_WRITE_FRAG_SHIFT 3
+
+  assert ( op->length == stream_get_endp(op->s) );
+
+  /* we can but try.
+   *
+   * SunOS, BSD and BSD derived kernels likely will clear ip_id, as
+   * well as the IP_MF flag, making this all quite pointless.
+   *
+   * However, for a system on which IP_MF is left alone, and ip_id left
+   * alone or else which sets same ip_id for each fragment this might
+   * work, eg linux.
+   *
+   * XXX-TODO: It would be much nicer to have the kernel's use their
+   * existing fragmentation support to do this for us. Bugs/RFEs need to
+   * be raised against the various kernels.
+   */
+  
+  /* set More Frag */
+  iph->ip_off |= IP_MF;
+  
+  /* ip frag offset is expressed in units of 8byte words */
+  offset = maxdatasize >> OSPF_WRITE_FRAG_SHIFT;
+  
+  while ( (stream_get_endp(op->s) - stream_get_getp (op->s)) 
+         > maxdatasize )
+    {
+      /* data length of this frag is to next offset value */
+      iov[1]->iov_len = offset << OSPF_WRITE_FRAG_SHIFT;
+      iph->ip_len = iov[1]->iov_len + sizeof (struct ip);
+      assert (iph->ip_len <= oi->ifp->mtu);
+
+      ospf_swab_iph_ton (iph);
+
+      ret = sendmsg (ospf->fd, msg, flags);
+      
+      ospf_swab_iph_toh (iph);
+      
+      if (ret < 0)
+        zlog_warn ("*** sendmsg in ospf_write to %s,"
+                   " id %d, off %d, len %d failed with %s",
+                   inet_ntoa (iph->ip_dst),
+                   iph->ip_id,
+                   iph->ip_off,
+                   iph->ip_len,
+                   strerror (errno));
+      
+      iph->ip_off += offset;
+      stream_forward (op->s, iov[1]->iov_len);
+      iov[1]->iov_base = STREAM_PNT (op->s); 
+    }
+    
+  /* setup for final fragment */
+  iov[1]->iov_len = stream_get_endp(op->s) - stream_get_getp (op->s);
+  iph->ip_len = iov[1]->iov_len + sizeof (struct ip);
+  iph->ip_off &= (~IP_MF);
+}
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
+
 int
 ospf_write (struct thread *thread)
 {
@@ -521,10 +585,11 @@
   int ret;
   int flags = 0;
   struct listnode *node;
+#ifdef WANT_OSPF_WRITE_FRAGMENT
   static u_int16_t ipid = 0;
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
   u_int16_t maxdatasize, offset;
 #define OSPF_WRITE_IPHL_SHIFT 2
-#define OSPF_WRITE_FRAG_SHIFT 3
   
   ospf->t_write = NULL;
 
@@ -532,11 +597,13 @@
   assert (node);
   oi = getdata (node);
   assert (oi);
-  
+
+#ifdef WANT_OSPF_WRITE_FRAGMENT
   /* seed ipid static with low order bits of time */
   if (ipid == 0)
     ipid = (time(NULL) & 0xffff);
-  
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
+
   /* convenience - max OSPF data per packet */
   maxdatasize = oi->ifp->mtu - sizeof (struct ip);
   
@@ -578,14 +645,15 @@
   iph.ip_v = IPVERSION;
   iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
   iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length;
-  iph.ip_id = 0;
 
+#ifdef WANT_OSPF_WRITE_FRAGMENT
   /* XXX-MT: not thread-safe at all..
    * XXX: this presumes this is only programme sending OSPF packets 
    * otherwise, no guarantee ipid will be unique
    */
   iph.ip_id = ++ipid;
-  
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
+
   iph.ip_off = 0;
   if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
     iph.ip_ttl = OSPF_VL_IP_TTL;
@@ -609,63 +677,10 @@
   /* Sadly we can not rely on kernels to fragment packets because of either
    * IP_HDRINCL and/or multicast destination being set.
    */
+#ifdef WANT_OSPF_WRITE_FRAGMENT
   if ( op->length > maxdatasize )
-    {
-      assert ( op->length == stream_get_endp(op->s) );
-
-      /* we can but try.
-       *
-       * SunOS, BSD and BSD derived kernels likely will clear ip_id, as
-       * well as the IP_MF flag, making this all quite pointless.
-       *
-       * However, for a system on which IP_MF is left alone, and ip_id left
-       * alone or else which sets same ip_id for each fragment this might
-       * work, eg linux.
-       *
-       * XXX-TODO: It would be much nicer to have the kernel's use their
-       * existing fragmentation support to do this for us. Bugs/RFEs need to
-       * be raised against the various kernels.
-       */
-      
-      /* set More Frag */
-      iph.ip_off |= IP_MF;
-      
-      /* ip frag offset is expressed in units of 8byte words */
-      offset = maxdatasize >> OSPF_WRITE_FRAG_SHIFT;      
-      
-      while ( (stream_get_endp(op->s) - stream_get_getp (op->s)) 
-             > maxdatasize )
-        {
-          /* data length of this frag is to next offset value */
-          iov[1].iov_len = offset << OSPF_WRITE_FRAG_SHIFT;
-          iph.ip_len = iov[1].iov_len + sizeof (struct ip);
-          assert (iph.ip_len <= oi->ifp->mtu);
-
-          ospf_swab_iph_ton (&iph);
-
-          ret = sendmsg (ospf->fd, &msg, flags);
-          
-          ospf_swab_iph_toh (&iph);
-          
-          if (ret < 0)
-            zlog_warn ("*** sendmsg in ospf_write to %s,"
-                       " id %d, off %d, len %d failed with %s",
-                       inet_ntoa (iph.ip_dst),
-                       iph.ip_id,
-                       iph.ip_off,
-                       iph.ip_len,
-                       strerror (errno));
-          
-          iph.ip_off += offset;
-          stream_forward (op->s, iov[1].iov_len);
-          iov[1].iov_base = STREAM_PNT (op->s); 
-        }
-        
-      /* setup for final fragment */
-      iov[1].iov_len = stream_get_endp(op->s) - stream_get_getp (op->s);
-      iph.ip_len = iov[1].iov_len + sizeof (struct ip);
-      iph.ip_off &= (~IP_MF);
-    }
+    ospf_write_frags (&op, &ip, &msg, &iov, maxdatasize);
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
 
   /* send final fragment (could be first) */
   ospf_swab_iph_ton (&iph);