]> git.proxmox.com Git - mirror_frr.git/blobdiff - ospfd/ospf_packet.c
[doc] bug #245, remove reference to non-existent log_mode argument
[mirror_frr.git] / ospfd / ospf_packet.c
index a0a9931c6252b11d9cfe419bd0f8ed1659bba42c..d6aca719862452271b25eabdcb1d1974f7874cc3 100644 (file)
@@ -31,7 +31,9 @@
 #include "sockunion.h"
 #include "stream.h"
 #include "log.h"
-#include "md5-gnu.h"
+#include "sockopt.h"
+#include "checksum.h"
+#include "md5.h"
 
 #include "ospfd/ospfd.h"
 #include "ospfd/ospf_network.h"
 #include "ospfd/ospf_flood.h"
 #include "ospfd/ospf_dump.h"
 
-static void ospf_ls_ack_send_list (struct ospf_interface *, list,
-                                  struct in_addr);
-
 /* Packet Type String. */
-char *ospf_packet_type_str[] =
+const char *ospf_packet_type_str[] =
 {
   "unknown",
   "Hello",
@@ -61,10 +60,8 @@ char *ospf_packet_type_str[] =
   "Link State Acknowledgment",
 };
 
-extern int in_cksum (void *ptr, int nbytes);
-
 /* OSPF authentication checking function */
-int
+static int
 ospf_auth_type (struct ospf_interface *oi)
 {
   int auth_type;
@@ -83,13 +80,6 @@ ospf_auth_type (struct ospf_interface *oi)
 
 }
 
-/* forward output pointer. */
-void
-ospf_output_forward (struct stream *s, int size)
-{
-  s->putp += size;
-}
-
 struct ospf_packet *
 ospf_packet_new (size_t size)
 {
@@ -191,6 +181,17 @@ ospf_fifo_free (struct ospf_fifo *fifo)
 void
 ospf_packet_add (struct ospf_interface *oi, struct ospf_packet *op)
 {
+  if (!oi->obuf)
+    {
+      zlog_err("ospf_packet_add(interface %s in state %d [%s], packet type %s, "
+              "destination %s) called with NULL obuf, ignoring "
+              "(please report this bug)!\n",
+              IF_NAME(oi), oi->state, LOOKUP (ospf_ism_state_msg, oi->state),
+              ospf_packet_type_str[stream_getc_from(op->s, 1)],
+              inet_ntoa (op->dst));
+      return;
+    }
+
   /* Add packet to end of queue. */
   ospf_fifo_push (oi->obuf, op);
 
@@ -209,18 +210,6 @@ ospf_packet_delete (struct ospf_interface *oi)
     ospf_packet_free (op);
 }
 
-struct stream *
-ospf_stream_copy (struct stream *new, struct stream *s)
-{
-  new->endp = s->endp;
-  new->putp = s->putp;
-  new->getp = s->getp;
-
-  memcpy (new->data, s->data, stream_get_endp (s));
-
-  return new;
-}
-
 struct ospf_packet *
 ospf_packet_dup (struct ospf_packet *op)
 {
@@ -232,7 +221,7 @@ ospf_packet_dup (struct ospf_packet *op)
 
   /* Reserve space for MD5 authentication that may be added later. */
   new = ospf_packet_new (stream_get_endp(op->s) + OSPF_AUTH_MD5_SIZE);
-  ospf_stream_copy (new->s, op->s);
+  stream_copy (new->s, op->s);
 
   new->dst = op->dst;
   new->length = op->length;
@@ -240,26 +229,37 @@ ospf_packet_dup (struct ospf_packet *op)
   return new;
 }
 
-int
+/* XXX inline */
+static inline unsigned int
+ospf_packet_authspace (struct ospf_interface *oi)
+{
+  int auth = 0;
+
+  if ( ospf_auth_type (oi) == OSPF_AUTH_CRYPTOGRAPHIC)
+    auth = OSPF_AUTH_MD5_SIZE;
+
+  return auth;
+}
+
+static unsigned int
 ospf_packet_max (struct ospf_interface *oi)
 {
   int max;
 
-  if ( ospf_auth_type (oi) == OSPF_AUTH_CRYPTOGRAPHIC)
-    max = oi->ifp->mtu - OSPF_AUTH_MD5_SIZE - 88;
-  else
-    max = oi->ifp->mtu - 88;
+  max = oi->ifp->mtu - ospf_packet_authspace(oi);
+
+  max -= (OSPF_HEADER_SIZE + sizeof (struct ip));
 
   return max;
 }
 
 \f
-int
+static int
 ospf_check_md5_digest (struct ospf_interface *oi, struct stream *s,
                        u_int16_t length)
 {
-  void *ibuf;
-  struct md5_ctx ctx;
+  unsigned char *ibuf;
+  MD5_CTX ctx;
   unsigned char digest[OSPF_AUTH_MD5_SIZE];
   unsigned char *pdigest;
   struct crypt_key *ck;
@@ -296,10 +296,11 @@ ospf_check_md5_digest (struct ospf_interface *oi, struct stream *s,
     }
       
   /* Generate a digest for the ospf packet - their digest + our digest. */
-  md5_init_ctx (&ctx);
-  md5_process_bytes (ibuf, length, &ctx);
-  md5_process_bytes (ck->auth_key, OSPF_AUTH_MD5_SIZE, &ctx);
-  md5_finish_ctx (&ctx, digest);
+  memset(&ctx, 0, sizeof(ctx));
+  MD5Init(&ctx);
+  MD5Update(&ctx, ibuf, length);
+  MD5Update(&ctx, ck->auth_key, OSPF_AUTH_MD5_SIZE);
+  MD5Final(digest, &ctx);
 
   /* compare the two */
   if (memcmp (pdigest, digest, OSPF_AUTH_MD5_SIZE))
@@ -318,17 +319,16 @@ ospf_check_md5_digest (struct ospf_interface *oi, struct stream *s,
 /* This function is called from ospf_write(), it will detect the
    authentication scheme and if it is MD5, it will change the sequence
    and update the MD5 digest. */
-int
+static int
 ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op)
 {
   struct ospf_header *ospfh;
   unsigned char digest[OSPF_AUTH_MD5_SIZE];
-  struct md5_ctx ctx;
+  MD5_CTX ctx;
   void *ibuf;
-  unsigned long oldputp;
   u_int32_t t;
   struct crypt_key *ck;
-  char *auth_key;
+  const u_int8_t *auth_key;
 
   ibuf = STREAM_DATA (op->s);
   ospfh = (struct ospf_header *) ibuf;
@@ -339,29 +339,31 @@ ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op)
   /* We do this here so when we dup a packet, we don't have to
      waste CPU rewriting other headers. */
   t = (time(NULL) & 0xFFFFFFFF);
-  oi->crypt_seqnum = ( t > oi->crypt_seqnum ? t : oi->crypt_seqnum++);
+  if (t > oi->crypt_seqnum)
+    oi->crypt_seqnum = t;
+  else
+    oi->crypt_seqnum++;
+  
   ospfh->u.crypt.crypt_seqnum = htonl (oi->crypt_seqnum); 
 
   /* Get MD5 Authentication key from auth_key list. */
   if (list_isempty (OSPF_IF_PARAM (oi, auth_crypt)))
-    auth_key = "";
+    auth_key = (const u_int8_t *) "";
   else
     {
-      ck = getdata (OSPF_IF_PARAM (oi, auth_crypt)->tail);
+      ck = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt)));
       auth_key = ck->auth_key;
     }
 
   /* Generate a digest for the entire packet + our secret key. */
-  md5_init_ctx (&ctx);
-  md5_process_bytes (ibuf, ntohs (ospfh->length), &ctx);
-  md5_process_bytes (auth_key, OSPF_AUTH_MD5_SIZE, &ctx);
-  md5_finish_ctx (&ctx, digest);
+  memset(&ctx, 0, sizeof(ctx));
+  MD5Init(&ctx);
+  MD5Update(&ctx, ibuf, ntohs (ospfh->length));
+  MD5Update(&ctx, auth_key, OSPF_AUTH_MD5_SIZE);
+  MD5Final(digest, &ctx);
 
   /* Append md5 digest to the end of the stream. */
-  oldputp = stream_get_putp (op->s);
-  stream_set_putp (op->s, ntohs (ospfh->length));
   stream_put (op->s, digest, OSPF_AUTH_MD5_SIZE);
-  stream_set_putp (op->s, oldputp);
 
   /* We do *NOT* increment the OSPF header length. */
   op->length = ntohs (ospfh->length) + OSPF_AUTH_MD5_SIZE;
@@ -373,7 +375,7 @@ ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op)
 }
 
 \f
-int
+static int
 ospf_ls_req_timer (struct thread *thread)
 {
   struct ospf_neighbor *nbr;
@@ -415,13 +417,11 @@ ospf_ls_upd_timer (struct thread *thread)
   /* Send Link State Update. */
   if (ospf_ls_retransmit_count (nbr) > 0)
     {
-      list update;
+      struct list *update;
       struct ospf_lsdb *lsdb;
       int i;
-      struct timeval now;
       int retransmit_interval;
 
-      gettimeofday (&now, NULL);
       retransmit_interval = OSPF_IF_PARAM (nbr->oi, retransmit_interval);
 
       lsdb = &nbr->ls_rxmt;
@@ -444,7 +444,7 @@ ospf_ls_upd_timer (struct thread *thread)
                  fired.  This is a small tweak to what is in the RFC,
                  but it will cut out out a lot of retransmit traffic
                  - MAG */
-               if (tv_cmp (tv_sub (now, lsa->tv_recv), 
+               if (tv_cmp (tv_sub (recent_time, lsa->tv_recv), 
                            int2tv (retransmit_interval)) >= 0)
                  listnode_add (update, rn->info);
            }
@@ -479,7 +479,92 @@ ospf_ls_ack_timer (struct thread *thread)
   return 0;
 }
 
-int
+#ifdef WANT_OSPF_WRITE_FRAGMENT
+static void
+ospf_write_frags (int fd, struct ospf_packet *op, struct ip *iph, 
+                  struct msghdr *msg, unsigned int maxdatasize, 
+                  unsigned int mtu, int flags, u_char type)
+{
+#define OSPF_WRITE_FRAG_SHIFT 3
+  u_int16_t offset;
+  struct iovec *iovp;
+  int ret;
+
+  assert ( op->length == stream_get_endp(op->s) );
+  assert (msg->msg_iovlen == 2);
+
+  /* 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;
+  
+  iovp = &msg->msg_iov[1];
+  
+  while ( (stream_get_endp(op->s) - stream_get_getp (op->s)) 
+         > maxdatasize )
+    {
+      /* data length of this frag is to next offset value */
+      iovp->iov_len = offset << OSPF_WRITE_FRAG_SHIFT;
+      iph->ip_len = iovp->iov_len + sizeof (struct ip);
+      assert (iph->ip_len <= mtu);
+
+      sockopt_iphdrincl_swab_htosys (iph);
+
+      ret = sendmsg (fd, msg, flags);
+      
+      sockopt_iphdrincl_swab_systoh (iph);
+      
+      if (ret < 0)
+        zlog_warn ("*** ospf_write_frags: sendmsg failed to %s,"
+                  " id %d, off %d, len %d, mtu %u failed with %s",
+                  inet_ntoa (iph->ip_dst),
+                  iph->ip_id,
+                  iph->ip_off,
+                  iph->ip_len,
+                  mtu,
+                  safe_strerror (errno));
+      
+      if (IS_DEBUG_OSPF_PACKET (type - 1, SEND))
+        {
+          zlog_debug ("ospf_write_frags: sent id %d, off %d, len %d to %s\n",
+                     iph->ip_id, iph->ip_off, iph->ip_len,
+                     inet_ntoa (iph->ip_dst));
+          if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
+            {
+              zlog_debug ("-----------------IP Header Dump----------------------");
+              ospf_ip_header_dump (iph);
+              zlog_debug ("-----------------------------------------------------");
+            }
+        }
+      
+      iph->ip_off += offset;
+      stream_forward_getp (op->s, iovp->iov_len);
+      iovp->iov_base = STREAM_PNT (op->s); 
+    }
+    
+  /* setup for final fragment */
+  iovp->iov_len = stream_get_endp(op->s) - stream_get_getp (op->s);
+  iph->ip_len = iovp->iov_len + sizeof (struct ip);
+  iph->ip_off &= (~IP_MF);
+}
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
+
+static int
 ospf_write (struct thread *thread)
 {
   struct ospf *ospf = THREAD_ARG (thread);
@@ -492,14 +577,28 @@ ospf_write (struct thread *thread)
   u_char type;
   int ret;
   int flags = 0;
-  listnode node;
+  struct listnode *node;
+#ifdef WANT_OSPF_WRITE_FRAGMENT
+  static u_int16_t ipid = 0;
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
+  u_int16_t maxdatasize;
+#define OSPF_WRITE_IPHL_SHIFT 2
   
   ospf->t_write = NULL;
 
   node = listhead (ospf->oi_write_q);
   assert (node);
-  oi = getdata (node);
+  oi = listgetdata (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);
   
   /* Get one packet from queue. */
   op = ospf_fifo_head (oi->obuf);
@@ -508,12 +607,21 @@ ospf_write (struct thread *thread)
 
   if (op->dst.s_addr == htonl (OSPF_ALLSPFROUTERS)
       || op->dst.s_addr == htonl (OSPF_ALLDROUTERS))
-    ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex);
-
+      ospf_if_ipmulticast (ospf, oi->address, oi->ifp->ifindex);
+    
   /* Rewrite the md5 signature & update the seq */
   ospf_make_md5_digest (oi, op);
 
+  /* Retrieve OSPF packet type. */
+  stream_set_getp (op->s, 1);
+  type = stream_getc (op->s);
+  
+  /* reset get pointer */
+  stream_set_getp (op->s, 0);
+
+  memset (&iph, 0, sizeof (struct ip));
   memset (&sa_dst, 0, sizeof (sa_dst));
+  
   sa_dst.sin_family = AF_INET;
 #ifdef HAVE_SIN_LEN
   sa_dst.sin_len = sizeof(sa_dst);
@@ -526,15 +634,24 @@ ospf_write (struct thread *thread)
     if (!IN_MULTICAST (htonl (op->dst.s_addr)))
       flags = MSG_DONTROUTE;
 
-  iph.ip_hl = sizeof (struct ip) >> 2;
+  iph.ip_hl = sizeof (struct ip) >> OSPF_WRITE_IPHL_SHIFT;
+  /* it'd be very strange for header to not be 4byte-word aligned but.. */
+  if ( sizeof (struct ip) 
+        > (unsigned int)(iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) )
+    iph.ip_hl++; /* we presume sizeof struct ip cant overflow ip_hl.. */
+  
   iph.ip_v = IPVERSION;
   iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
-#if defined(__NetBSD__) || defined(__FreeBSD__)
-  iph.ip_len = iph.ip_hl*4 + op->length;
-#else
-  iph.ip_len = htons (iph.ip_hl*4 + op->length);
-#endif
-  iph.ip_id = 0;
+  iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length;
+
+#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;
@@ -546,41 +663,52 @@ ospf_write (struct thread *thread)
   iph.ip_dst.s_addr = op->dst.s_addr;
 
   memset (&msg, 0, sizeof (msg));
-  msg.msg_name = &sa_dst;
+  msg.msg_name = (caddr_t) &sa_dst;
   msg.msg_namelen = sizeof (sa_dst); 
   msg.msg_iov = iov;
   msg.msg_iovlen = 2;
   iov[0].iov_base = (char*)&iph;
-  iov[0].iov_len = iph.ip_hl*4;
-  iov[1].iov_base = STREAM_DATA (op->s);
+  iov[0].iov_len = iph.ip_hl << OSPF_WRITE_IPHL_SHIFT;
+  iov[1].iov_base = STREAM_PNT (op->s);
   iov[1].iov_len = op->length;
-
+  
+  /* 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 )
+    ospf_write_frags (ospf->fd, op, &iph, &msg, maxdatasize, 
+                      oi->ifp->mtu, flags, type);
+#endif /* WANT_OSPF_WRITE_FRAGMENT */
+
+  /* send final fragment (could be first) */
+  sockopt_iphdrincl_swab_htosys (&iph);
   ret = sendmsg (ospf->fd, &msg, flags);
+  sockopt_iphdrincl_swab_systoh (&iph);
   
   if (ret < 0)
-    zlog_warn ("*** sendmsg in ospf_write to %s failed with %s", 
-               inet_ntoa (iph.ip_dst), strerror (errno));
-
-  /* Retrieve OSPF packet type. */
-  stream_set_getp (op->s, 1);
-  type = stream_getc (op->s);
+    zlog_warn ("*** sendmsg in ospf_write failed to %s, "
+              "id %d, off %d, len %d, interface %s, mtu %u: %s",
+              inet_ntoa (iph.ip_dst), iph.ip_id, iph.ip_off, iph.ip_len,
+              oi->ifp->name, oi->ifp->mtu, safe_strerror (errno));
 
   /* Show debug sending packet. */
   if (IS_DEBUG_OSPF_PACKET (type - 1, SEND))
     {
       if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
        {
-         zlog_info ("-----------------------------------------------------");
+         zlog_debug ("-----------------------------------------------------");
+         ospf_ip_header_dump (&iph);
          stream_set_getp (op->s, 0);
          ospf_packet_dump (op->s);
        }
 
-      zlog_info ("%s sent to [%s] via [%s].",
+      zlog_debug ("%s sent to [%s] via [%s].",
                 ospf_packet_type_str[type], inet_ntoa (op->dst),
                 IF_NAME (oi));
 
       if (IS_DEBUG_OSPF_PACKET (type - 1, DETAIL))
-       zlog_info ("-----------------------------------------------------");
+       zlog_debug ("-----------------------------------------------------");
     }
 
   /* Now delete packet from queue. */
@@ -601,15 +729,14 @@ ospf_write (struct thread *thread)
 }
 
 /* OSPF Hello message read -- RFC2328 Section 10.5. */
-void
+static void
 ospf_hello (struct ip *iph, struct ospf_header *ospfh,
            struct stream * s, struct ospf_interface *oi, int size)
 {
   struct ospf_hello *hello;
   struct ospf_neighbor *nbr;
-  struct route_node *rn;
-  struct prefix p, key;
   int old_state;
+  struct prefix p;
 
   /* increment statistics. */
   oi->hello_in++;
@@ -618,12 +745,32 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
 
   /* If Hello is myself, silently discard. */
   if (IPV4_ADDR_SAME (&ospfh->router_id, &oi->ospf->router_id))
-    return;
+    {
+      if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+        {
+          zlog_debug ("ospf_header[%s/%s]: selforiginated, "
+                     "dropping.",
+                     ospf_packet_type_str[ospfh->type],
+                     inet_ntoa (iph->ip_src));
+        }
+      return;
+    }
 
   /* If incoming interface is passive one, ignore Hello. */
   if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE) {
-    zlog_info ("Packet %s [HELLO:RECV]: oi is passive",
-               inet_ntoa (ospfh->router_id));
+    char buf[3][INET_ADDRSTRLEN];
+    zlog_debug ("ignoring HELLO from router %s sent to %s, "
+               "received on a passive interface, %s",
+               inet_ntop(AF_INET, &ospfh->router_id, buf[0], sizeof(buf[0])),
+               inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])),
+               inet_ntop(AF_INET, &oi->address->u.prefix4,
+                         buf[2], sizeof(buf[2])));
+    if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS))
+      {
+        /* Try to fix multicast membership. */
+        SET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
+        ospf_if_set_multicast(oi);
+      }
     return;
   }
 
@@ -643,14 +790,6 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
        return;
       }
 
-  /* Compare Hello Interval. */
-  if (OSPF_IF_PARAM (oi, v_hello) != ntohs (hello->hello_interval))
-    {
-      zlog_warn ("Packet %s [Hello:RECV]: HelloInterval mismatch.",
-                inet_ntoa (ospfh->router_id));
-      return;
-    }
-
   /* Compare Router Dead Interval. */
   if (OSPF_IF_PARAM (oi, v_wait) != ntohl (hello->dead_interval))
     {
@@ -659,8 +798,19 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
       return;
     }
 
+  /* Compare Hello Interval - ignored if fast-hellos are set. */
+  if (OSPF_IF_PARAM (oi, fast_hello) == 0)
+    {
+      if (OSPF_IF_PARAM (oi, v_hello) != ntohs (hello->hello_interval))
+        {
+          zlog_warn ("Packet %s [Hello:RECV]: HelloInterval mismatch.",
+                     inet_ntoa (ospfh->router_id));
+          return;
+        }
+    }
+  
   if (IS_DEBUG_OSPF_EVENT)
-    zlog_info ("Packet %s [Hello:RECV]: Options %s",
+    zlog_debug ("Packet %s [Hello:RECV]: Options %s",
               inet_ntoa (ospfh->router_id),
               ospf_options_dump (hello->options));
 
@@ -699,7 +849,6 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
 
   /* new for NSSA is to ensure that NP is on and E is off */
 
-#ifdef HAVE_NSSA
   if (oi->area->external_routing == OSPF_AREA_NSSA) 
     {
       if (! (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_NP)
@@ -711,10 +860,9 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
          return;
        }
       if (IS_DEBUG_OSPF_NSSA)
-        zlog_info ("NSSA-Hello:RECV:Packet from %s:", inet_ntoa(ospfh->router_id));
+        zlog_debug ("NSSA-Hello:RECV:Packet from %s:", inet_ntoa(ospfh->router_id));
     }
   else    
-#endif /* HAVE_NSSA */
     /* The setting of the E-bit found in the Hello Packet's Options
        field must match this area's ExternalRoutingCapability A
        mismatch causes processing to stop and the packet to be
@@ -723,74 +871,16 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
     if (CHECK_FLAG (OPTIONS (oi), OSPF_OPTION_E) !=
        CHECK_FLAG (hello->options, OSPF_OPTION_E))
       {
-       zlog_warn ("Packet[Hello:RECV]: my options: %x, his options %x",
-                  OPTIONS (oi), hello->options);
+       zlog_warn ("Packet %s [Hello:RECV]: my options: %x, his options %x",
+                  inet_ntoa(ospfh->router_id), OPTIONS (oi), hello->options);
        return;
       }
-
-
-  /* Get neighbor information from table. */
-  key.family = AF_INET;
-  key.prefixlen = IPV4_MAX_BITLEN;
-  key.u.prefix4 = iph->ip_src;
-
-  rn = route_node_get (oi->nbrs, &key);
-  if (rn->info)
-    {
-      route_unlock_node (rn);
-      nbr = rn->info;
-
-      if (oi->type == OSPF_IFTYPE_NBMA && nbr->state == NSM_Attempt)
-       {
-         nbr->src = iph->ip_src;
-         nbr->address = p;
-       }
-    }
-  else
-    {
-      /* Create new OSPF Neighbor structure. */
-      nbr = ospf_nbr_new (oi);
-      nbr->state = NSM_Down;
-      nbr->src = iph->ip_src;
-      nbr->address = p;
-
-      rn->info = nbr;
-
-      nbr->nbr_nbma = NULL;
-
-      if (oi->type == OSPF_IFTYPE_NBMA)
-       {
-         struct ospf_nbr_nbma *nbr_nbma;
-         listnode node;
-
-         for (node = listhead (oi->nbr_nbma); node; nextnode (node))
-           {
-             nbr_nbma = getdata (node);
-             assert (nbr_nbma);
-      
-             if (IPV4_ADDR_SAME(&nbr_nbma->addr, &iph->ip_src))
-               {
-                 nbr_nbma->nbr = nbr;
-                 nbr->nbr_nbma = nbr_nbma;
-
-                 if (nbr_nbma->t_poll)
-                   OSPF_POLL_TIMER_OFF (nbr_nbma->t_poll);
-                 
-                 nbr->state_change = nbr_nbma->state_change + 1;
-               }
-           }
-       }
-      
-      /* New nbr, save the crypto sequence number if necessary */
-      if (ntohs (ospfh->auth_type) == OSPF_AUTH_CRYPTOGRAPHIC)
-       nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
-
-      if (IS_DEBUG_OSPF_EVENT)
-       zlog_info ("NSM[%s:%s]: start", IF_NAME (nbr->oi),
-                  inet_ntoa (nbr->router_id));
-    }
   
-  nbr->router_id = ospfh->router_id;
+  /* get neighbour struct */
+  nbr = ospf_nbr_get (oi, ospfh, iph, &p);
+
+  /* neighbour must be valid, ospf_nbr_get creates if none existed */
+  assert (nbr);
 
   old_state = nbr->state;
 
@@ -874,7 +964,7 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
 }
 
 /* Save DD flags/options/Seqnum received. */
-void
+static void
 ospf_db_desc_save_current (struct ospf_neighbor *nbr,
                           struct ospf_db_desc *dd)
 {
@@ -892,17 +982,17 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi,
   struct ospf_lsa *new, *find;
   struct lsa_header *lsah;
 
-  stream_forward (s, OSPF_DB_DESC_MIN_SIZE);
+  stream_forward_getp (s, OSPF_DB_DESC_MIN_SIZE);
   for (size -= OSPF_DB_DESC_MIN_SIZE;
        size >= OSPF_LSA_HEADER_SIZE; size -= OSPF_LSA_HEADER_SIZE) 
     {
       lsah = (struct lsa_header *) STREAM_PNT (s);
-      stream_forward (s, OSPF_LSA_HEADER_SIZE);
+      stream_forward_getp (s, OSPF_LSA_HEADER_SIZE);
 
       /* Unknown LS type. */
       if (lsah->type < OSPF_MIN_LSA || lsah->type >= OSPF_MAX_LSA)
        {
-         zlog_warn ("Pakcet [DD:RECV]: Unknown LS type %d.", lsah->type);
+         zlog_warn ("Packet [DD:RECV]: Unknown LS type %d.", lsah->type);
          OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
          return;
        }
@@ -923,13 +1013,9 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi,
 #ifdef HAVE_OPAQUE_LSA
        case OSPF_OPAQUE_AS_LSA:
 #endif /* HAVE_OPAQUE_LSA */
-#ifdef HAVE_NSSA
           /* Check for stub area.  Reject if AS-External from stub but
              allow if from NSSA. */
           if (oi->area->external_routing == OSPF_AREA_STUB)
-#else /* ! HAVE_NSSA */
-          if (oi->area->external_routing != OSPF_AREA_DEFAULT)
-#endif /* HAVE_NSSA */
             {
               zlog_warn ("Packet [DD:RECV]: LSA[Type%d:%s] from %s area.",
                          lsah->type, inet_ntoa (lsah->id),
@@ -957,7 +1043,7 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi,
        {
          /* Received LSA is not recent. */
          if (IS_DEBUG_OSPF_EVENT)
-           zlog_info ("Packet [DD:RECV]: LSA received Type %d, "
+           zlog_debug ("Packet [DD:RECV]: LSA received Type %d, "
                       "ID %s is not recent.", lsah->type, inet_ntoa (lsah->id));
          ospf_lsa_discard (new);
          continue;
@@ -987,7 +1073,7 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi,
          OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone);
        }
 
-      /* Send DD pakcet in reply. */
+      /* Send DD packet in reply. */
       ospf_db_desc_send (nbr);
     }
 
@@ -995,7 +1081,7 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi,
   ospf_db_desc_save_current (nbr, dd);
 }
 
-int
+static int
 ospf_db_desc_is_dup (struct ospf_db_desc *dd, struct ospf_neighbor *nbr)
 {
   /* Is DD duplicated? */
@@ -1008,7 +1094,7 @@ ospf_db_desc_is_dup (struct ospf_db_desc *dd, struct ospf_neighbor *nbr)
 }
 
 /* OSPF Database Description message read -- RFC2328 Section 10.6. */
-void
+static void
 ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
              struct stream *s, struct ospf_interface *oi, u_int16_t size)
 {
@@ -1020,7 +1106,7 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
 
   dd = (struct ospf_db_desc *) STREAM_PNT (s);
 
-  nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src);
+  nbr = ospf_nbr_lookup (oi, iph, ospfh);
   if (nbr == NULL)
     {
       zlog_warn ("Packet[DD]: Unknown Neighbor %s",
@@ -1029,13 +1115,15 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
     }
 
   /* Check MTU. */
-  if (ntohs (dd->mtu) > oi->ifp->mtu)
+  if ((OSPF_IF_PARAM (oi, mtu_ignore) == 0) && 
+      (ntohs (dd->mtu) > oi->ifp->mtu))
     {
-      zlog_warn ("Packet[DD]: MTU is larger than [%s]'s MTU", IF_NAME (oi));
+      zlog_warn ("Packet[DD]: Neighbor %s MTU %u is larger than [%s]'s MTU %u",
+                inet_ntoa (nbr->router_id), ntohs (dd->mtu),
+                IF_NAME (oi), oi->ifp->mtu);
       return;
     }
 
-#ifdef HAVE_NSSA
   /* 
    * XXX HACK by Hasso Tepper. Setting N/P bit in NSSA area DD packets is not
    * required. In fact at least JunOS sends DD packets with P bit clear. 
@@ -1054,11 +1142,10 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
        && (!CHECK_FLAG (dd->options, OSPF_OPTION_NP)) )
     {
       if (IS_DEBUG_OSPF_EVENT) 
-        zlog_notice ("Packet[DD]: Neighbour %s: Has NSSA capability, sends with N bit clear in DD options",
+        zlog_debug ("Packet[DD]: Neighbour %s: Has NSSA capability, sends with N bit clear in DD options",
                     inet_ntoa (nbr->router_id) );
       SET_FLAG (dd->options, OSPF_OPTION_NP);
     }
-#endif /* HAVE_NSSA */
 
 #ifdef REJECT_IF_TBIT_ON
   if (CHECK_FLAG (dd->options, OSPF_OPTION_T))
@@ -1090,7 +1177,8 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
     case NSM_Down:
     case NSM_Attempt:
     case NSM_TwoWay:
-      zlog_warn ("Packet[DD]: Neighbor state is %s, packet discarded.",
+      zlog_warn ("Packet[DD]: Neighbor %s state is %s, packet discarded.",
+                inet_ntoa(nbr->router_id),
                 LOOKUP (ospf_nsm_state_msg, nbr->state));
       break;
     case NSM_Init:
@@ -1108,14 +1196,16 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
          if (IPV4_ADDR_CMP (&nbr->router_id, &oi->ospf->router_id) > 0)
            {
              /* We're Slave---obey */
-             zlog_warn ("Packet[DD]: Negotiation done (Slave).");
+             zlog_info ("Packet[DD]: Neighbor %s Negotiation done (Slave).",
+                        inet_ntoa(nbr->router_id));
              nbr->dd_seqnum = ntohl (dd->dd_seqnum);
              nbr->dd_flags &= ~(OSPF_DD_FLAG_MS|OSPF_DD_FLAG_I); /* Reset I/MS */
            }
          else
            {
              /* We're Master, ignore the initial DBD from Slave */
-             zlog_warn ("Packet[DD]: Initial DBD from Slave, ignoring.");
+             zlog_info ("Packet[DD]: Neighbor %s: Initial DBD from Slave, "
+                        "ignoring.", inet_ntoa(nbr->router_id));
              break;
            }
        }
@@ -1124,12 +1214,14 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
               ntohl (dd->dd_seqnum) == nbr->dd_seqnum &&
               IPV4_ADDR_CMP (&nbr->router_id, &oi->ospf->router_id) < 0)
        {
-         zlog_warn ("Packet[DD]: Negotiation done (Master).");
+         zlog_info ("Packet[DD]: Neighbor %s Negotiation done (Master).",
+                    inet_ntoa(nbr->router_id));
          nbr->dd_flags &= ~OSPF_DD_FLAG_I;
        }
       else
        {
-         zlog_warn ("Packet[DD]: Negotiation fails.");
+         zlog_warn ("Packet[DD]: Neighbor %s Negotiation fails.",
+                    inet_ntoa(nbr->router_id));
          break;
        }
       
@@ -1140,14 +1232,17 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
       if (CHECK_FLAG (oi->ospf->config, OSPF_OPAQUE_CAPABLE))
         {
           if (IS_DEBUG_OSPF_EVENT)
-            zlog_info ("Neighbor[%s] is %sOpaque-capable.",
+            zlog_debug ("Neighbor[%s] is %sOpaque-capable.",
                       inet_ntoa (nbr->router_id),
                       CHECK_FLAG (nbr->options, OSPF_OPTION_O) ? "" : "NOT ");
 
           if (! CHECK_FLAG (nbr->options, OSPF_OPTION_O)
           &&  IPV4_ADDR_SAME (&DR (oi), &nbr->address.u.prefix4))
             {
-              zlog_warn ("DR-neighbor[%s] is NOT opaque-capable; Opaque-LSAs cannot be reliably advertised in this network.", inet_ntoa (nbr->router_id));
+              zlog_warn ("DR-neighbor[%s] is NOT opaque-capable; "
+                         "Opaque-LSAs cannot be reliably advertised "
+                         "in this network.",
+                         inet_ntoa (nbr->router_id));
               /* This situation is undesirable, but not a real error. */
             }
         }
@@ -1163,11 +1258,13 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
        {
          if (IS_SET_DD_MS (nbr->dd_flags))
            /* Master: discard duplicated DD packet. */
-           zlog_warn ("Packet[DD] (Master): packet duplicated.");
+           zlog_info ("Packet[DD] (Master): Neighbor %s packet duplicated.",
+                      inet_ntoa (nbr->router_id));
          else
            /* Slave: cause to retransmit the last Database Description. */
            {
-             zlog_warn ("Packet[DD] [Slave]: packet duplicated.");
+             zlog_info ("Packet[DD] [Slave]: Neighbor %s packet duplicated.",
+                        inet_ntoa (nbr->router_id));
              ospf_db_desc_resend (nbr);
            }
          break;
@@ -1177,18 +1274,20 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
       /* Check Master/Slave bit mismatch */
       if (IS_SET_DD_MS (dd->flags) != IS_SET_DD_MS (nbr->last_recv.flags))
        {
-         zlog_warn ("Packet[DD]: MS-bit mismatch.");
+         zlog_warn ("Packet[DD]: Neighbor %s MS-bit mismatch.",
+                    inet_ntoa(nbr->router_id));
          OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
          if (IS_DEBUG_OSPF_EVENT)
-           zlog_info ("Packet[DD]: dd->flags=%d, nbr->dd_flags=%d",
-                      dd->flags, nbr->dd_flags);
+           zlog_debug ("Packet[DD]: dd->flags=%d, nbr->dd_flags=%d",
+                       dd->flags, nbr->dd_flags);
          break;
        }
 
       /* Check initialize bit is set. */
       if (IS_SET_DD_I (dd->flags))
        {
-         zlog_warn ("Packet[DD]: I-bit set.");
+         zlog_info ("Packet[DD]: Neighbor %s I-bit set.",
+                    inet_ntoa(nbr->router_id));
          OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
          break;
        }
@@ -1200,7 +1299,8 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
          /* Save the new options for debugging */
          nbr->options = dd->options;
 #endif /* ORIGINAL_CODING */
-         zlog_warn ("Packet[DD]: options mismatch.");
+         zlog_warn ("Packet[DD]: Neighbor %s options mismatch.",
+                    inet_ntoa(nbr->router_id));
          OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
          break;
        }
@@ -1211,7 +1311,8 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
          (!IS_SET_DD_MS (nbr->dd_flags) &&
           ntohl (dd->dd_seqnum) != nbr->dd_seqnum + 1))
        {
-         zlog_warn ("Pakcet[DD]: sequence number mismatch.");
+         zlog_warn ("Packet[DD]: Neighbor %s sequence number mismatch.",
+                    inet_ntoa(nbr->router_id));
          OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
          break;
        }
@@ -1226,7 +1327,9 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
          if (IS_SET_DD_MS (nbr->dd_flags))
            {
              /* Master should discard duplicate DD packet. */
-             zlog_warn ("Pakcet[DD]: duplicated, packet discarded.");
+             zlog_info ("Packet[DD]: Neighbor %s duplicated, "
+                        "packet discarded.",
+                       inet_ntoa(nbr->router_id));
              break;
            }
          else
@@ -1254,7 +1357,8 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
       OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_SeqNumberMismatch);
       break;
     default:
-      zlog_warn ("Packet[DD]: NSM illegal status.");
+      zlog_warn ("Packet[DD]: Neighbor %s NSM illegal status %u.",
+                inet_ntoa(nbr->router_id), nbr->state);
       break;
     }
 }
@@ -1262,7 +1366,7 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
 #define OSPF_LSA_KEY_SIZE       12 /* type(4) + id(4) + ar(4) */
 
 /* OSPF Link State Request Read -- RFC2328 Section 10.7. */
-void
+static void
 ospf_ls_req (struct ip *iph, struct ospf_header *ospfh,
             struct stream *s, struct ospf_interface *oi, u_int16_t size)
 {
@@ -1271,13 +1375,13 @@ ospf_ls_req (struct ip *iph, struct ospf_header *ospfh,
   struct in_addr ls_id;
   struct in_addr adv_router;
   struct ospf_lsa *find;
-  list ls_upd;
-  int length;
+  struct list *ls_upd;
+  unsigned int length;
 
   /* Increment statistics. */
   oi->ls_req_in++;
 
-  nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src);
+  nbr = ospf_nbr_lookup (oi, iph, ospfh);
   if (nbr == NULL)
     {
       zlog_warn ("Link State Request: Unknown Neighbor %s.",
@@ -1290,7 +1394,9 @@ ospf_ls_req (struct ip *iph, struct ospf_header *ospfh,
       nbr->state != NSM_Loading &&
       nbr->state != NSM_Full)
     {
-      zlog_warn ("Link State Request: Neighbor state is %s, packet discarded.",
+      zlog_warn ("Link State Request received from %s: "
+                "Neighbor state is %s, packet discarded.",
+                inet_ntoa (ospfh->router_id),
                 LOOKUP (ospf_nsm_state_msg, nbr->state));
       return;
     }
@@ -1323,8 +1429,8 @@ ospf_ls_req (struct ip *iph, struct ospf_header *ospfh,
          return;
        }
 
-      /* Packet overflows MTU size, send immediatly. */
-      if (length + ntohs (find->data->length) > OSPF_PACKET_MAX (oi))
+      /* Packet overflows MTU size, send immediately. */
+      if (length + ntohs (find->data->length) > ospf_packet_max (oi))
        {
          if (oi->type == OSPF_IFTYPE_NBMA)
            ospf_ls_upd_send (nbr, ls_upd, OSPF_SEND_PACKET_DIRECT);
@@ -1360,7 +1466,7 @@ ospf_ls_req (struct ip *iph, struct ospf_header *ospfh,
 
 /* Get the list of LSAs from Link State Update packet.
    And process some validation -- RFC2328 Section 13. (1)-(2). */
-static list
+static struct list *
 ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s,
                       struct ospf_interface *oi, size_t size)
 {
@@ -1368,7 +1474,7 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s,
   u_int32_t length;
   struct lsa_header *lsah;
   struct ospf_lsa *lsa;
-  list lsas;
+  struct list *lsas;
 
   lsas = list_new ();
 
@@ -1376,7 +1482,7 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s,
   size -= OSPF_LS_UPD_MIN_SIZE; /* # LSAs */
 
   for (; size >= OSPF_LSA_HEADER_SIZE && count > 0;
-       size -= length, stream_forward (s, length), count--)
+       size -= length, stream_forward_getp (s, length), count--)
     {
       lsah = (struct lsa_header *) STREAM_PNT (s);
       length = ntohs (lsah->length);
@@ -1433,7 +1539,7 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s,
              && nbr->oi->area->external_routing != OSPF_AREA_DEFAULT) 
             {
               if (IS_DEBUG_OSPF_EVENT)
-                zlog_info ("LSA[Type%d:%s]: We are a stub, don't take this LSA.", lsah->type, inet_ntoa (lsah->id));
+                zlog_debug ("LSA[Type%d:%s]: We are a stub, don't take this LSA.", lsah->type, inet_ntoa (lsah->id));
               continue;
             }
         }
@@ -1469,7 +1575,7 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s,
       memcpy (lsa->data, lsah, length);
 
       if (IS_DEBUG_OSPF_EVENT)
-       zlog_info("LSA[Type%d:%s]: %p new LSA created with Link State Update",
+       zlog_debug("LSA[Type%d:%s]: %p new LSA created with Link State Update",
                  lsa->data->type, inet_ntoa (lsa->data->id), lsa);
       listnode_add (lsas, lsa);
     }
@@ -1478,30 +1584,26 @@ ospf_ls_upd_list_lsa (struct ospf_neighbor *nbr, struct stream *s,
 }
 
 /* Cleanup Update list. */
-void
-ospf_upd_list_clean (list lsas)
+static void
+ospf_upd_list_clean (struct list *lsas)
 {
-  listnode node;
+  struct listnode *node, *nnode;
   struct ospf_lsa *lsa;
 
-  for (node = listhead (lsas); node; nextnode (node))
-    if ((lsa = getdata (node)) != NULL)
-      ospf_lsa_discard (lsa);
+  for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa))
+    ospf_lsa_discard (lsa);
 
   list_delete (lsas);
 }
 
 /* OSPF Link State Update message read -- RFC2328 Section 13. */
-void
+static void
 ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
             struct stream *s, struct ospf_interface *oi, u_int16_t size)
 {
   struct ospf_neighbor *nbr;
-  list lsas;
-#ifdef HAVE_OPAQUE_LSA
-  list mylsa_acks, mylsa_upds;
-#endif /* HAVE_OPAQUE_LSA */
-  listnode node, next;
+  struct list *lsas;
+  struct listnode *node, *nnode;
   struct ospf_lsa *lsa = NULL;
   /* unsigned long ls_req_found = 0; */
 
@@ -1511,7 +1613,7 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
   oi->ls_upd_in++;
 
   /* Check neighbor. */
-  nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src);
+  nbr = ospf_nbr_lookup (oi, iph, ospfh);
   if (nbr == NULL)
     {
       zlog_warn ("Link State Update: Unknown Neighbor %s on int: %s",
@@ -1522,8 +1624,10 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
   /* Check neighbor state. */
   if (nbr->state < NSM_Exchange)
     {
-      zlog_warn ("Link State Update: Neighbor[%s] state is less than Exchange",
-                inet_ntoa (ospfh->router_id));
+      zlog_warn ("Link State Update: "
+                "Neighbor[%s] state %s is less than Exchange",
+                inet_ntoa (ospfh->router_id),
+                LOOKUP(ospf_nsm_state_msg, nbr->state));
       return;
     }
 
@@ -1534,13 +1638,6 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
   lsas = ospf_ls_upd_list_lsa (nbr, s, oi, size);
 
 #ifdef HAVE_OPAQUE_LSA
-  /*
-   * Prepare two kinds of lists to clean up unwanted self-originated
-   * Opaque-LSAs from the routing domain as soon as possible.
-   */
-  mylsa_acks = list_new (); /* Let the sender cease retransmission. */
-  mylsa_upds = list_new (); /* Flush target LSAs if necessary. */
-
   /*
    * If self-originated Opaque-LSAs that have flooded before restart
    * are contained in the received LSUpd message, corresponding LSReq
@@ -1549,33 +1646,31 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
    * updating for the same LSA would take place alternately, this trick
    * must be done before entering to the loop below.
    */
+   /* XXX: Why is this Opaque specific? Either our core code is deficient
+    * and this should be fixed generally, or Opaque is inventing strawman
+    * problems */
    ospf_opaque_adjust_lsreq (nbr, lsas);
 #endif /* HAVE_OPAQUE_LSA */
 
 #define DISCARD_LSA(L,N) {\
         if (IS_DEBUG_OSPF_EVENT) \
-          zlog_info ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p Type-%d", N, lsa, (int) lsa->data->type); \
+          zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point %d: lsa %p Type-%d", N, lsa, (int) lsa->data->type); \
         ospf_lsa_discard (L); \
        continue; }
 
   /* Process each LSA received in the one packet. */
-  for (node = listhead (lsas); node; node = next)
+  for (ALL_LIST_ELEMENTS (lsas, node, nnode, lsa))
     {
       struct ospf_lsa *ls_ret, *current;
       int ret = 1;
 
-      next = node->next;
-
-      lsa = getdata (node);
-
-#ifdef HAVE_NSSA
       if (IS_DEBUG_OSPF_NSSA)
        {
          char buf1[INET_ADDRSTRLEN];
          char buf2[INET_ADDRSTRLEN];
          char buf3[INET_ADDRSTRLEN];
 
-         zlog_info("LSA Type-%d from %s, ID: %s, ADV: %s",
+         zlog_debug("LSA Type-%d from %s, ID: %s, ADV: %s",
                  lsa->data->type,
                  inet_ntop (AF_INET, &ospfh->router_id,
                             buf1, INET_ADDRSTRLEN),
@@ -1584,7 +1679,6 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
                  inet_ntop (AF_INET, &lsa->data->adv_router,
                             buf3, INET_ADDRSTRLEN));
        }
-#endif /* HAVE_NSSA */
 
       listnode_delete (lsas, lsa); /* We don't need it in list anymore */
 
@@ -1608,21 +1702,17 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
         if (nbr->oi->area->external_routing != OSPF_AREA_DEFAULT) 
          {
            DISCARD_LSA (lsa, 1);
-#ifdef HAVE_NSSA
            if (IS_DEBUG_OSPF_NSSA)
-             zlog_info("Incoming External LSA Discarded: We are NSSA/STUB Area");
-#endif /* HAVE_NSSA */
+             zlog_debug("Incoming External LSA Discarded: We are NSSA/STUB Area");
          }
 
-#ifdef  HAVE_NSSA 
       if (lsa->data->type == OSPF_AS_NSSA_LSA)
        if (nbr->oi->area->external_routing != OSPF_AREA_NSSA)
          {
            DISCARD_LSA (lsa,2);
            if (IS_DEBUG_OSPF_NSSA)
-             zlog_info("Incoming NSSA LSA Discarded:  Not NSSA Area");
+             zlog_debug("Incoming NSSA LSA Discarded:  Not NSSA Area");
          }
-#endif /* HAVE_NSSA */
 
       /* Find the LSA in the current database. */
 
@@ -1641,7 +1731,8 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
          ospf_ls_ack_send (nbr, lsa);
 
          /* Discard LSA. */      
-         zlog_warn ("Link State Update: LS age is equal to MaxAge.");
+         zlog_info ("Link State Update[%s]: LS age is equal to MaxAge.",
+                    dump_lsa_key(lsa));
           DISCARD_LSA (lsa, 3);
        }
 
@@ -1678,19 +1769,60 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
            * Otherwise, the LSA instance remains in the routing domain
            * until its age reaches to MaxAge.
            */
+          /* XXX: We should deal with this for *ALL* LSAs, not just opaque */
           if (current == NULL)
             {
               if (IS_DEBUG_OSPF_EVENT)
-                zlog_info ("LSA[%s]: Previously originated Opaque-LSA, not found in the LSDB.", dump_lsa_key (lsa));
+                zlog_debug ("LSA[%s]: Previously originated Opaque-LSA,"
+                            "not found in the LSDB.", dump_lsa_key (lsa));
 
               SET_FLAG (lsa->flags, OSPF_LSA_SELF);
-              listnode_add (mylsa_upds, ospf_lsa_dup  (lsa));
-              listnode_add (mylsa_acks, ospf_lsa_lock (lsa));
+              
+              ospf_opaque_self_originated_lsa_received (nbr, lsa);
+              ospf_ls_ack_send (nbr, lsa);
+              
               continue;
             }
         }
 #endif /* HAVE_OPAQUE_LSA */
 
+      /* It might be happen that received LSA is self-originated network LSA, but
+       * router ID is cahnged. So, we should check if LSA is a network-LSA whose
+       * Link State ID is one of the router's own IP interface addresses but whose
+       * Advertising Router is not equal to the router's own Router ID
+       * According to RFC 2328 12.4.2 and 13.4 this LSA should be flushed.
+       */
+
+      if(lsa->data->type == OSPF_NETWORK_LSA)
+      {
+        struct listnode *oinode, *oinnode;
+        struct ospf_interface *out_if;
+        int Flag = 0;
+
+        for (ALL_LIST_ELEMENTS (oi->ospf->oiflist, oinode, oinnode, out_if))
+        {
+          if(out_if == NULL)
+            break;
+
+          if((IPV4_ADDR_SAME(&out_if->address->u.prefix4, &lsa->data->id)) &&
+              (!(IPV4_ADDR_SAME(&oi->ospf->router_id, &lsa->data->adv_router))))
+          {
+            if(out_if->network_lsa_self)
+            {
+              ospf_lsa_flush_area(lsa,out_if->area);
+              if(IS_DEBUG_OSPF_EVENT)
+                zlog_debug ("ospf_lsa_discard() in ospf_ls_upd() point 9: lsa %p Type-%d",
+                            lsa, (int) lsa->data->type);
+              ospf_lsa_discard (lsa);
+              Flag = 1;
+            }
+            break;
+          }
+        }
+        if(Flag)
+          continue;
+      }
+
       /* (5) Find the instance of this LSA that is currently contained
         in the router's link state database.  If there is no
         database copy, or the received LSA is more recent than
@@ -1715,16 +1847,13 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
       if (ospf_ls_request_lookup (nbr, lsa))
        {
          OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_BadLSReq);
-         zlog_warn ("LSA instance exists on Link state request list");
+         zlog_warn("LSA[%s] instance exists on Link state request list",
+                   dump_lsa_key(lsa));
 
          /* Clean list of LSAs. */
           ospf_upd_list_clean (lsas);
          /* this lsa is not on lsas list already. */
          ospf_lsa_discard (lsa);
-#ifdef HAVE_OPAQUE_LSA
-          list_delete (mylsa_acks);
-          list_delete (mylsa_upds);
-#endif /* HAVE_OPAQUE_LSA */
          return;
        }
 
@@ -1802,41 +1931,21 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
        }
     }
   
-#ifdef HAVE_OPAQUE_LSA
-  /*
-   * Now that previously originated Opaque-LSAs those which not yet
-   * installed into LSDB are captured, take several steps to clear
-   * them completely from the routing domain, before proceeding to
-   * origination for the current target Opaque-LSAs.
-   */
-  while (listcount (mylsa_acks) > 0)
-    ospf_ls_ack_send_list (oi, mylsa_acks, nbr->address.u.prefix4);
-
-  if (listcount (mylsa_upds) > 0)
-    ospf_opaque_self_originated_lsa_received (nbr, mylsa_upds);
-
-  list_delete (mylsa_upds);
-  list_delete (mylsa_acks);
-#endif /* HAVE_OPAQUE_LSA */
-
   assert (listcount (lsas) == 0);
   list_delete (lsas);
 }
 
 /* OSPF Link State Acknowledgment message read -- RFC2328 Section 13.7. */
-void
+static void
 ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh,
             struct stream *s, struct ospf_interface *oi, u_int16_t size)
 {
   struct ospf_neighbor *nbr;
-#ifdef HAVE_OPAQUE_LSA
-  list opaque_acks;
-#endif /* HAVE_OPAQUE_LSA */
-
+  
   /* increment statistics. */
   oi->ls_ack_in++;
 
-  nbr = ospf_nbr_lookup_by_addr (oi->nbrs, &iph->ip_src);
+  nbr = ospf_nbr_lookup (oi, iph, ospfh);
   if (nbr == NULL)
     {
       zlog_warn ("Link State Acknowledgment: Unknown Neighbor %s.",
@@ -1846,14 +1955,13 @@ ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh,
 
   if (nbr->state < NSM_Exchange)
     {
-      zlog_warn ("Link State Acknowledgment: State is less than Exchange.");
+      zlog_warn ("Link State Acknowledgment: "
+                "Neighbor[%s] state %s is less than Exchange",
+                inet_ntoa (ospfh->router_id),
+                LOOKUP(ospf_nsm_state_msg, nbr->state));
       return;
     }
-
-#ifdef HAVE_OPAQUE_LSA
-  opaque_acks = list_new ();
-#endif /* HAVE_OPAQUE_LSA */
-
+  
   while (size >= OSPF_LSA_HEADER_SIZE)
     {
       struct ospf_lsa *lsa, *lsr;
@@ -1863,7 +1971,7 @@ ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh,
 
       /* lsah = (struct lsa_header *) STREAM_PNT (s); */
       size -= OSPF_LSA_HEADER_SIZE;
-      stream_forward (s, OSPF_LSA_HEADER_SIZE);
+      stream_forward_getp (s, OSPF_LSA_HEADER_SIZE);
 
       if (lsa->data->type < OSPF_MIN_LSA || lsa->data->type >= OSPF_MAX_LSA)
        {
@@ -1877,9 +1985,8 @@ ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh,
       if (lsr != NULL && lsr->data->ls_seqnum == lsa->data->ls_seqnum)
         {
 #ifdef HAVE_OPAQUE_LSA
-          /* Keep this LSA entry for later reference. */
           if (IS_OPAQUE_LSA (lsr->data->type))
-            listnode_add (opaque_acks, ospf_lsa_dup (lsr));
+            ospf_opaque_ls_ack_received (nbr, lsr);
 #endif /* HAVE_OPAQUE_LSA */
 
           ospf_ls_retransmit_delete (nbr, lsr);
@@ -1889,51 +1996,49 @@ ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh,
       ospf_lsa_discard (lsa);
     }
 
-#ifdef HAVE_OPAQUE_LSA
-  if (listcount (opaque_acks) > 0)
-    ospf_opaque_ls_ack_received (nbr, opaque_acks);
-
-  list_delete (opaque_acks);
   return;
-#endif /* HAVE_OPAQUE_LSA */
 }
 \f
-struct stream *
-ospf_recv_packet (int fd, struct interface **ifp)
+static struct stream *
+ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf)
 {
   int ret;
-  struct ip iph;
+  struct ip *iph;
   u_int16_t ip_len;
-  struct stream *ibuf;
   unsigned int ifindex = 0;
   struct iovec iov;
-  struct cmsghdr *cmsg;
-#if defined (IP_PKTINFO)
-  struct in_pktinfo *pktinfo;
-#elif defined (IP_RECVIF)
-  struct sockaddr_dl *pktinfo;
-#else
-  char *pktinfo; /* dummy */
-#endif
-  char buff [sizeof (*cmsg) + sizeof (*pktinfo)];
-  struct msghdr msgh = {NULL, 0, &iov, 1, buff,
-                       sizeof (*cmsg) + sizeof (*pktinfo), 0};
-    
-  ret = recvfrom (fd, (void *)&iph, sizeof (iph), MSG_PEEK, NULL, 0);
+  /* Header and data both require alignment. */
+  char buff [CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())];
+  struct msghdr msgh;
+
+  memset (&msgh, 0, sizeof (struct msghdr));
+  msgh.msg_iov = &iov;
+  msgh.msg_iovlen = 1;
+  msgh.msg_control = (caddr_t) buff;
+  msgh.msg_controllen = sizeof (buff);
   
-  if (ret != sizeof (iph))
+  ret = stream_recvmsg (ibuf, fd, &msgh, 0, OSPF_MAX_PACKET_SIZE+1);
+  if (ret < 0)
     {
-      zlog_warn ("ospf_recv_packet packet smaller than ip header");
+      zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno));
       return NULL;
     }
-
-#if defined(__NetBSD__) || defined(__FreeBSD__) || defined(__OpenBSD__)
-  ip_len = iph.ip_len;
-#else
-  ip_len = ntohs (iph.ip_len);
-#endif
-
-#if !defined(GNU_LINUX)
+  if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */
+    {
+      zlog_warn("ospf_recv_packet: discarding runt packet of length %d "
+               "(ip header size is %u)",
+               ret, (u_int)sizeof(iph));
+      return NULL;
+    }
+  
+  /* Note that there should not be alignment problems with this assignment
+     because this is at the beginning of the stream data buffer. */
+  iph = (struct ip *) STREAM_DATA(ibuf);
+  sockopt_iphdrincl_swab_systoh (iph);
+  
+  ip_len = iph->ip_len;
+  
+#if !defined(GNU_LINUX) && (OpenBSD < 200311)
   /*
    * Kernel network code touches incoming IP header parameters,
    * before protocol specific processing.
@@ -1948,77 +2053,47 @@ ospf_recv_packet (int fd, struct interface **ifp)
    *
    * For more details, see <netinet/ip_input.c>.
    */
-  ip_len = ip_len + (iph.ip_hl << 2);
+  ip_len = ip_len + (iph->ip_hl << 2);
 #endif
   
-  ibuf = stream_new (ip_len);
-  iov.iov_base = STREAM_DATA (ibuf);
-  iov.iov_len = ip_len;
-  ret = recvmsg (fd, &msgh, 0);
-  
-  cmsg = CMSG_FIRSTHDR (&msgh);
-  
-  if (cmsg != NULL && //cmsg->cmsg_len == sizeof (*pktinfo) &&
-      cmsg->cmsg_level == IPPROTO_IP &&
-#if defined (IP_PKTINFO)
-      cmsg->cmsg_type == IP_PKTINFO
-#elif defined (IP_RECVIF)
-      cmsg->cmsg_type == IP_RECVIF
-#else
-      0
-#endif
-      )
-    {
-#if defined (IP_PKTINFO)
-      pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
-      ifindex = pktinfo->ipi_ifindex;
-#elif defined (IP_RECVIF)
-      pktinfo = (struct sockaddr_dl *)CMSG_DATA(cmsg);
-      ifindex = pktinfo->sdl_index;
-#else
-      ifindex = 0;
-#endif
-    }
+  ifindex = getsockopt_ifindex (AF_INET, &msgh);
   
   *ifp = if_lookup_by_index (ifindex);
 
   if (ret != ip_len)
     {
-      zlog_warn ("ospf_recv_packet short read. "
-                "ip_len %d bytes read %d", ip_len, ret);
-      stream_free (ibuf);
+      zlog_warn ("ospf_recv_packet read length mismatch: ip_len is %d, "
+                        "but recvmsg returned %d", ip_len, ret);
       return NULL;
     }
   
   return ibuf;
 }
 
-struct ospf_interface *
-ospf_associate_packet_vl (struct ospf *ospf,
-                         struct interface *ifp, struct ospf_interface *oi,
+static struct ospf_interface *
+ospf_associate_packet_vl (struct ospf *ospf, struct interface *ifp, 
                          struct ip *iph, struct ospf_header *ospfh)
 {
   struct ospf_interface *rcv_oi;
   struct ospf_vl_data *vl_data;
   struct ospf_area *vl_area;
-  listnode node;
+  struct listnode *node;
 
   if (IN_MULTICAST (ntohl (iph->ip_dst.s_addr)) ||
       !OSPF_IS_AREA_BACKBONE (ospfh))
-    return oi;
+    return NULL;
 
-  if ((rcv_oi = oi) == NULL)
-    {
-     if ((rcv_oi = ospf_if_lookup_by_local_addr (ospf, ifp,
-                                                iph->ip_dst)) == NULL)
-       return NULL;
-    }
+  /* look for local OSPF interface matching the destination
+   * to determine Area ID. We presume therefore the destination address
+   * is unique, or at least (for "unnumbered" links), not used in other 
+   * areas
+   */
+  if ((rcv_oi = ospf_if_lookup_by_local_addr (ospf, NULL, 
+                                              iph->ip_dst)) == NULL)
+    return NULL;
 
-  for (node = listhead (ospf->vlinks); node; nextnode (node))
+  for (ALL_LIST_ELEMENTS_RO (ospf->vlinks, node, vl_data))
     {
-      if ((vl_data = getdata (node)) == NULL)
-       continue;
-      
       vl_area = ospf_area_lookup_by_area_id (ospf, vl_data->vl_area_id);
       if (!vl_area)
        continue;
@@ -2027,12 +2102,12 @@ ospf_associate_packet_vl (struct ospf *ospf,
          IPV4_ADDR_SAME (&vl_data->vl_peer, &ospfh->router_id))
        {
          if (IS_DEBUG_OSPF_EVENT)
-           zlog_info ("associating packet with %s",
+           zlog_debug ("associating packet with %s",
                       IF_NAME (vl_data->vl_oi));
          if (! CHECK_FLAG (vl_data->vl_oi->ifp->flags, IFF_UP))
            {
              if (IS_DEBUG_OSPF_EVENT)
-               zlog_info ("This VL is not up yet, sorry");
+               zlog_debug ("This VL is not up yet, sorry");
              return NULL;
            }
          
@@ -2041,12 +2116,12 @@ ospf_associate_packet_vl (struct ospf *ospf,
     }
 
   if (IS_DEBUG_OSPF_EVENT)
-    zlog_info ("couldn't find any VL to associate the packet with");
+    zlog_debug ("couldn't find any VL to associate the packet with");
   
-  return oi;
+  return NULL;
 }
 
-int
+static inline int
 ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh)
 {
   /* Check match the Area ID of the receiving interface. */
@@ -2059,7 +2134,7 @@ ospf_check_area_id (struct ospf_interface *oi, struct ospf_header *ospfh)
 /* Unbound socket will accept any Raw IP packets if proto is matched.
    To prevent it, compare src IP address and i/f address with masking
    i/f network mask. */
-int
+static int
 ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src)
 {
   struct in_addr mask, me, him;
@@ -2079,7 +2154,7 @@ ospf_check_network_mask (struct ospf_interface *oi, struct in_addr ip_src)
  return 0;
 }
 
-int
+static int
 ospf_check_auth (struct ospf_interface *oi, struct stream *ibuf,
                 struct ospf_header *ospfh)
 {
@@ -2098,7 +2173,7 @@ ospf_check_auth (struct ospf_interface *oi, struct stream *ibuf,
        ret = 0;
       break;
     case OSPF_AUTH_CRYPTOGRAPHIC:
-      if ((ck = getdata (OSPF_IF_PARAM (oi,auth_crypt)->tail)) == NULL)
+      if ((ck = listgetdata (listtail(OSPF_IF_PARAM (oi,auth_crypt)))) == NULL)
        {
          ret = 0;
          break;
@@ -2120,12 +2195,11 @@ ospf_check_auth (struct ospf_interface *oi, struct stream *ibuf,
   return ret;
 }
 
-int
+static int
 ospf_check_sum (struct ospf_header *ospfh)
 {
   u_int32_t ret;
   u_int16_t sum;
-  int in_cksum (void *ptr, int nbytes);
 
   /* clear auth_data for checksum. */
   memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
@@ -2148,7 +2222,7 @@ ospf_check_sum (struct ospf_header *ospfh)
 }
 
 /* OSPF Header verification. */
-int
+static int
 ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi,
                    struct ip *iph, struct ospf_header *ospfh)
 {
@@ -2179,8 +2253,8 @@ ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi,
   /* Check authentication. */
   if (ospf_auth_type (oi) != ntohs (ospfh->auth_type))
     {
-      zlog_warn ("interface %s: ospf_read authentication type mismatch.",
-                IF_NAME (oi));
+      zlog_warn ("interface %s: auth-type mismatch, local %d, rcvd %d",
+                IF_NAME (oi), ospf_auth_type (oi), ntohs (ospfh->auth_type));
       return -1;
     }
 
@@ -2231,48 +2305,95 @@ ospf_read (struct thread *thread)
 
   /* first of all get interface pointer. */
   ospf = THREAD_ARG (thread);
-  ospf->t_read = NULL;
+
+  /* prepare for next packet. */
+  ospf->t_read = thread_add_read (master, ospf_read, ospf, ospf->fd);
 
   /* read OSPF packet. */
-  ibuf = ospf_recv_packet (ospf->fd, &ifp);
-  if (ibuf == NULL)
+  stream_reset(ospf->ibuf);
+  if (!(ibuf = ospf_recv_packet (ospf->fd, &ifp, ospf->ibuf)))
     return -1;
   
+  /* Note that there should not be alignment problems with this assignment
+     because this is at the beginning of the stream data buffer. */
   iph = (struct ip *) STREAM_DATA (ibuf);
+  /* Note that sockopt_iphdrincl_swab_systoh was called in ospf_recv_packet. */
 
-  /* prepare for next packet. */
-  ospf->t_read = thread_add_read (master, ospf_read, ospf, ospf->fd);
+  if (ifp == NULL)
+    /* Handle cases where the platform does not support retrieving the ifindex,
+       and also platforms (such as Solaris 8) that claim to support ifindex
+       retrieval but do not. */
+    ifp = if_lookup_address (iph->ip_src);
+  
+  if (ifp == NULL)
+    return 0;
 
   /* IP Header dump. */
     if (IS_DEBUG_OSPF_PACKET(0, RECV))
-           ospf_ip_header_dump (ibuf);
+           ospf_ip_header_dump (iph);
 
   /* Self-originated packet should be discarded silently. */
   if (ospf_if_lookup_by_local_addr (ospf, NULL, iph->ip_src))
     {
-      stream_free (ibuf);
+      if (IS_DEBUG_OSPF_PACKET (0, RECV))
+        {
+          zlog_debug ("ospf_read[%s]: Dropping self-originated packet",
+                     inet_ntoa (iph->ip_src));
+        }
       return 0;
     }
 
   /* Adjust size to message length. */
-  stream_forward (ibuf, iph->ip_hl * 4);
+  stream_forward_getp (ibuf, iph->ip_hl * 4);
   
   /* Get ospf packet header. */
   ospfh = (struct ospf_header *) STREAM_PNT (ibuf);
 
   /* associate packet with ospf interface */
   oi = ospf_if_lookup_recv_if (ospf, iph->ip_src);
-  if (ifp && oi && oi->ifp != ifp)
+
+  /* if no local ospf_interface, 
+   * or header area is backbone but ospf_interface is not
+   * check for VLINK interface
+   */
+  if ( (oi == NULL) ||
+      (OSPF_IS_AREA_ID_BACKBONE(ospfh->area_id)
+      && !OSPF_IS_AREA_ID_BACKBONE(oi->area->area_id))
+     )
+    {
+      if ((oi = ospf_associate_packet_vl (ospf, ifp, iph, ospfh)) == NULL)
+        {
+          zlog_debug ("Packet from [%s] received on link %s"
+                     " but no ospf_interface",
+                     inet_ntoa (iph->ip_src), ifp->name);
+          return 0;
+        }
+    }
+    
+  /* else it must be a local ospf interface, check it was received on 
+   * correct link 
+   */
+  else if (oi->ifp != ifp)
     {
       zlog_warn ("Packet from [%s] received on wrong link %s",
-                inet_ntoa (iph->ip_src), ifp->name); 
-      stream_free (ibuf);
+                 inet_ntoa (iph->ip_src), ifp->name); 
       return 0;
     }
-  
-  if ((oi = ospf_associate_packet_vl (ospf, ifp, oi, iph, ospfh)) == NULL)
-    {
-      stream_free (ibuf);
+  else if (oi->state == ISM_Down)
+    {
+      char buf[2][INET_ADDRSTRLEN];
+      zlog_warn ("Ignoring packet from %s to %s received on interface that is "
+                "down [%s]; interface flags are %s",
+                inet_ntop(AF_INET, &iph->ip_src, buf[0], sizeof(buf[0])),
+                inet_ntop(AF_INET, &iph->ip_dst, buf[1], sizeof(buf[1])),
+                ifp->name, if_flag_dump(ifp->flags));
+      /* Fix multicast memberships? */
+      if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS))
+       SET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
+      else if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS))
+       SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
+      if (oi->multicast_memberships)
+       ospf_if_set_multicast(oi);
       return 0;
     }
 
@@ -2284,10 +2405,12 @@ ospf_read (struct thread *thread)
   if (iph->ip_dst.s_addr == htonl (OSPF_ALLDROUTERS)
   && (oi->state != ISM_DR && oi->state != ISM_Backup))
     {
-      zlog_info ("Packet for AllDRouters from [%s] via [%s] (ISM: %s)",
+      zlog_warn ("Dropping packet for AllDRouters from [%s] via [%s] (ISM: %s)",
                  inet_ntoa (iph->ip_src), IF_NAME (oi),
                  LOOKUP (ospf_ism_state_msg, oi->state));
-      stream_free (ibuf);
+      /* Try to fix multicast membership. */
+      SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
+      ospf_if_set_multicast(oi);
       return 0;
     }
 
@@ -2296,29 +2419,35 @@ ospf_read (struct thread *thread)
     {
       if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL))
         {
-          zlog_info ("-----------------------------------------------------");
+          zlog_debug ("-----------------------------------------------------");
           ospf_packet_dump (ibuf);
         }
 
-      zlog_info ("%s received from [%s] via [%s]",
+      zlog_debug ("%s received from [%s] via [%s]",
                  ospf_packet_type_str[ospfh->type],
                  inet_ntoa (ospfh->router_id), IF_NAME (oi));
-      zlog_info (" src [%s],", inet_ntoa (iph->ip_src));
-      zlog_info (" dst [%s]", inet_ntoa (iph->ip_dst));
+      zlog_debug (" src [%s],", inet_ntoa (iph->ip_src));
+      zlog_debug (" dst [%s]", inet_ntoa (iph->ip_dst));
 
       if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, DETAIL))
-       zlog_info ("-----------------------------------------------------");
+       zlog_debug ("-----------------------------------------------------");
   }
 
   /* Some header verification. */
   ret = ospf_verify_header (ibuf, oi, iph, ospfh);
   if (ret < 0)
     {
-      stream_free (ibuf);
+      if (IS_DEBUG_OSPF_PACKET (ospfh->type - 1, RECV))
+        {
+          zlog_debug ("ospf_read[%s/%s]: Header check failed, "
+                     "dropping.",
+                     ospf_packet_type_str[ospfh->type],
+                     inet_ntoa (iph->ip_src));
+        }
       return ret;
     }
 
-  stream_forward (ibuf, OSPF_HEADER_SIZE);
+  stream_forward_getp (ibuf, OSPF_HEADER_SIZE);
 
   /* Adjust size to message length. */
   length = ntohs (ospfh->length) - OSPF_HEADER_SIZE;
@@ -2348,12 +2477,11 @@ ospf_read (struct thread *thread)
       break;
     }
 
-  stream_free (ibuf);
   return 0;
 }
 
 /* Make OSPF header. */
-void
+static void
 ospf_make_header (int type, struct ospf_interface *oi, struct stream *s)
 {
   struct ospf_header *ospfh;
@@ -2371,11 +2499,11 @@ ospf_make_header (int type, struct ospf_interface *oi, struct stream *s)
 
   memset (ospfh->u.auth_data, 0, OSPF_AUTH_SIMPLE_SIZE);
 
-  ospf_output_forward (s, OSPF_HEADER_SIZE);
+  stream_forward_endp (s, OSPF_HEADER_SIZE);
 }
 
 /* Make Authentication Data. */
-int
+static int
 ospf_make_auth (struct ospf_interface *oi, struct ospf_header *ospfh)
 {
   struct crypt_key *ck;
@@ -2399,7 +2527,7 @@ ospf_make_auth (struct ospf_interface *oi, struct ospf_header *ospfh)
        }
       else
        {
-         ck = getdata (OSPF_IF_PARAM (oi, auth_crypt)->tail);
+         ck = listgetdata (listtail(OSPF_IF_PARAM (oi, auth_crypt)));
          ospfh->u.crypt.zero = 0;
          ospfh->u.crypt.key_id = ck->key_id;
          ospfh->u.crypt.auth_data_len = OSPF_AUTH_MD5_SIZE;
@@ -2415,7 +2543,7 @@ ospf_make_auth (struct ospf_interface *oi, struct ospf_header *ospfh)
 }
 
 /* Fill rest of OSPF header. */
-void
+static void
 ospf_fill_header (struct ospf_interface *oi,
                  struct stream *s, u_int16_t length)
 {
@@ -2436,7 +2564,7 @@ ospf_fill_header (struct ospf_interface *oi,
   ospf_make_auth (oi, ospfh);
 }
 
-int
+static int
 ospf_make_hello (struct ospf_interface *oi, struct stream *s)
 {
   struct ospf_neighbor *nbr;
@@ -2455,10 +2583,13 @@ ospf_make_hello (struct ospf_interface *oi, struct stream *s)
   stream_put_ipv4 (s, mask.s_addr);
 
   /* Set Hello Interval. */
-  stream_putw (s, OSPF_IF_PARAM (oi, v_hello));
+  if (OSPF_IF_PARAM (oi, fast_hello) == 0)
+    stream_putw (s, OSPF_IF_PARAM (oi, v_hello));
+  else
+    stream_putw (s, 0); /* hello-interval of 0 for fast-hellos */
 
   if (IS_DEBUG_OSPF_EVENT)
-    zlog_info ("make_hello: options: %x, int: %s",
+    zlog_debug ("make_hello: options: %x, int: %s",
               OPTIONS(oi), IF_NAME (oi));
 
   /* Set Options. */
@@ -2473,7 +2604,7 @@ ospf_make_hello (struct ospf_interface *oi, struct stream *s)
   /* Set Designated Router. */
   stream_put_ipv4 (s, DR (oi).s_addr);
 
-  p = s->putp;
+  p = stream_get_endp (s);
 
   /* Set Backup Designated Router. */
   stream_put_ipv4 (s, BDR (oi).s_addr);
@@ -2498,15 +2629,12 @@ ospf_make_hello (struct ospf_interface *oi, struct stream *s)
 
   /* Let neighbor generate BackupSeen. */
   if (flag == 1)
-    {
-      stream_set_putp (s, p);
-      stream_put_ipv4 (s, 0);
-    }
+    stream_putl_at (s, p, 0); /* ipv4 address, normally */
 
   return length;
 }
 
-int
+static int
 ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
                   struct stream *s)
 {
@@ -2547,7 +2675,7 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
   stream_putc (s, options);
 
   /* Keep pointer to flags. */
-  pp = stream_get_putp (s);
+  pp = stream_get_endp (s);
   stream_putc (s, nbr->dd_flags);
 
   /* Set DD Sequence Number. */
@@ -2559,8 +2687,7 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
        {
          nbr->dd_flags &= ~OSPF_DD_FLAG_M;
          /* Set DD flags again */
-         stream_set_putp (s, pp);
-         stream_putc (s, nbr->dd_flags);
+         stream_putc_at (s, pp, nbr->dd_flags);
        }
       return length;
     }
@@ -2593,12 +2720,12 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
                u_int16_t ls_age;
                
                /* DD packet overflows interface MTU. */
-               if (length + OSPF_LSA_HEADER_SIZE > OSPF_PACKET_MAX (oi))
+               if (length + OSPF_LSA_HEADER_SIZE > ospf_packet_max (oi))
                  break;
                
                /* Keep pointer to LS age. */
                lsah = (struct lsa_header *) (STREAM_DATA (s) +
-                                             stream_get_putp (s));
+                                             stream_get_endp (s));
                
                /* Proceed stream pointer. */
                stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE);
@@ -2618,7 +2745,7 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
   return length;
 }
 
-int
+static int
 ospf_make_ls_req_func (struct stream *s, u_int16_t *length,
                       unsigned long delta, struct ospf_neighbor *nbr,
                       struct ospf_lsa *lsa)
@@ -2628,7 +2755,7 @@ ospf_make_ls_req_func (struct stream *s, u_int16_t *length,
   oi = nbr->oi;
 
   /* LS Request packet overflows interface MTU. */
-  if (*length + delta > OSPF_PACKET_MAX(oi))
+  if (*length + delta > ospf_packet_max(oi))
     return 0;
 
   stream_putl (s, lsa->data->type);
@@ -2642,12 +2769,12 @@ ospf_make_ls_req_func (struct stream *s, u_int16_t *length,
   return 1;
 }
 
-int
+static int
 ospf_make_ls_req (struct ospf_neighbor *nbr, struct stream *s)
 {
   struct ospf_lsa *lsa;
   u_int16_t length = OSPF_LS_REQ_MIN_SIZE;
-  unsigned long delta = stream_get_putp(s)+12;
+  unsigned long delta = stream_get_endp(s)+12;
   struct route_table *table;
   struct route_node *rn;
   int i;
@@ -2669,7 +2796,7 @@ ospf_make_ls_req (struct ospf_neighbor *nbr, struct stream *s)
   return length;
 }
 
-int
+static int
 ls_age_increment (struct ospf_lsa *lsa, int delay)
 {
   int age;
@@ -2679,21 +2806,25 @@ ls_age_increment (struct ospf_lsa *lsa, int delay)
   return (age > OSPF_LSA_MAXAGE ? OSPF_LSA_MAXAGE : age);
 }
 
-int
-ospf_make_ls_upd (struct ospf_interface *oi, list update, struct stream *s)
+static int
+ospf_make_ls_upd (struct ospf_interface *oi, struct list *update, struct stream *s)
 {
   struct ospf_lsa *lsa;
-  listnode node;
+  struct listnode *node;
   u_int16_t length = OSPF_LS_UPD_MIN_SIZE;
-  unsigned long delta = stream_get_putp (s);
+  unsigned int size_noauth;
+  unsigned long delta = stream_get_endp (s);
   unsigned long pp;
   int count = 0;
 
   if (IS_DEBUG_OSPF_EVENT)
-    zlog_info("ospf_make_ls_upd: Start");
-  
-  pp = stream_get_putp (s);
-  ospf_output_forward (s, 4);
+    zlog_debug ("ospf_make_ls_upd: Start");
+
+  pp = stream_get_endp (s);
+  stream_forward_endp (s, OSPF_LS_UPD_MIN_SIZE);
+
+  /* Calculate amount of packet usable for data. */
+  size_noauth = stream_get_size(s) - ospf_packet_authspace(oi);
 
   while ((node = listhead (update)) != NULL)
     {
@@ -2701,18 +2832,18 @@ ospf_make_ls_upd (struct ospf_interface *oi, list update, struct stream *s)
       u_int16_t ls_age;
 
       if (IS_DEBUG_OSPF_EVENT)
-       zlog_info("ospf_make_ls_upd: List Iteration");
+        zlog_debug ("ospf_make_ls_upd: List Iteration");
+
+      lsa = listgetdata (node);
 
-      lsa = getdata (node);
-      assert (lsa);
       assert (lsa->data);
 
-      /* Check packet size. */
-      if (length + delta + ntohs (lsa->data->length) > OSPF_PACKET_MAX (oi))
-       break;
-      
+      /* Will it fit? */
+      if (length + delta + ntohs (lsa->data->length) > size_noauth)
+        break;
+
       /* Keep pointer to LS age. */
-      lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_putp (s));
+      lsah = (struct lsa_header *) (STREAM_DATA (s) + stream_get_endp (s));
 
       /* Put LSA to Link State Request. */
       stream_put (s, lsa->data, ntohs (lsa->data->length));
@@ -2731,33 +2862,30 @@ ospf_make_ls_upd (struct ospf_interface *oi, list update, struct stream *s)
     }
 
   /* Now set #LSAs. */
-  stream_set_putp (s, pp);
-  stream_putl (s, count);
-
-  stream_set_putp (s, s->endp);
+  stream_putl_at (s, pp, count);
 
   if (IS_DEBUG_OSPF_EVENT)
-    zlog_info("ospf_make_ls_upd: Stop");
+    zlog_debug ("ospf_make_ls_upd: Stop");
   return length;
 }
 
-int
-ospf_make_ls_ack (struct ospf_interface *oi, list ack, struct stream *s)
+static int
+ospf_make_ls_ack (struct ospf_interface *oi, struct list *ack, struct stream *s)
 {
-  list rm_list;
-  listnode node;
+  struct list *rm_list;
+  struct listnode *node;
   u_int16_t length = OSPF_LS_ACK_MIN_SIZE;
-  unsigned long delta = stream_get_putp(s) + 24;
+  unsigned long delta = stream_get_endp(s) + 24;
   struct ospf_lsa *lsa;
 
   rm_list = list_new ();
   
-  for (node = listhead (ack); node; nextnode (node))
+  for (ALL_LIST_ELEMENTS_RO (ack, node, lsa))
     {
-      lsa = getdata (node);
+      lsa = listgetdata (node);
       assert (lsa);
       
-      if (length + delta > OSPF_PACKET_MAX (oi))
+      if (length + delta > ospf_packet_max (oi))
        break;
       
       stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE);
@@ -2767,10 +2895,11 @@ ospf_make_ls_ack (struct ospf_interface *oi, list ack, struct stream *s)
     }
   
   /* Remove LSA from LS-Ack list. */
-  for (node = listhead (rm_list); node; nextnode (node))
+  /* XXX: this loop should be removed and the list move done in previous
+   * loop
+   */
+  for (ALL_LIST_ELEMENTS_RO (rm_list, node, lsa))
     {
-      lsa = (struct ospf_lsa *) getdata (node);
-      
       listnode_delete (ack, lsa);
       ospf_lsa_unlock (lsa);
     }
@@ -2809,7 +2938,7 @@ ospf_hello_send_sub (struct ospf_interface *oi, struct in_addr *addr)
   OSPF_ISM_WRITE_ON (oi->ospf);
 }
 
-void
+static void
 ospf_poll_send (struct ospf_nbr_nbma *nbr_nbma)
 {
   struct ospf_interface *oi;
@@ -2846,7 +2975,7 @@ ospf_poll_timer (struct thread *thread)
   nbr_nbma->t_poll = NULL;
 
   if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
-    zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (Poll timer expire)",
+    zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (Poll timer expire)",
     IF_NAME (nbr_nbma->oi), inet_ntoa (nbr_nbma->addr));
 
   ospf_poll_send (nbr_nbma);
@@ -2870,7 +2999,7 @@ ospf_hello_reply_timer (struct thread *thread)
   assert (nbr->oi);
 
   if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
-    zlog (NULL, LOG_INFO, "NSM[%s:%s]: Timer (hello-reply timer expire)",
+    zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (hello-reply timer expire)",
          IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
 
   ospf_hello_send_sub (nbr->oi, &nbr->address.u.prefix4);
@@ -3063,7 +3192,7 @@ void
 ospf_ls_upd_send_lsa (struct ospf_neighbor *nbr, struct ospf_lsa *lsa,
                      int flag)
 {
-  list update;
+  struct list *update;
 
   update = list_new ();
 
@@ -3073,23 +3202,86 @@ ospf_ls_upd_send_lsa (struct ospf_neighbor *nbr, struct ospf_lsa *lsa,
   list_delete (update);
 }
 
+/* Determine size for packet. Must be at least big enough to accomodate next
+ * LSA on list, which may be bigger than MTU size.
+ *
+ * Return pointer to new ospf_packet
+ * NULL if we can not allocate, eg because LSA is bigger than imposed limit
+ * on packet sizes (in which case offending LSA is deleted from update list)
+ */
+static struct ospf_packet *
+ospf_ls_upd_packet_new (struct list *update, struct ospf_interface *oi)
+{
+  struct ospf_lsa *lsa;
+  struct listnode *ln;
+  size_t size;
+  static char warned = 0;
+
+  lsa = listgetdata((ln = listhead (update)));
+  assert (lsa->data);
+
+  if ((OSPF_LS_UPD_MIN_SIZE + ntohs (lsa->data->length))
+      > ospf_packet_max (oi))
+    {
+      if (!warned)
+        {
+          zlog_warn ("ospf_ls_upd_packet_new: oversized LSA encountered!"
+                     "will need to fragment. Not optimal. Try divide up"
+                     " your network with areas. Use 'debug ospf packet send'"
+                     " to see details, or look at 'show ip ospf database ..'");
+          warned = 1;
+        }
+
+      if (IS_DEBUG_OSPF_PACKET (0, SEND))
+        zlog_debug ("ospf_ls_upd_packet_new: oversized LSA id:%s,"
+                   " %d bytes originated by %s, will be fragmented!",
+                   inet_ntoa (lsa->data->id),
+                   ntohs (lsa->data->length),
+                   inet_ntoa (lsa->data->adv_router));
+
+      /* 
+       * Allocate just enough to fit this LSA only, to avoid including other
+       * LSAs in fragmented LSA Updates.
+       */
+      size = ntohs (lsa->data->length) + (oi->ifp->mtu - ospf_packet_max (oi))
+             + OSPF_LS_UPD_MIN_SIZE;
+    }
+  else
+    size = oi->ifp->mtu;
+
+  /* XXX Should this be - sizeof(struct ip)?? -gdt */
+  if (size > OSPF_MAX_PACKET_SIZE)
+    {
+      zlog_warn ("ospf_ls_upd_packet_new: oversized LSA id:%s too big,"
+                 " %d bytes, packet size %ld, dropping it completely."
+                 " OSPF routing is broken!",
+                 inet_ntoa (lsa->data->id), ntohs (lsa->data->length),
+                 (long int) size);
+      list_delete_node (update, ln);
+      return NULL;
+    }
+
+  return ospf_packet_new (size);
+}
+
 static void
-ospf_ls_upd_queue_send (struct ospf_interface *oi, list update,
+ospf_ls_upd_queue_send (struct ospf_interface *oi, struct list *update,
                        struct in_addr addr)
 {
   struct ospf_packet *op;
   u_int16_t length = OSPF_HEADER_SIZE;
 
   if (IS_DEBUG_OSPF_EVENT)
-    zlog_info ("listcount = %d, dst %s", listcount (update), inet_ntoa(addr));
-
-  op = ospf_packet_new (oi->ifp->mtu);
+    zlog_debug ("listcount = %d, dst %s", listcount (update), inet_ntoa(addr));
+  
+  op = ospf_ls_upd_packet_new (update, oi);
 
   /* Prepare OSPF common header. */
   ospf_make_header (OSPF_MSG_LS_UPD, oi, op->s);
 
-  /* Prepare OSPF Link State Update body. */
-  /* Includes Type-7 translation. */
+  /* Prepare OSPF Link State Update body.
+   * Includes Type-7 translation. 
+   */
   length += ospf_make_ls_upd (oi, update, op->s);
 
   /* Fill OSPF header. */
@@ -3114,41 +3306,59 @@ ospf_ls_upd_send_queue_event (struct thread *thread)
   struct ospf_interface *oi = THREAD_ARG(thread);
   struct route_node *rn;
   struct route_node *rnext;
+  struct list *update;
+  char again = 0;
   
   oi->t_ls_upd_event = NULL;
 
   if (IS_DEBUG_OSPF_EVENT)
-    zlog_info ("ospf_ls_upd_send_queue start");
+    zlog_debug ("ospf_ls_upd_send_queue start");
 
   for (rn = route_top (oi->ls_upd_queue); rn; rn = rnext)
     {
-      
       rnext = route_next (rn);
       
       if (rn->info == NULL)
         continue;
+      
+      update = (struct list *)rn->info;
 
-      while (!list_isempty ((list)rn->info))
-        ospf_ls_upd_queue_send (oi, rn->info, rn->p.u.prefix4);
-
-      list_delete (rn->info);
-      rn->info = NULL;
+      ospf_ls_upd_queue_send (oi, update, rn->p.u.prefix4);
       
-      route_unlock_node (rn);
+      /* list might not be empty. */
+      if (listcount(update) == 0)
+        {
+          list_delete (rn->info);
+          rn->info = NULL;
+          route_unlock_node (rn);
+        }
+      else
+        again = 1;
+    }
+
+  if (again != 0)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_debug ("ospf_ls_upd_send_queue: update lists not cleared,"
+                   " %d nodes to try again, raising new event", again);
+      oi->t_ls_upd_event = 
+        thread_add_event (master, ospf_ls_upd_send_queue_event, oi, 0);
     }
 
   if (IS_DEBUG_OSPF_EVENT)
-    zlog_info ("ospf_ls_upd_send_queue stop");
+    zlog_debug ("ospf_ls_upd_send_queue stop");
+  
   return 0;
 }
 
 void
-ospf_ls_upd_send (struct ospf_neighbor *nbr, list update, int flag)
+ospf_ls_upd_send (struct ospf_neighbor *nbr, struct list *update, int flag)
 {
   struct ospf_interface *oi;
+  struct ospf_lsa *lsa;
   struct prefix_ipv4 p;
   struct route_node *rn;
-  listnode n;
+  struct listnode *node;
   
   oi = nbr->oi;
 
@@ -3183,8 +3393,11 @@ ospf_ls_upd_send (struct ospf_neighbor *nbr, list update, int flag)
   if (rn->info == NULL)
     rn->info = list_new ();
 
-  for (n = listhead (update); n; nextnode (n))
-    listnode_add (rn->info, ospf_lsa_lock (getdata (n)));
+  for (ALL_LIST_ELEMENTS_RO (update, node, lsa))
+    {
+      ospf_lsa_lock (lsa);
+      listnode_add (rn->info, lsa);
+    }
 
   if (oi->t_ls_upd_event == NULL)
     oi->t_ls_upd_event =
@@ -3192,7 +3405,8 @@ ospf_ls_upd_send (struct ospf_neighbor *nbr, list update, int flag)
 }
 
 static void
-ospf_ls_ack_send_list (struct ospf_interface *oi, list ack, struct in_addr dst)
+ospf_ls_ack_send_list (struct ospf_interface *oi, struct list *ack,
+                      struct in_addr dst)
 {
   struct ospf_packet *op;
   u_int16_t length = OSPF_HEADER_SIZE;
@@ -3279,6 +3493,8 @@ ospf_ls_ack_send_delayed (struct ospf_interface *oi)
     dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
   else if (oi->type == OSPF_IFTYPE_POINTOPOINT)
     dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
+  else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
+    dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
   else
     dst.s_addr = htonl (OSPF_ALLDROUTERS);