Initial revision
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
new file mode 100644
index 0000000..5b63a76
--- /dev/null
+++ b/ospfd/ospf_lsa.c
@@ -0,0 +1,3315 @@
+/*
+ * OSPF Link State Advertisement
+ * Copyright (C) 1999, 2000 Toshiaki Takada
+ *
+ * This file is part of GNU Zebra.
+ *
+ * GNU Zebra is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * GNU Zebra is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Zebra; see the file COPYING.  If not, write to the Free
+ * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <zebra.h>
+
+#include "linklist.h"
+#include "prefix.h"
+#include "if.h"
+#include "table.h"
+#include "memory.h"
+#include "stream.h"
+#include "log.h"
+#include "thread.h"
+#include "hash.h"
+#include "sockunion.h"		/* for inet_aton() */
+
+#include "ospfd/ospfd.h"
+#include "ospfd/ospf_interface.h"
+#include "ospfd/ospf_ism.h"
+#include "ospfd/ospf_asbr.h"
+#include "ospfd/ospf_lsa.h"
+#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_neighbor.h"
+#include "ospfd/ospf_nsm.h"
+#include "ospfd/ospf_flood.h"
+#include "ospfd/ospf_packet.h"
+#include "ospfd/ospf_spf.h"
+#include "ospfd/ospf_dump.h"
+#include "ospfd/ospf_route.h"
+#include "ospfd/ospf_ase.h"
+#include "ospfd/ospf_zebra.h"
+
+
+u_int32_t
+get_metric (u_char *metric)
+{
+  u_int32_t m;
+  m = metric[0];
+  m = (m << 8) + metric[1];
+  m = (m << 8) + metric[2];
+  return m;
+}
+
+
+struct timeval
+tv_adjust (struct timeval a)
+{
+  while (a.tv_usec >= 1000000)
+    {
+      a.tv_usec -= 1000000;
+      a.tv_sec++;
+    }
+
+  while (a.tv_usec < 0)
+    {
+      a.tv_usec += 1000000;
+      a.tv_sec--;
+    }
+
+  return a;
+}
+
+int
+tv_ceil (struct timeval a)
+{
+  a = tv_adjust (a);
+
+  return (a.tv_usec ? a.tv_sec + 1 : a.tv_sec);
+}
+
+int
+tv_floor (struct timeval a)
+{
+  a = tv_adjust (a);
+
+  return a.tv_sec;
+}
+
+struct timeval
+int2tv (int a)
+{
+  struct timeval ret;
+
+  ret.tv_sec = a;
+  ret.tv_usec = 0;
+
+  return ret;
+}
+
+struct timeval
+tv_add (struct timeval a, struct timeval b)
+{
+  struct timeval ret;
+
+  ret.tv_sec = a.tv_sec + b.tv_sec;
+  ret.tv_usec = a.tv_usec + b.tv_usec;
+
+  return tv_adjust (ret);
+}
+
+struct timeval
+tv_sub (struct timeval a, struct timeval b)
+{
+  struct timeval ret;
+
+  ret.tv_sec = a.tv_sec - b.tv_sec;
+  ret.tv_usec = a.tv_usec - b.tv_usec;
+
+  return tv_adjust (ret);
+}
+
+int
+tv_cmp (struct timeval a, struct timeval b)
+{
+  return (a.tv_sec == b.tv_sec ?
+	  a.tv_usec - b.tv_usec : a.tv_sec - b.tv_sec);
+}
+
+int
+ospf_lsa_refresh_delay (struct ospf_lsa *lsa)
+{
+  struct timeval delta, now;
+  int delay = 0;
+
+  gettimeofday (&now, NULL);
+  delta = tv_sub (now, lsa->tv_orig);
+
+  if (tv_cmp (delta, int2tv (OSPF_MIN_LS_INTERVAL)) < 0)
+    {
+      delay = tv_ceil (tv_sub (int2tv (OSPF_MIN_LS_INTERVAL), delta));
+
+      if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+        zlog_info ("LSA[Type%d:%s]: Refresh timer delay %d seconds",
+	           lsa->data->type, inet_ntoa (lsa->data->id), delay);
+
+      assert (delay > 0);
+    }
+
+  return delay;
+}
+
+
+int
+get_age (struct ospf_lsa *lsa)
+{
+  int age;
+  struct timeval now;
+
+  gettimeofday (&now, NULL);
+  age = ntohs (lsa->data->ls_age) + tv_floor (tv_sub (now, lsa->tv_recv));
+
+  return age;
+}
+
+
+/* Fletcher Checksum -- Refer to RFC1008. */
+#define MODX                 4102
+#define LSA_CHECKSUM_OFFSET    15
+
+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;
+
+  lsa->checksum = 0;
+  length = ntohs (lsa->length) - 2;
+  sp = (char *) &lsa->options;
+
+  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;
+    }
+
+  x = ((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);
+}
+
+
+
+/* Create OSPF LSA. */
+struct ospf_lsa *
+ospf_lsa_new ()
+{
+  struct ospf_lsa *new;
+
+  new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa));
+  memset (new, 0, sizeof (struct ospf_lsa));
+
+  new->flags = 0;
+  new->lock = 1;
+  new->retransmit_counter = 0;
+  gettimeofday (&new->tv_recv, NULL);
+  new->tv_orig = new->tv_recv;
+  new->refresh_list = -1;
+  
+  return new;
+}
+
+/* Duplicate OSPF LSA. */
+struct ospf_lsa *
+ospf_lsa_dup (struct ospf_lsa *lsa)
+{
+  struct ospf_lsa *new;
+
+  if (lsa == NULL)
+    return NULL;
+
+  new = XCALLOC (MTYPE_OSPF_LSA, sizeof (struct ospf_lsa));
+
+  memcpy (new, lsa, sizeof (struct ospf_lsa));
+  UNSET_FLAG (new->flags, OSPF_LSA_DISCARD);
+  new->lock = 1;
+  new->retransmit_counter = 0;
+  new->data = ospf_lsa_data_dup (lsa->data);
+
+  return new;
+}
+
+/* Free OSPF LSA. */
+void
+ospf_lsa_free (struct ospf_lsa *lsa)
+{
+  assert (lsa->lock == 0);
+  
+  if (IS_DEBUG_OSPF (lsa, LSA))
+    zlog_info ("LSA: freed %p", lsa);
+
+  /* Delete LSA data. */
+  if (lsa->data != NULL)
+    ospf_lsa_data_free (lsa->data);
+
+  assert (lsa->refresh_list < 0);
+
+  memset (lsa, 0, sizeof (struct ospf_lsa)); 
+  XFREE (MTYPE_OSPF_LSA, lsa);
+}
+
+/* Lock LSA. */
+struct ospf_lsa *
+ospf_lsa_lock (struct ospf_lsa *lsa)
+{
+  lsa->lock++;
+  return lsa;
+}
+
+/* Unlock LSA. */
+void
+ospf_lsa_unlock (struct ospf_lsa *lsa)
+{
+  /* This is sanity check. */
+  if (!lsa)
+    return;
+  
+  lsa->lock--;
+
+  assert (lsa->lock >= 0);
+
+  if (lsa->lock == 0)
+    {
+      assert (CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD));
+      ospf_lsa_free (lsa);
+    }
+}
+
+/* Check discard flag. */
+void
+ospf_lsa_discard (struct ospf_lsa *lsa)
+{
+  if (!CHECK_FLAG (lsa->flags, OSPF_LSA_DISCARD))
+    {
+      SET_FLAG (lsa->flags, OSPF_LSA_DISCARD);
+      ospf_lsa_unlock (lsa);
+    }
+}
+
+/* Create LSA data. */
+struct lsa_header *
+ospf_lsa_data_new (size_t size)
+{
+  struct lsa_header *new;
+
+  new = (struct lsa_header *) XMALLOC (MTYPE_OSPF_LSA_DATA, size);
+  memset (new, 0, size);
+
+  return new;
+}
+
+/* Duplicate LSA data. */
+struct lsa_header *
+ospf_lsa_data_dup (struct lsa_header *lsah)
+{
+  struct lsa_header *new;
+
+  new = ospf_lsa_data_new (ntohs (lsah->length));
+  memcpy (new, lsah, ntohs (lsah->length));
+
+  return new;
+}
+
+/* Free LSA data. */
+void
+ospf_lsa_data_free (struct lsa_header *lsah)
+{
+  if (IS_DEBUG_OSPF (lsa, LSA))
+    zlog_info ("LSA[Type%d:%s]: data freed %p",
+	       lsah->type, inet_ntoa (lsah->id), lsah);
+
+  XFREE (MTYPE_OSPF_LSA_DATA, lsah);
+}
+
+
+/* LSA general functions. */
+
+const char *
+dump_lsa_key (struct ospf_lsa *lsa)
+{
+  static char buf[] = {
+    "Type255,id(255.255.255.255),ar(255.255.255.255)",
+  };
+  struct lsa_header *lsah;
+
+  if (lsa != NULL && (lsah = lsa->data) != NULL)
+    {
+      char id[INET_ADDRSTRLEN], ar[INET_ADDRSTRLEN];
+      strcpy (id, inet_ntoa (lsah->id));
+      strcpy (ar, inet_ntoa (lsah->adv_router));
+
+      sprintf (buf, "Type%d,id(%s),ar(%s)", lsah->type, id, ar);
+    }
+  else
+    strcpy (buf, "NULL");
+
+  return buf;
+}
+
+u_int32_t
+lsa_seqnum_increment (struct ospf_lsa *lsa)
+{
+  u_int32_t seqnum;
+
+  seqnum = ntohl (lsa->data->ls_seqnum) + 1;
+
+  return htonl (seqnum);
+}
+
+void
+lsa_header_set (struct stream *s, u_char options,
+		u_char type, struct in_addr id)
+{
+  struct lsa_header *lsah;
+
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+  lsah->ls_age = htons (0);
+  lsah->options = options;
+  lsah->type = type;
+  lsah->id = id;
+  lsah->adv_router = ospf_top->router_id;
+  lsah->ls_seqnum = htonl (OSPF_INITIAL_SEQUENCE_NUMBER);
+
+  ospf_output_forward (s, OSPF_LSA_HEADER_SIZE);
+}
+
+/* router-LSA related functions. */
+/* Get router-LSA flags. */
+u_char
+router_lsa_flags (struct ospf_area *area)
+{
+  u_char flags;
+
+  flags = ospf_top->flags;
+
+  /* Set virtual link flag. */
+  if (ospf_full_virtual_nbrs (area))
+    SET_FLAG (flags, ROUTER_LSA_VIRTUAL);
+  else
+    /* Just sanity check */
+    UNSET_FLAG (flags, ROUTER_LSA_VIRTUAL);
+
+  /* Set Shortcut ABR behabiour flag. */
+  UNSET_FLAG (flags, ROUTER_LSA_SHORTCUT);
+  if (ospf_top->abr_type == OSPF_ABR_SHORTCUT)
+    if (!OSPF_IS_AREA_BACKBONE (area))
+      if ((area->shortcut_configured == OSPF_SHORTCUT_DEFAULT &&
+	   !ospf_top->backbone) ||
+	  area->shortcut_configured == OSPF_SHORTCUT_ENABLE)
+	SET_FLAG (flags, ROUTER_LSA_SHORTCUT);
+
+  /* ASBR can't exit in stub area. */
+  if (area->external_routing == OSPF_AREA_STUB)
+    UNSET_FLAG (flags, OSPF_FLAG_ASBR);
+
+  return flags;
+}
+
+/* Lookup neighbor other than myself.
+   And check neighbor count,
+   Point-to-Point link must have only 1 neighbor. */
+struct ospf_neighbor *
+ospf_nbr_lookup_ptop (struct route_table *nbrs, struct in_addr router_id)
+{
+  struct route_node *rn;
+  struct ospf_neighbor *nbr = NULL;
+
+  /* Search neighbor, there must be one of two nbrs. */
+  for (rn = route_top (nbrs); rn; rn = route_next (rn))
+    if ((nbr = rn->info) != NULL)
+      /* Ignore myself. */
+      if (!IPV4_ADDR_SAME (&nbr->router_id, &ospf_top->router_id))
+	if (nbr->state == NSM_Full)
+	  break;
+
+  /* PtoP link must have only 1 neighbor. */
+  if (ospf_nbr_count (nbrs, 0) > 1)
+    zlog_warn ("Point-to-Point link has more than 1 neighobrs.");
+
+  return nbr;
+}
+
+/* Set a link information. */
+void
+link_info_set (struct stream *s, struct in_addr id,
+	       struct in_addr data, u_char type, u_char tos, u_int16_t cost)
+{
+  /* TOS based routing is not supported. */
+  stream_put_ipv4 (s, id.s_addr);		/* Link ID. */
+  stream_put_ipv4 (s, data.s_addr);		/* Link Data. */
+  stream_putc (s, type);			/* Link Type. */
+  stream_putc (s, tos);				/* TOS = 0. */
+  stream_putw (s, cost);			/* Link Cost. */
+}
+
+/* Describe Point-to-Point link. */
+int
+lsa_link_ptop_set (struct stream *s, struct ospf_interface *oi)
+{
+  int links = 0;
+  struct ospf_neighbor *nbr;
+  struct in_addr id, mask;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type1]: Set link Point-to-Point");
+
+  if ((nbr = ospf_nbr_lookup_ptop (oi->nbrs, ospf_top->router_id)))
+    if (nbr->state == NSM_Full)
+      {
+	/* For unnumbered point-to-point networks, the Link Data field
+	   should specify the interface's MIB-II ifIndex value. */
+	link_info_set (s, nbr->router_id, oi->address->u.prefix4,
+		       LSA_LINK_TYPE_POINTOPOINT, 0, oi->output_cost);
+	links++;
+      }
+
+  if (oi->connected->destination != NULL)
+    {
+      /* Option 1:
+	 link_type = LSA_LINK_TYPE_STUB;
+	 link_id = nbr->address.u.prefix4;
+	 link_data.s_addr = 0xffffffff;
+	 link_cost = o->output_cost; */
+      
+      id.s_addr = oi->connected->destination->u.prefix4.s_addr;
+      mask.s_addr = 0xffffffff;
+      link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+    }
+  else
+    {
+       /* Option 2:  We need to include link to a stub
+	 network regardless of the state of the neighbor */
+      masklen2ip (oi->address->prefixlen, &mask);
+      id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
+      link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+    }
+  links++;
+
+  return links;
+}
+
+/* Describe Broadcast Link. */
+int
+lsa_link_broadcast_set (struct stream *s, struct ospf_interface *oi)
+{
+  struct ospf_neighbor *dr;
+  struct in_addr id, mask;
+
+  /* Describe Type 3 Link. */
+  if (oi->state == ISM_Waiting)
+    {
+      masklen2ip (oi->address->prefixlen, &mask);
+      id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
+      link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+      return 1;
+    }
+
+  dr = ospf_nbr_lookup_by_addr (oi->nbrs, &DR (oi));
+  /* Describe Type 2 link. */
+  if (dr && (dr->state == NSM_Full ||
+	     IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))) &&
+      ospf_nbr_count (oi->nbrs, NSM_Full) > 0)
+    {
+      link_info_set (s, DR (oi), oi->address->u.prefix4,
+		     LSA_LINK_TYPE_TRANSIT, 0, oi->output_cost);
+    }
+  /* Describe type 3 link. */
+  else
+    {
+      masklen2ip (oi->address->prefixlen, &mask);
+      id.s_addr = oi->address->u.prefix4.s_addr & mask.s_addr;
+      link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+    }
+  return 1;
+}
+
+int
+lsa_link_loopback_set (struct stream *s, struct ospf_interface *oi)
+{
+  struct in_addr id, mask;
+
+  /* Describe Type 3 Link. */
+  if (oi->state != ISM_Loopback)
+    return 0;
+
+  mask.s_addr = 0xffffffff;
+  id.s_addr = oi->address->u.prefix4.s_addr;
+  link_info_set (s, id, mask, LSA_LINK_TYPE_STUB, 0, oi->output_cost);
+  return 1;
+}
+
+/* Describe Virtual Link. */
+int
+lsa_link_virtuallink_set (struct stream *s, struct ospf_interface *oi)
+{
+  struct ospf_neighbor *nbr;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type1]: Set link type VL, state %d", oi->state);
+
+  if (oi->state == ISM_PointToPoint)
+    if ((nbr = ospf_nbr_lookup_ptop (oi->nbrs, ospf_top->router_id)))
+      if (nbr->state == NSM_Full)
+	{
+	  link_info_set (s, nbr->router_id, oi->address->u.prefix4,
+			 LSA_LINK_TYPE_VIRTUALLINK, 0, oi->output_cost);
+	  return 1;
+	}
+
+  return 0;
+}
+
+#define lsa_link_nbma_set(S,O)  lsa_link_broadcast_set (S, O)
+
+/* Set router-LSA link information. */
+int
+router_lsa_link_set (struct stream *s, struct ospf_area *area)
+{
+  listnode node;
+  int links = 0;
+
+  for (node = listhead (area->oiflist); node; node = nextnode (node))
+    {
+      struct ospf_interface *oi = node->data;
+      struct interface *ifp = oi->ifp;
+
+      /* Check interface is up, OSPF is enable. */
+      if (if_is_up (ifp))
+	{
+	  if (oi->state != ISM_Down)
+	    {
+	      /* Describe each link. */
+	      switch (oi->type)
+		{
+		case OSPF_IFTYPE_POINTOPOINT:
+		  links += lsa_link_ptop_set (s, oi);
+		  break;
+		case OSPF_IFTYPE_BROADCAST:
+		  links += lsa_link_broadcast_set (s, oi);
+		  break;
+		case OSPF_IFTYPE_NBMA:
+		  links += lsa_link_nbma_set (s, oi);
+		  break;
+		case OSPF_IFTYPE_POINTOMULTIPOINT:
+		  /* Not supproted yet. */
+		  break;
+		case OSPF_IFTYPE_VIRTUALLINK:
+		  links += lsa_link_virtuallink_set (s, oi);
+		  break;
+		case OSPF_IFTYPE_LOOPBACK:
+		  links += lsa_link_loopback_set (s, oi); 
+		}
+	    }
+	}
+    }
+
+  return links;
+}
+
+/* Set router-LSA body. */
+void
+ospf_router_lsa_body_set (struct stream *s, struct ospf_area *area)
+{
+  unsigned long putp;
+  u_int16_t cnt;
+
+  /* Set flags. */
+  stream_putc (s, router_lsa_flags (area));
+
+  /* Set Zero fields. */
+  stream_putc (s, 0);
+
+  /* Keep pointer to # links. */
+  putp = s->putp;
+
+  /* Forward word */
+  stream_putw(s, 0);
+
+  /* Set all link information. */
+  cnt = router_lsa_link_set (s, area);
+
+  /* Set # of links here. */
+  stream_putw_at (s, putp, cnt);
+}
+
+/* Create new router-LSA. */
+struct ospf_lsa *
+ospf_router_lsa_new (struct ospf_area *area)
+{
+  struct stream *s;
+  struct lsa_header *lsah;
+  struct ospf_lsa *new;
+  int length;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type1]: Create router-LSA instance");
+
+  /* Create a stream for LSA. */
+  s = stream_new (OSPF_MAX_LSA_SIZE);
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+#ifdef HAVE_NSSA
+  /* Set LSA common header fields. */
+  lsa_header_set (s, LSA_OPTIONS_GET (area) | LSA_NSSA_GET (area),
+		  OSPF_ROUTER_LSA, ospf_top->router_id);
+#else /* ! HAVE_NSSA */
+  /* Set LSA common header fields. */
+  lsa_header_set (s, LSA_OPTIONS_GET (area),
+		  OSPF_ROUTER_LSA, ospf_top->router_id);
+#endif /* HAVE_NSSA */
+
+  /* Set router-LSA body fields. */
+  ospf_router_lsa_body_set (s, area);
+
+  /* Set length. */
+  length = stream_get_endp (s);
+  lsah->length = htons (length);
+
+  /* Now, create OSPF LSA instance. */
+  new = ospf_lsa_new ();
+  new->area = area;
+  SET_FLAG (new->flags, OSPF_LSA_SELF);
+
+  /* Copy LSA data to store, discard stream. */
+  new->data = ospf_lsa_data_new (length);
+  memcpy (new->data, lsah, length);
+  stream_free (s);
+
+  return new;
+}
+
+/* Originate Router-LSA. */
+struct ospf_lsa *
+ospf_router_lsa_originate (struct ospf_area *area)
+{
+  struct ospf_lsa *new;
+
+  /* Create new router-LSA instance. */
+  new = ospf_router_lsa_new (area);
+
+  /* Sanity check. */
+  if (new->data->adv_router.s_addr == 0)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+	zlog_info ("LSA[Type1]: AdvRouter is 0, discard");
+      ospf_lsa_discard (new);
+      return NULL;
+    }
+
+  /* Install LSA to LSDB. */
+  new = ospf_lsa_install (NULL, new);
+
+  /* Update LSA origination count. */
+  ospf_top->lsa_originate_count++;
+
+  /* Flooding new LSA through area. */
+  ospf_flood_through_area (area, NULL, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: Originate router-LSA %p",
+		 new->data->type, inet_ntoa (new->data->id), new);
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return new;
+}
+
+/* Refresh router-LSA. */
+struct ospf_lsa *
+ospf_router_lsa_refresh (struct ospf_lsa *lsa)
+{
+  struct ospf_area *area = lsa->area;
+  struct ospf_lsa *new;
+
+  /* Sanity check. */
+  assert (lsa->data);
+
+  /* Delete LSA from neighbor retransmit-list. */
+  ospf_ls_retransmit_delete_nbr_all (area, lsa);
+
+  /* Create new router-LSA instance. */
+  new = ospf_router_lsa_new (area);
+  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+
+  ospf_lsa_install (NULL, new);
+
+  /* Flood LSA through area. */
+  ospf_flood_through_area (area, NULL, new);
+
+  /* Debug logging. */
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: router-LSA refresh",
+		 new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return NULL;
+}
+
+int
+ospf_router_lsa_timer (struct thread *t)
+{
+  struct ospf_area *area;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("Timer[router-LSA]: (router-LSA Refresh expire)");
+
+  area = THREAD_ARG (t);
+  area->t_router_lsa_self = NULL;
+
+  /* Now refresh router-LSA. */
+  if (area->router_lsa_self)
+    ospf_router_lsa_refresh (area->router_lsa_self);
+  /* Newly originate router-LSA. */
+  else
+    ospf_router_lsa_originate (area);
+
+  return 0;
+}
+
+void
+ospf_router_lsa_timer_add (struct ospf_area *area)
+{
+  /* Keep area's self-originated router-LSA. */
+  struct ospf_lsa *lsa = area->router_lsa_self;
+
+  /* Cancel previously scheduled router-LSA timer. */
+  if (area->t_router_lsa_self)
+    if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+      zlog_info ("LSA[Type1]: Cancel previous router-LSA timer");
+
+  OSPF_TIMER_OFF (area->t_router_lsa_self);
+
+  /* If router-LSA is originated previously, check the interval time. */
+  if (lsa)
+    {
+      int delay;
+      if ((delay = ospf_lsa_refresh_delay (lsa)) > 0)
+        {
+	  OSPF_AREA_TIMER_ON (area->t_router_lsa_self,
+			      ospf_router_lsa_timer, delay);
+	  return;
+        }
+    }
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type1]: Scheduling router-LSA origination right away");
+
+  /* Immediately refresh router-LSA. */
+  OSPF_AREA_TIMER_ON (area->t_router_lsa_self, ospf_router_lsa_timer, 0);
+}
+
+int
+ospf_router_lsa_update_timer (struct thread *t)
+{
+  listnode node;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("Timer[router-LSA Update]: (timer expire)");
+
+  ospf_top->t_router_lsa_update = NULL;
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      struct ospf_area *area = getdata (node);
+      struct ospf_lsa *lsa = area->router_lsa_self;
+      struct router_lsa *rl;
+      char *area_str;
+
+      /* Keep Area ID string. */
+      area_str = AREA_NAME (area);
+
+      /* If LSA not exist in this Area, originate new. */
+      if (lsa == NULL)
+        {
+	  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+	    zlog_info("LSA[Type1]: Create router-LSA for Area %s", area_str);
+
+	  ospf_router_lsa_originate (area);
+        }
+      /* If router-ID is changed, Link ID must change.
+	 First flush old LSA, then originate new. */
+      else if (!IPV4_ADDR_SAME (&lsa->data->id, &ospf_top->router_id))
+	{
+	  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+	    zlog_info("LSA[Type%d:%s]: Refresh router-LSA for Area %s",
+		      lsa->data->type, inet_ntoa (lsa->data->id), area_str);
+	  ospf_lsa_flush_area (lsa, area);
+	  ospf_lsa_unlock (area->router_lsa_self);
+	  area->router_lsa_self = NULL;
+
+	  /* Refresh router-LSA, (not install) and flood through area. */
+	  ospf_router_lsa_timer_add (area);
+	}
+      else
+	{
+	  rl = (struct router_lsa *) lsa->data;
+	  /* Refresh router-LSA, (not install) and flood through area. */
+	  if (rl->flags != ospf_top->flags)
+	    ospf_router_lsa_timer_add (area);
+	}
+    }
+
+  return 0;
+}
+
+
+/* network-LSA related functions. */
+/* Originate Network-LSA. */
+void
+ospf_network_lsa_body_set (struct stream *s, struct ospf_interface *oi)
+{
+  struct in_addr mask;
+  struct route_node *rn;
+  struct ospf_neighbor *nbr;
+
+  masklen2ip (oi->address->prefixlen, &mask);
+  stream_put_ipv4 (s, mask.s_addr);
+
+  /* The network-LSA lists those routers that are fully adjacent to
+    the Designated Router; each fully adjacent router is identified by
+    its OSPF Router ID.  The Designated Router includes itself in this
+    list. RFC2328, Section 12.4.2 */
+
+  for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+    if ((nbr = rn->info) != NULL)
+      if (nbr->state == NSM_Full || nbr == oi->nbr_self)
+	stream_put_ipv4 (s, nbr->router_id.s_addr);
+}
+
+struct ospf_lsa *
+ospf_network_lsa_new (struct ospf_interface *oi)
+{
+  struct stream *s;
+  struct ospf_lsa *new;
+  struct lsa_header *lsah;
+  int length;
+
+  /* If there are no neighbours on this network (the net is stub),
+     the router does not originate network-LSA (see RFC 12.4.2) */
+  if (oi->full_nbrs == 0)
+    return NULL;
+  
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type2]: Create network-LSA instance");
+
+  /* Create new stream for LSA. */
+  s = stream_new (OSPF_MAX_LSA_SIZE);
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+  lsa_header_set (s, (OPTIONS (oi) | LSA_OPTIONS_GET (oi->area)),
+		  OSPF_NETWORK_LSA, DR (oi));
+
+  /* Set network-LSA body fields. */
+  ospf_network_lsa_body_set (s, oi);
+
+  /* Set length. */
+  length = stream_get_endp (s);
+  lsah->length = htons (length);
+
+  /* Create OSPF LSA instance. */
+  new = ospf_lsa_new ();
+  new->area = oi->area;
+  SET_FLAG (new->flags, OSPF_LSA_SELF);
+
+  /* Copy LSA to store. */
+  new->data = ospf_lsa_data_new (length);
+  memcpy (new->data, lsah, length);
+  stream_free (s);
+
+  return new;
+}
+
+/* Originate network-LSA. */
+struct ospf_lsa *
+ospf_network_lsa_originate (struct ospf_interface *oi)
+{
+  struct ospf_lsa *new;
+
+  /* Create new network-LSA instance. */
+  new = ospf_network_lsa_new (oi);
+  if (new == NULL)
+    return NULL;
+
+  /* Install LSA to LSDB. */
+  new = ospf_lsa_install (oi, new);
+
+  /* Update LSA origination count. */
+  ospf_top->lsa_originate_count++;
+
+  /* Flooding new LSA through area. */
+  ospf_flood_through_area (oi->area, NULL, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: Originate network-LSA %p",
+		 new->data->type, inet_ntoa (new->data->id), new);
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return new;
+}
+
+int
+ospf_network_lsa_refresh (struct ospf_lsa *lsa, struct ospf_interface *oi)
+{
+  struct ospf_area *area = lsa->area;
+  struct ospf_lsa *new;
+
+  assert (lsa->data);
+
+  /* Delete LSA from neighbor retransmit-list. */
+  ospf_ls_retransmit_delete_nbr_all (area, lsa);
+
+  /* Create new network-LSA instance. */
+  new = ospf_network_lsa_new (oi);
+  if (new == NULL)
+    return -1;
+  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+
+  ospf_lsa_install (oi, new);
+
+  /* Flood LSA through aera. */
+  ospf_flood_through_area (area, NULL, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: network-LSA refresh",
+		 new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return 0;
+}
+
+int
+ospf_network_lsa_refresh_timer (struct thread *t)
+{
+  struct ospf_interface *oi;
+
+  oi = THREAD_ARG (t);
+  oi->t_network_lsa_self = NULL;
+
+  if (oi->network_lsa_self)
+    /* Now refresh network-LSA. */
+    ospf_network_lsa_refresh (oi->network_lsa_self, oi);
+  else
+    /* Newly create network-LSA. */
+    ospf_network_lsa_originate (oi);
+
+  return 0;
+}
+
+void
+ospf_network_lsa_timer_add (struct ospf_interface *oi)
+{
+  /* Keep interface's self-originated network-LSA. */
+  struct ospf_lsa *lsa = oi->network_lsa_self;
+
+  /* Cancel previously schedules network-LSA timer. */
+  if (oi->t_network_lsa_self)
+    if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+      zlog_info ("LSA[Type2]: Cancel previous network-LSA timer");
+  OSPF_TIMER_OFF (oi->t_network_lsa_self);
+
+  /* If network-LSA is originated previously, check the interval time. */
+  if (lsa)
+    {
+      int delay;
+      if ((delay = ospf_lsa_refresh_delay (lsa)) > 0)
+        {
+          oi->t_network_lsa_self =
+            thread_add_timer (master, ospf_network_lsa_refresh_timer,
+			      oi, delay);
+          return;
+        }
+    }
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("Scheduling network-LSA origination right away");
+
+  /* Immediately refresh network-LSA. */
+  oi->t_network_lsa_self =
+    thread_add_event (master, ospf_network_lsa_refresh_timer, oi, 0);
+}
+
+
+void
+stream_put_ospf_metric (struct stream *s, u_int32_t metric_value)
+{
+  u_int32_t metric;
+  char *mp;
+
+  /* Put 0 metric. TOS metric is not supported. */
+  metric = htonl (metric_value);
+  mp = (char *) &metric;
+  mp++;
+  stream_put (s, mp, 3);
+}
+
+/* summary-LSA related functions. */
+void
+ospf_summary_lsa_body_set (struct stream *s, struct prefix *p,
+			   u_int32_t metric)
+{
+  struct in_addr mask;
+
+  masklen2ip (p->prefixlen, &mask);
+
+  /* Put Network Mask. */
+  stream_put_ipv4 (s, mask.s_addr);
+
+  /* Set # TOS. */
+  stream_putc (s, (u_char) 0);
+
+  /* Set metric. */
+  stream_put_ospf_metric (s, metric);
+}
+
+struct ospf_lsa *
+ospf_summary_lsa_new (struct ospf_area *area, struct prefix *p,
+		      u_int32_t metric, struct in_addr id)
+{
+  struct stream *s;
+  struct ospf_lsa *new;
+  struct lsa_header *lsah;
+  int length;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type3]: Create summary-LSA instance");
+
+  /* Create new stream for LSA. */
+  s = stream_new (OSPF_MAX_LSA_SIZE);
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+  lsa_header_set (s, LSA_OPTIONS_GET (area), OSPF_SUMMARY_LSA, id);
+
+  /* Set summary-LSA body fields. */
+  ospf_summary_lsa_body_set (s, p, metric);
+
+  /* Set length. */
+  length = stream_get_endp (s);
+  lsah->length = htons (length);
+
+  /* Create OSPF LSA instance. */
+  new = ospf_lsa_new ();
+  new->area = area;
+  SET_FLAG (new->flags, OSPF_LSA_SELF);
+
+  /* Copy LSA to store. */
+  new->data = ospf_lsa_data_new (length);
+  memcpy (new->data, lsah, length);
+  stream_free (s);
+
+  return new;
+}
+
+/* Originate Summary-LSA. */
+struct ospf_lsa *
+ospf_summary_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, 
+			    struct ospf_area *area)
+{
+  struct ospf_lsa *new;
+  struct in_addr id;
+  
+  id = ospf_lsa_unique_id (area->lsdb, OSPF_SUMMARY_LSA, p);
+
+  /* Create new summary-LSA instance. */
+  new = ospf_summary_lsa_new (area, (struct prefix *) p, metric, id);
+
+  /* Instlal LSA to LSDB. */
+  new = ospf_lsa_install (NULL, new);
+
+  /* Update LSA origination count. */
+  ospf_top->lsa_originate_count++;
+
+  /* Flooding new LSA through area. */
+  ospf_flood_through_area (area, NULL, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: Originate summary-LSA %p",
+		 new->data->type, inet_ntoa (new->data->id), new);
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return new;
+}
+
+struct ospf_lsa*
+ospf_summary_lsa_refresh (struct ospf_lsa *lsa)
+{
+  struct ospf_lsa *new;
+  struct summary_lsa *sl;
+  struct prefix p;
+  
+  /* Sanity check. */
+  assert (lsa->data);
+
+  sl = (struct summary_lsa *)lsa->data;
+  p.prefixlen = ip_masklen (sl->mask);
+  new = ospf_summary_lsa_new (lsa->area, &p, GET_METRIC (sl->metric),
+			      sl->header.id);
+
+  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+  
+  /* Re-calculate checksum. */
+  ospf_lsa_checksum (new->data);
+
+  ospf_lsa_install (NULL, new);
+  
+  /* Flood LSA through AS. */
+  ospf_flood_through_area (new->area, NULL, new);
+
+  /* Debug logging. */
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: summary-LSA refresh",
+		 new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_header_dump (new->data);
+    }
+  
+  return new;
+}
+
+
+/* summary-ASBR-LSA related functions. */
+void
+ospf_summary_asbr_lsa_body_set (struct stream *s, struct prefix *p,
+				u_int32_t metric)
+{
+  struct in_addr mask;
+
+  masklen2ip (p->prefixlen, &mask);
+
+  /* Put Network Mask. */
+  stream_put_ipv4 (s, mask.s_addr);
+
+  /* Set # TOS. */
+  stream_putc (s, (u_char) 0);
+
+  /* Set metric. */
+  stream_put_ospf_metric (s, metric);
+}
+
+struct ospf_lsa *
+ospf_summary_asbr_lsa_new (struct ospf_area *area, struct prefix *p,
+			   u_int32_t metric, struct in_addr id)
+{
+  struct stream *s;
+  struct ospf_lsa *new;
+  struct lsa_header *lsah;
+  int length;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type3]: Create summary-LSA instance");
+
+  /* Create new stream for LSA. */
+  s = stream_new (OSPF_MAX_LSA_SIZE);
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+  lsa_header_set (s, LSA_OPTIONS_GET (area), OSPF_ASBR_SUMMARY_LSA, id);
+
+  /* Set summary-LSA body fields. */
+  ospf_summary_asbr_lsa_body_set (s, p, metric);
+
+  /* Set length. */
+  length = stream_get_endp (s);
+  lsah->length = htons (length);
+
+  /* Create OSPF LSA instance. */
+  new = ospf_lsa_new ();
+  new->area = area;
+  SET_FLAG (new->flags, OSPF_LSA_SELF);
+
+  /* Copy LSA to store. */
+  new->data = ospf_lsa_data_new (length);
+  memcpy (new->data, lsah, length);
+  stream_free (s);
+
+  return new;
+}
+
+/* Originate summary-ASBR-LSA. */
+struct ospf_lsa *
+ospf_summary_asbr_lsa_originate (struct prefix_ipv4 *p, u_int32_t metric, 
+				 struct ospf_area *area)
+{
+  struct ospf_lsa *new;
+  struct in_addr id;
+  
+  id = ospf_lsa_unique_id (area->lsdb, OSPF_ASBR_SUMMARY_LSA, p);
+
+  /* Create new summary-LSA instance. */
+  new = ospf_summary_asbr_lsa_new (area, (struct prefix *) p, metric, id);
+
+  /* Install LSA to LSDB. */
+  new = ospf_lsa_install (NULL, new);
+  
+  /* Update LSA origination count. */
+  ospf_top->lsa_originate_count++;
+
+  /* Flooding new LSA through area. */
+  ospf_flood_through_area (area, NULL, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: Originate summary-ASBR-LSA %p",
+		 new->data->type, inet_ntoa (new->data->id), new);
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return new;
+}
+
+struct ospf_lsa*
+ospf_summary_asbr_lsa_refresh (struct ospf_lsa *lsa)
+{
+  struct ospf_lsa *new;
+  struct summary_lsa *sl;
+  struct prefix p;
+
+  /* Sanity check. */
+  assert (lsa->data);
+
+  sl = (struct summary_lsa *)lsa->data;
+  p.prefixlen = ip_masklen (sl->mask);
+  new = ospf_summary_asbr_lsa_new (lsa->area, &p, GET_METRIC (sl->metric),
+				   sl->header.id);
+  
+  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+  
+  /* Re-calculate checksum. */
+  ospf_lsa_checksum (new->data);
+
+  ospf_lsa_install (NULL, new);
+  
+  /* Flood LSA through area. */
+  ospf_flood_through_area (new->area, NULL, new);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: summary-ASBR-LSA refresh",
+		 new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return new;
+}
+
+/* AS-external-LSA related functions. */
+
+/* Get nexthop for AS-external-LSAs.  Return nexthop if its interface
+   is connected, else 0*/
+struct in_addr
+ospf_external_lsa_nexthop_get (struct in_addr nexthop)
+{
+  struct in_addr fwd;
+  struct prefix nh;
+  /* struct route_node *rn; */
+  listnode n1;
+
+  fwd.s_addr = 0;
+
+  if (!nexthop.s_addr)
+    return fwd;
+
+  /* Check whether nexthop is covered by OSPF network. */
+  nh.family = AF_INET;
+  nh.u.prefix4 = nexthop;
+  nh.prefixlen = IPV4_MAX_BITLEN;
+
+  for (n1 = listhead (ospf_top->oiflist); n1; nextnode (n1))
+    {
+      struct ospf_interface *oi = getdata (n1);
+
+      if (if_is_up (oi->ifp))
+	if (oi->address->family == AF_INET)
+	  if (prefix_match (oi->address, &nh))
+	    return nexthop;
+    }
+
+  return fwd;
+}
+
+#ifdef HAVE_NSSA
+/* NSSA-external-LSA related functions. */
+
+/* Get 1st IP connection for Forward Addr */
+          
+struct in_addr
+ospf_get_ip_from_ifp (struct ospf_interface *oi)
+{
+  struct in_addr fwd;
+
+  fwd.s_addr = 0;
+
+  if (if_is_up (oi->ifp))
+    return oi->address->u.prefix4;
+  
+  return fwd;
+}
+
+/* Get 1st IP connection for Forward Addr */
+struct in_addr
+ospf_get_nssa_ip (void)
+{
+  struct in_addr fwd;
+  listnode n1;
+
+  fwd.s_addr = 0;
+
+
+  for (n1 = listhead (ospf_top->oiflist); n1; nextnode (n1))
+    {
+      struct ospf_interface *oi = getdata (n1);
+
+      if (if_is_up (oi->ifp))
+	if (oi->area->external_routing == OSPF_AREA_NSSA)
+	  if (oi->address && oi->address->family == AF_INET)
+	    return (oi->address->u.prefix4 );
+    }
+
+  return fwd;
+}
+#endif /* HAVE_NSSA */
+
+#define DEFAULT_DEFAULT_METRIC	             20
+#define DEFAULT_DEFAULT_ORIGINATE_METRIC     10
+#define DEFAULT_DEFAULT_ALWAYS_METRIC	      1
+
+#define DEFAULT_METRIC_TYPE		     EXTERNAL_METRIC_TYPE_2
+
+int
+metric_type (u_char src)
+{
+  return (ospf_top->dmetric[src].type < 0 ?
+	  DEFAULT_METRIC_TYPE : ospf_top->dmetric[src].type);
+}
+
+int
+metric_value (u_char src)
+{
+  if (ospf_top->dmetric[src].value < 0)
+    {
+      if (src == DEFAULT_ROUTE)
+	{
+	  if (ospf_top->default_originate == DEFAULT_ORIGINATE_ZEBRA)
+	    return DEFAULT_DEFAULT_ORIGINATE_METRIC;
+	  else
+	    return DEFAULT_DEFAULT_ALWAYS_METRIC;
+	}
+      else if (ospf_top->default_metric < 0)
+	return DEFAULT_DEFAULT_METRIC;
+      else
+	return ospf_top->default_metric;
+    }
+
+  return ospf_top->dmetric[src].value;
+}
+
+/* Set AS-external-LSA body. */
+void
+ospf_external_lsa_body_set (struct stream *s, struct external_info *ei)
+{
+  struct prefix_ipv4 *p = &ei->p;
+  struct in_addr mask, fwd_addr;
+  u_int32_t mvalue;
+  int mtype;
+  int type;
+
+  /* Put Network Mask. */
+  masklen2ip (p->prefixlen, &mask);
+  stream_put_ipv4 (s, mask.s_addr);
+
+  /* If prefix is default, specify DEFAULT_ROUTE. */
+  type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type;
+  
+  mtype = (ROUTEMAP_METRIC_TYPE (ei) != -1) ?
+    ROUTEMAP_METRIC_TYPE (ei) : metric_type (type);
+
+  mvalue = (ROUTEMAP_METRIC (ei) != -1) ?
+    ROUTEMAP_METRIC (ei) : metric_value (type);
+
+  /* Put type of external metric. */
+  stream_putc (s, (mtype == EXTERNAL_METRIC_TYPE_2 ? 0x80 : 0));
+
+  /* Put 0 metric. TOS metric is not supported. */
+  stream_put_ospf_metric (s, mvalue);
+  
+  /* Get forwarding address to nexthop if on the Connection List, else 0. */
+  fwd_addr = ospf_external_lsa_nexthop_get (ei->nexthop);
+
+  /* Put forwarding address. */
+  stream_put_ipv4 (s, fwd_addr.s_addr);
+  
+  /* Put route tag -- This value should be introduced from configuration. */
+  stream_putl (s, 0);
+}
+
+/* Create new external-LSA. */
+struct ospf_lsa *
+ospf_external_lsa_new (struct external_info *ei, struct in_addr *old_id)
+{
+  struct stream *s;
+  struct lsa_header *lsah;
+  struct ospf_lsa *new;
+  struct in_addr id;
+  int length;
+
+  if (ei == NULL)
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+	zlog_warn ("LSA[Type5]: External info is NULL, could not originated");
+      return NULL;
+    }
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type5]: Originate AS-external-LSA instance");
+
+  /* If old Link State ID is specified, refresh LSA with same ID. */
+  if (old_id)
+    id = *old_id;
+  /* Get Link State with unique ID. */
+  else
+    {
+      id = ospf_lsa_unique_id (ospf_top->lsdb, OSPF_AS_EXTERNAL_LSA, &ei->p);
+      if (id.s_addr == 0xffffffff)
+	{
+	  /* Maybe Link State ID not available. */
+	  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+	    zlog_info ("LSA[Type5]: Link ID not available, can't originate");
+	  return NULL;
+	}
+    }
+
+  /* Create new stream for LSA. */
+  s = stream_new (OSPF_MAX_LSA_SIZE);
+  lsah = (struct lsa_header *) STREAM_DATA (s);
+
+  /* Set LSA common header fields. */
+  lsa_header_set (s, OSPF_OPTION_E, OSPF_AS_EXTERNAL_LSA, id);
+
+  /* Set AS-external-LSA body fields. */
+  ospf_external_lsa_body_set (s, ei);
+
+  /* Set length. */
+  length = stream_get_endp (s);
+  lsah->length = htons (length);
+
+  /* Now, create OSPF LSA instance. */
+  new = ospf_lsa_new ();
+  new->area = NULL;
+  SET_FLAG (new->flags, OSPF_LSA_SELF|OSPF_LSA_APPROVED);
+
+  /* Copy LSA data to store, discard stream. */
+  new->data = ospf_lsa_data_new (length);
+  memcpy (new->data, lsah, length);
+  stream_free (s);
+
+  return new;
+}
+
+#ifdef HAVE_NSSA
+/* Set AS-external-LSA body test. */
+void
+ospf_external_lsa_body_test (struct stream *s)
+{
+  struct in_addr mask, fwd_addr;
+  u_int32_t mvalue = 0;
+  /* int mtype;
+     int type; */
+
+  mask.s_addr = 0;
+  fwd_addr.s_addr = 0;
+
+  /* Put Network Mask. */
+  /* masklen2ip (p->prefixlen, &mask); */
+  stream_put_ipv4 (s, mask.s_addr);
+
+  /* If prefix is default, specify DEFAULT_ROUTE. */
+  /* type = is_prefix_default (&ei->p) ? DEFAULT_ROUTE : ei->type;
+  
+  mtype = (ROUTEMAP_METRIC_TYPE (ei) != -1) ?
+  ROUTEMAP_METRIC_TYPE (ei) : metric_type (type);
+
+  mvalue = (ROUTEMAP_METRIC (ei) != -1) ?
+  ROUTEMAP_METRIC (ei) : metric_value (type); */
+
+  /* Put type of external metric. */
+  stream_putc (s,  0);
+
+  /* Put 0 metric. TOS metric is not supported. */
+  stream_put_ospf_metric (s, mvalue);
+  
+ 
+  /*  fwd_addr = ospf_top->router_id; */
+       
+  /* OLD == ospf_external_lsa_nexthop_get (ei->nexthop); */
+
+  /* Put forwarding address. */
+  /* stream_put_ipv4 (s, fwd_addr.s_addr); */
+  stream_put_ipv4 (s, ospf_top->router_id.s_addr);
+  
+  /* Put route tag -- This value should be introduced from configuration. */
+  stream_putl (s, 0);
+}
+
+/* As Type-7 */
+void
+ospf_install_flood_nssa (struct ospf_lsa *lsa, struct external_info *ei)
+{
+  struct ospf_lsa *new2;
+  struct as_external_lsa *extlsa;
+
+  /* NSSA Originate or Refresh (If anyNSSA)
+
+  LSA is self-originated. And just installed as Type-5.
+  Additionally, install as Type-7 LSDB for every attached NSSA.
+
+  P-Bit controls which ABR performs translation to outside world; If
+  we are an ABR....do not set the P-bit, because we send the Type-5,
+  not as the ABR Translator, but as the ASBR owner within the AS!
+
+  If we are NOT ABR, Flood through NSSA as Type-7 w/P-bit set.  The
+  elected ABR Translator will see the P-bit, Translate, and re-flood.
+
+  Later, ABR_TASK and P-bit will scan Type-7 LSDB and translate to
+  Type-5's to non-NSSA Areas.  (it will also attempt a re-install) */
+
+  /* make lsa duplicate, lock=1 */
+  new2 = ospf_lsa_dup(lsa);
+
+  /* make type-7 */
+  new2->data->type  = OSPF_AS_NSSA_LSA;
+
+  /* set P-bit if not ABR */
+  if (! OSPF_IS_ABR)
+    {
+      SET_FLAG(new2->data->options, OSPF_OPTION_NP);
+
+      /* set non-zero FWD ADDR 
+
+      draft-ietf-ospf-nssa-update-09.txt
+
+      if the network between the NSSA AS boundary router and the
+      adjacent AS is advertised into OSPF as an internal OSPF route, 
+      the forwarding address should be the next op address as is cu
+      currently done with type-5 LSAs.  If the intervening network is 
+      not adversited into OSPF as an internal OSPF route and the 
+      type-7 LSA's P-bit is set a forwarding address should be 
+      selected from one of the router's active OSPF inteface addresses
+      which belong to the NSSA.  If no such addresses exist, then
+      no type-7 LSA's with the P-bit set should originate from this
+      router.   */
+
+      extlsa = (struct as_external_lsa *)(lsa->data);
+
+      if (extlsa->e[0].fwd_addr.s_addr == 0) 
+	extlsa->e[0].fwd_addr = ospf_get_nssa_ip(); /* this NSSA area in ifp */
+
+      if (IS_DEBUG_OSPF_NSSA)
+	if (extlsa->e[0].fwd_addr.s_addr == 0) 
+	  {
+	    zlog_info ("LSA[Type-7]: Could not build FWD-ADDR");
+	    ospf_lsa_discard(new2);
+	    return;
+	  }
+    }
+
+  /* Re-calculate checksum. */
+  ospf_lsa_checksum (new2->data);
+
+  /* install also as Type-7 */
+  ospf_lsa_install (NULL, new2);   /* Remove Old, Lock New = 2 */
+
+  /* will send each copy, lock=2+n */
+  ospf_flood_through_as (NULL, new2); /* all attached NSSA's, no AS/STUBs */
+
+  /* last send, lock=2 LSA is now permanent in Type-7 LSDB */
+  /* It has the same ID as it's Type-5 Counter-Part */
+ 
+}
+#endif /* HAVE_NSSA */
+
+int
+is_prefix_default (struct prefix_ipv4 *p)
+{
+  struct prefix_ipv4 q;
+
+  q.family = AF_INET;
+  q.prefix.s_addr = 0;
+  q.prefixlen = 0;
+
+  return prefix_same ((struct prefix *) p, (struct prefix *) &q);
+}
+
+/* Originate an AS-external-LSA, install and flood. */
+struct ospf_lsa *
+ospf_external_lsa_originate (struct external_info *ei)
+{
+  struct ospf_lsa *new;
+
+  /* Added for NSSA project....
+
+       External LSAs are originated in ASBRs as usual, but for NSSA systems.
+     there is the global Type-5 LSDB and a Type-7 LSDB installed for
+     every area.  The Type-7's are flooded to every IR and every ABR; We
+     install the Type-5 LSDB so that the normal "refresh" code operates
+     as usual, and flag them as not used during ASE calculations.  The
+     Type-7 LSDB is used for calculations.  Each Type-7 has a Forwarding
+     Address of non-zero.
+
+     If an ABR is the elected NSSA translator, following SPF and during
+     the ABR task it will translate all the scanned Type-7's, with P-bit
+     ON and not-self generated, and translate to Type-5's throughout the
+     non-NSSA/STUB AS.
+
+     A difference in operation depends whether this ASBR is an ABR
+     or not.  If not an ABR, the P-bit is ON, to indicate that any
+     elected NSSA-ABR can perform its translation.
+
+     If an ABR, the P-bit is OFF;  No ABR will perform translation and
+     this ASBR will flood the Type-5 LSA as usual.
+
+     For the case where this ASBR is not an ABR, the ASE calculations
+     are based on the Type-5 LSDB;  The Type-7 LSDB exists just to
+     demonstrate to the user that there are LSA's that belong to any
+     attached NSSA.
+
+     Finally, it just so happens that when the ABR is translating every
+     Type-7 into Type-5, it installs it into the Type-5 LSDB as an
+     approved Type-5 (translated from Type-7);  at the end of translation
+     if any Translated Type-5's remain unapproved, then they must be
+     flushed from the AS.
+
+     */
+  
+  /* Check the AS-external-LSA should be originated. */
+  if (!ospf_redistribute_check (ei, NULL))
+    return NULL;
+  
+  /* Create new AS-external-LSA instance. */
+  if ((new = ospf_external_lsa_new (ei, NULL)) == NULL)
+    {
+      if (IS_DEBUG_OSPF_EVENT)
+	zlog_info ("LSA[Type5:%s]: Could not originate AS-external-LSA",
+		   inet_ntoa (ei->p.prefix));
+      return NULL;
+    }
+
+  /* Install newly created LSA into Type-5 LSDB, lock = 1. */
+  ospf_lsa_install (NULL, new);
+
+  /* Update LSA origination count. */
+  ospf_top->lsa_originate_count++;
+
+  /* Flooding new LSA. only to AS (non-NSSA/STUB) */
+  ospf_flood_through_as (NULL, new);
+
+#ifdef HAVE_NSSA
+  /* If there is any attached NSSA, do special handling */
+  if (ospf_top->anyNSSA)
+    ospf_install_flood_nssa (new, ei); /* Install/Flood Type-7 to all NSSAs */
+#endif /* HAVE_NSSA */
+
+  /* Debug logging. */
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: Originate AS-external-LSA %p",
+		 new->data->type, inet_ntoa (new->data->id), new);
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return new;
+}
+
+/* Originate AS-external-LSA from external info with initial flag. */
+int
+ospf_external_lsa_originate_timer (struct thread *t)
+{
+  struct route_node *rn;
+  struct external_info *ei;
+  struct route_table *rt;
+  int type;
+
+  ospf_top->t_external_lsa = NULL;
+  type = THREAD_VAL (t);
+
+  /* Originate As-external-LSA from all type of distribute source. */
+  if ((rt = EXTERNAL_INFO (type)))
+    for (rn = route_top (rt); rn; rn = route_next (rn))
+      if ((ei = rn->info) != NULL)
+	if (!is_prefix_default ((struct prefix_ipv4 *)&ei->p))
+	  if (!ospf_external_lsa_originate (ei))
+	    zlog_warn ("LSA: AS-external-LSA was not originated.");
+  
+  return 0;
+}
+
+struct external_info *
+ospf_default_external_info ()
+{
+  int type;
+  struct route_node *rn;
+  struct prefix_ipv4 p;
+  
+  p.family = AF_INET;
+  p.prefix.s_addr = 0;
+  p.prefixlen = 0;
+
+  /* First, lookup redistributed default route. */
+  for (type = 0; type <= ZEBRA_ROUTE_MAX; type++)
+    if (EXTERNAL_INFO (type) && type != ZEBRA_ROUTE_OSPF)
+      {
+	rn = route_node_lookup (EXTERNAL_INFO (type), (struct prefix *) &p);
+	if (rn != NULL)
+	  {
+	    route_unlock_node (rn);
+	    assert (rn->info);
+	    if (ospf_redistribute_check (rn->info, NULL))
+	      return rn->info;
+	  }
+      }
+
+  return NULL;
+}
+
+int
+ospf_default_originate_timer (struct thread *t)
+{
+  int *origin;
+  struct prefix_ipv4 p;
+  struct in_addr nexthop;
+  struct external_info *ei;
+  
+  /* Get originate flags. */
+  origin = THREAD_ARG (t);
+
+  p.family = AF_INET;
+  p.prefix.s_addr = 0;
+  p.prefixlen = 0;
+
+  if (*origin == DEFAULT_ORIGINATE_ALWAYS)
+    {
+      /* If there is no default route via redistribute,
+	 then originate AS-external-LSA with nexthop 0 (self). */
+      nexthop.s_addr = 0;
+      ospf_external_info_add (DEFAULT_ROUTE, p, 0, nexthop);
+    }
+
+  if ((ei = ospf_default_external_info ()))
+    ospf_external_lsa_originate (ei);
+  
+  return 0;
+}
+
+/* Flush an AS-external-LSA from LSDB and routing domain. */
+void
+ospf_external_lsa_flush (u_char type, struct prefix_ipv4 *p,
+			 unsigned int ifindex, struct in_addr nexthop)
+{
+  struct ospf_lsa *lsa;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+    zlog_info ("LSA: Flushing AS-external-LSA %s/%d",
+	       inet_ntoa (p->prefix), p->prefixlen);
+
+  /* First lookup LSA from LSDB. */
+  if (!(lsa = ospf_external_info_find_lsa (p)))
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+	zlog_warn ("LSA: There is no such AS-external-LSA %s/%d in LSDB",
+		   inet_ntoa (p->prefix), p->prefixlen);
+      return;
+    }
+
+  /* Sweep LSA from Link State Retransmit List. */
+  ospf_ls_retransmit_delete_nbr_all (NULL, lsa);
+
+  /* There must be no self-originated LSA in rtrs_external. */
+#if 0
+  /* Remove External route from Zebra. */
+  ospf_zebra_delete ((struct prefix_ipv4 *) p, &nexthop);
+#endif
+
+  if (!IS_LSA_MAXAGE (lsa))
+    {
+      /* Unregister LSA from Refresh queue. */
+      ospf_refresher_unregister_lsa (ospf_top, lsa);
+
+      /* Flush AS-external-LSA through AS. */
+      ospf_flush_through_as (lsa);
+    }
+
+  if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+    zlog_info ("ospf_external_lsa_flush(): stop");
+}
+
+void
+ospf_external_lsa_refresh_default ()
+{
+  struct prefix_ipv4 p;
+  struct external_info *ei;
+  struct ospf_lsa *lsa;
+
+  p.family = AF_INET;
+  p.prefixlen = 0;
+  p.prefix.s_addr = 0;
+
+  ei = ospf_default_external_info ();
+  lsa = ospf_external_info_find_lsa (&p);
+
+  if (ei)
+    {
+      if (lsa)
+	{
+	  if (IS_DEBUG_OSPF_EVENT)
+	    zlog_info ("LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", lsa);
+	  ospf_external_lsa_refresh (lsa, ei, LSA_REFRESH_FORCE);
+	}
+      else
+	{
+	  if (IS_DEBUG_OSPF_EVENT)
+	    zlog_info ("LSA[Type5:0.0.0.0]: Originate AS-external-LSA");
+	  ospf_external_lsa_originate (ei);
+	}
+    }
+  else
+    {
+      if (lsa)
+	{
+	  if (IS_DEBUG_OSPF_EVENT)
+	    zlog_info ("LSA[Type5:0.0.0.0]: Flush AS-external-LSA");
+	  ospf_lsa_flush_as (lsa);
+	}
+    }
+}
+
+void
+ospf_external_lsa_refresh_type (u_char type, int force)
+{
+  struct route_node *rn;
+  struct external_info *ei;
+
+  if (type != DEFAULT_ROUTE)
+    if (EXTERNAL_INFO(type))
+      /* Refresh each redistributed AS-external-LSAs. */
+      for (rn = route_top (EXTERNAL_INFO (type)); rn; rn = route_next (rn))
+	if ((ei = rn->info))
+	  if (!is_prefix_default (&ei->p))
+	    {
+	      struct ospf_lsa *lsa;
+
+	      if ((lsa = ospf_external_info_find_lsa (&ei->p)))
+		ospf_external_lsa_refresh (lsa, ei, force);
+	      else
+		ospf_external_lsa_originate (ei);
+	    }
+}
+
+/* Refresh AS-external-LSA. */
+void
+ospf_external_lsa_refresh (struct ospf_lsa *lsa,
+			   struct external_info *ei, int force)
+{
+  struct ospf_lsa *new;
+  int changed;
+  
+  /* Check the AS-external-LSA should be originated. */
+  if (!ospf_redistribute_check (ei, &changed))
+    {
+      ospf_external_lsa_flush (ei->type, &ei->p, ei->ifindex, ei->nexthop);
+      return;
+    }
+
+  if (!changed && !force)
+    return;
+
+  /* Delete LSA from neighbor retransmit-list. */
+  ospf_ls_retransmit_delete_nbr_all (NULL, lsa);
+
+  /* Unregister AS-external-LSA from refresh-list. */
+  ospf_refresher_unregister_lsa (ospf_top, lsa);
+
+  new = ospf_external_lsa_new (ei, &lsa->data->id);
+  
+  if (new == NULL)
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+	zlog_warn ("LSA[Type%d:%s]: Could not be refreshed", lsa->data->type,
+		   inet_ntoa (lsa->data->id));
+      return;
+    }
+  
+  new->data->ls_seqnum = lsa_seqnum_increment (lsa);
+
+  /* Record timestamp. */
+  gettimeofday (&new->tv_orig, NULL);
+
+  /* Re-calculate checksum. */
+  ospf_lsa_checksum (new->data);
+
+  ospf_lsa_install (NULL, new);	/* As type-5. */
+
+  /* Flood LSA through AS. */
+  ospf_flood_through_as (NULL, new);
+
+#ifdef HAVE_NSSA
+  /* If any attached NSSA, install as Type-7, flood to all NSSA Areas */
+  if (ospf_top->anyNSSA)
+    ospf_install_flood_nssa (new, ei); /* Install/Flood per new rules */
+#endif /* HAVE_NSSA */
+
+  /* Register slef-originated LSA to refresh queue. */
+  ospf_refresher_register_lsa (ospf_top, new);
+
+  /* Debug logging. */
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    {
+      zlog_info ("LSA[Type%d:%s]: AS-external-LSA refresh",
+		 new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_header_dump (new->data);
+    }
+
+  return;
+}
+
+
+/* LSA installation functions. */
+
+/* Install router-LSA to an area. */
+struct ospf_lsa *
+ospf_router_lsa_install (struct ospf_lsa *new, int rt_recalc)
+{
+  struct ospf_area *area = new->area;
+
+  /* RFC 2328 Section 13.2 Router-LSAs and network-LSAs
+     The entire routing table must be recalculated, starting with
+     the shortest path calculations for each area (not just the
+     area whose link-state database has changed). 
+  */
+  if (rt_recalc)
+    ospf_spf_calculate_schedule();
+
+  if (IS_LSA_SELF (new))
+    {
+      /* Set router-LSA refresh timer. */
+      OSPF_TIMER_OFF (area->t_router_lsa_self);
+      OSPF_AREA_TIMER_ON (area->t_router_lsa_self,
+			  ospf_router_lsa_timer, OSPF_LS_REFRESH_TIME);
+      
+      /* Set self-originated router-LSA. */
+      ospf_lsa_unlock (area->router_lsa_self);
+      area->router_lsa_self = ospf_lsa_lock (new);
+
+      if (IS_DEBUG_OSPF (lsa, LSA_INSTALL))
+	zlog_info("LSA[Type%d]: ID %s is self-originated",
+		  new->data->type, inet_ntoa (new->data->id));
+    }
+
+  return new;
+}
+
+#define OSPF_INTERFACE_TIMER_ON(T,F,V) \
+	if (!(T)) \
+	  (T) = thread_add_timer (master, (F), oi, (V))
+
+/* Install network-LSA to an area. */
+struct ospf_lsa *
+ospf_network_lsa_install (struct ospf_interface *oi, 
+			  struct ospf_lsa *new,
+			  int rt_recalc)
+{
+
+  /* RFC 2328 Section 13.2 Router-LSAs and network-LSAs
+     The entire routing table must be recalculated, starting with
+     the shortest path calculations for each area (not just the
+     area whose link-state database has changed). 
+  */
+  if (rt_recalc)
+    ospf_spf_calculate_schedule();
+
+  /* We supposed that when LSA is originated by us, we pass the int
+     for which it was originated. If LSA was received by flooding,
+     the RECEIVED flag is set, so we do not link the LSA to the int. */
+  if (IS_LSA_SELF (new) && !CHECK_FLAG (new->flags, OSPF_LSA_RECEIVED))
+    {
+      /* Set LSRefresh timer. */
+      OSPF_TIMER_OFF (oi->t_network_lsa_self);
+
+      OSPF_INTERFACE_TIMER_ON (oi->t_network_lsa_self,
+			       ospf_network_lsa_refresh_timer,
+			       OSPF_LS_REFRESH_TIME);
+
+      ospf_lsa_unlock (oi->network_lsa_self);
+      oi->network_lsa_self = ospf_lsa_lock (new);
+    }
+
+  return new;
+}
+
+/* Install summary-LSA to an area. */
+struct ospf_lsa *
+ospf_summary_lsa_install (struct ospf_lsa *new, int rt_recalc)
+{
+
+  if (rt_recalc && !IS_LSA_SELF (new))
+    {
+      /* RFC 2328 Section 13.2 Summary-LSAs
+	 The best route to the destination described by the summary-
+	 LSA must be recalculated (see Section 16.5).  If this
+	 destination is an AS boundary router, it may also be
+	 necessary to re-examine all the AS-external-LSAs.
+      */
+
+#if 0
+      /* This doesn't exist yet... */
+      ospf_summary_incremental_update(new); */
+#else /* #if 0 */
+      ospf_spf_calculate_schedule();
+#endif /* #if 0 */
+ 
+      if (IS_DEBUG_OSPF (lsa, LSA_INSTALL))
+	zlog_info ("ospf_summary_lsa_install(): SPF scheduled");
+    }
+
+  if (IS_LSA_SELF (new))
+    ospf_refresher_register_lsa (ospf_top, new);
+
+  return new;
+}
+
+/* Install ASBR-summary-LSA to an area. */
+struct ospf_lsa *
+ospf_summary_asbr_lsa_install (struct ospf_lsa *new, int rt_recalc)
+{
+  if (rt_recalc && !IS_LSA_SELF (new))
+    {
+      /* RFC 2328 Section 13.2 Summary-LSAs
+	 The best route to the destination described by the summary-
+	 LSA must be recalculated (see Section 16.5).  If this
+	 destination is an AS boundary router, it may also be
+	 necessary to re-examine all the AS-external-LSAs.
+      */
+#if 0
+      /* These don't exist yet... */
+      ospf_summary_incremental_update(new);
+      /* Isn't this done by the above call? 
+	 - RFC 2328 Section 16.5 implies it should be */
+      /* ospf_ase_calculate_schedule(); */
+#else  /* #if 0 */
+      ospf_spf_calculate_schedule();
+#endif /* #if 0 */
+    }
+
+  /* register LSA to refresh-list. */
+  if (IS_LSA_SELF (new))
+    ospf_refresher_register_lsa (ospf_top, new);
+
+  return new;
+}
+
+/* Install AS-external-LSA. */
+struct ospf_lsa *
+ospf_external_lsa_install (struct ospf_lsa *new, int rt_recalc)
+{
+  ospf_ase_register_external_lsa (new, ospf_top);
+  /* If LSA is not self-originated, calculate an external route. */
+  if (rt_recalc)
+    {
+      /* RFC 2328 Section 13.2 AS-external-LSAs
+            The best route to the destination described by the AS-
+            external-LSA must be recalculated (see Section 16.6).
+      */
+
+      if (!IS_LSA_SELF (new))
+	ospf_ase_incremental_update (new, ospf_top);
+    }
+
+  /* Register self-originated LSA to refresh queue. */
+  if (IS_LSA_SELF (new))
+    ospf_refresher_register_lsa (ospf_top, new);
+
+  return new;
+}
+
+void
+ospf_discard_from_db (struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
+{
+  struct ospf_lsa *old;
+  
+  old = ospf_lsdb_lookup (lsdb, lsa);
+
+  if (!old)
+    return;
+
+  if (old->refresh_list >= 0)
+    ospf_refresher_unregister_lsa (ospf_top, old);
+
+  ospf_ls_retransmit_delete_nbr_all (old->area, old);
+
+  switch (old->data->type)
+    {
+    case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      ospf_ase_unregister_external_lsa (old, ospf_top);
+      break;
+    default:
+      break;
+    }
+
+  ospf_lsa_maxage_delete (old);
+  ospf_lsa_discard (old);
+}
+
+/* callback for foreach_lsa */
+int
+ospf_lsa_discard_callback (struct ospf_lsa *lsa, void *p, int i)
+{
+#ifdef HAVE_NSSA
+  /* Removed: Stay away from any Local Translated Type-7 LSAs */
+  /* if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
+     return 0; */
+#endif /* HAVE_NSSA */
+  ospf_discard_from_db ((struct ospf_lsdb *)p, lsa);
+  return 0;
+}
+
+struct ospf_lsa *
+ospf_lsa_install (struct ospf_interface *oi, struct ospf_lsa *lsa)
+{
+  struct ospf_lsa *new = NULL;
+  struct ospf_lsa *old = NULL;
+  struct ospf_lsdb *lsdb = NULL;
+  int rt_recalc;
+
+  /* Set LSDB. */
+  switch (lsa->data->type)
+    {
+    case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      lsdb = ospf_top->lsdb;
+      break;
+    default:
+      lsdb = lsa->area->lsdb;
+      break;
+    }
+
+#ifdef HAVE_NSSA
+  if (IS_DEBUG_OSPF_NSSA)
+    {
+      zlog_info ("LSA[Installing]: Type-%d ", lsa->data->type);
+
+      if  (lsa->data->type == OSPF_AS_NSSA_LSA )
+	zlog_info ("NSSA LSA AREA = %s", inet_ntoa (lsa->area->area_id));
+    }
+#endif /* HAVE_NSSA */
+
+  assert (lsdb);
+
+  /*  RFC 2328 13.2.  Installing LSAs in the database
+
+        Installing a new LSA in the database, either as the result of
+        flooding or a newly self-originated LSA, may cause the OSPF
+        routing table structure to be recalculated.  The contents of the
+        new LSA should be compared to the old instance, if present.  If
+        there is no difference, there is no need to recalculate the
+        routing table. When comparing an LSA to its previous instance,
+        the following are all considered to be differences in contents:
+
+            o   The LSA's Options field has changed.
+
+            o   One of the LSA instances has LS age set to MaxAge, and
+                the other does not.
+
+            o   The length field in the LSA header has changed.
+
+            o   The body of the LSA (i.e., anything outside the 20-byte
+                LSA header) has changed. Note that this excludes changes
+                in LS Sequence Number and LS Checksum.
+
+  */
+  /* Look up old LSA and determine if any SPF calculation or incremental
+     update is needed */
+  old = ospf_lsdb_lookup (lsdb, lsa);
+
+  /* Do comparision and record if recalc needed. */
+  rt_recalc = 0;
+  if (  old == NULL || ospf_lsa_different(old, lsa))
+    rt_recalc = 1;
+
+  /* discard old LSA from LSDB */
+  if (old != NULL)
+    ospf_discard_from_db (lsdb, lsa);
+
+  /* Insert LSA to LSDB. */
+  ospf_lsdb_add (lsdb, lsa);
+  lsa->lsdb = lsdb;
+
+  /* Calculate Checksum if self-originated?. */
+  if (IS_LSA_SELF (lsa))
+    ospf_lsa_checksum (lsa->data);
+
+  /* Do LSA specific installation process. */
+  switch (lsa->data->type)
+    {
+    case OSPF_ROUTER_LSA:
+      new = ospf_router_lsa_install (lsa, rt_recalc);
+      break;
+    case OSPF_NETWORK_LSA:
+      assert (oi);
+      new = ospf_network_lsa_install (oi, lsa, rt_recalc);
+      break;
+    case OSPF_SUMMARY_LSA:
+      new = ospf_summary_lsa_install (lsa, rt_recalc);
+      break;
+    case OSPF_ASBR_SUMMARY_LSA:
+      new = ospf_summary_asbr_lsa_install (lsa, rt_recalc);
+      break;
+    case OSPF_AS_EXTERNAL_LSA:
+      new = ospf_external_lsa_install (lsa, rt_recalc);
+      break;
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+    case OSPF_OPAQUE_AS_LSA:
+      new = ospf_opaque_lsa_install (lsa, rt_recalc);
+      break;
+#endif /* HAVE_OPAQUE_LSA */
+    default: /* NSSA, or type-6,8,9....nothing special */
+#ifdef HAVE_NSSA
+      new = ospf_external_lsa_install (lsa, rt_recalc);
+#endif /* HAVE_NSSA */
+      break;
+    }
+
+  if (new == NULL)
+    return new;  /* Installation failed, cannot proceed further -- endo. */
+
+  /* Debug logs. */
+  if (IS_DEBUG_OSPF (lsa, LSA_INSTALL))
+    {
+      char area_str[INET_ADDRSTRLEN];
+
+      switch (lsa->data->type)
+        {
+        case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+        case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+          zlog_info ("LSA[%s]: Install %s",
+                 dump_lsa_key (new),
+                 LOOKUP (ospf_lsa_type_msg, new->data->type));
+          break;
+        default:
+	  strcpy (area_str, inet_ntoa (new->area->area_id));
+          zlog_info ("LSA[%s]: Install %s to Area %s",
+                 dump_lsa_key (new),
+                 LOOKUP (ospf_lsa_type_msg, new->data->type), area_str);
+          break;
+        }
+    }
+
+  /* If received LSA' ls_age is MaxAge, set LSA on MaxAge LSA list. */
+  if (IS_LSA_MAXAGE (new) && !IS_LSA_SELF (new))
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+	zlog_info ("LSA[Type%d:%s]: Install LSA, MaxAge",
+		   new->data->type, inet_ntoa (new->data->id));
+      ospf_lsa_maxage (lsa);
+    }
+
+  return new;
+}
+
+
+int
+ospf_check_nbr_status ()
+{
+  listnode node;
+
+  for (node = listhead (ospf_top->oiflist); node; node = nextnode (node))
+    {
+      struct ospf_interface *oi = getdata (node);
+      struct route_node *rn;
+      struct ospf_neighbor *nbr;
+
+      if (ospf_if_is_enable (oi))
+	for (rn = route_top (oi->nbrs); rn; rn = route_next (rn))
+          if ((nbr = rn->info) != NULL)
+	    if (nbr->state == NSM_Exchange || nbr->state == NSM_Loading)
+	      {
+		route_unlock_node (rn);
+		return 0;
+	      }
+    }
+
+  return 1;
+}
+
+
+#ifdef ORIGINAL_CODING
+/* This function flood the maxaged LSA to DR. */
+void
+ospf_maxage_flood (struct ospf_lsa *lsa)
+{
+  switch (lsa->data->type)
+    {
+    case OSPF_ROUTER_LSA:
+    case OSPF_NETWORK_LSA:
+    case OSPF_SUMMARY_LSA:
+    case OSPF_ASBR_SUMMARY_LSA:
+#ifdef HAVE_NSSA
+    case OSPF_AS_NSSA_LSA:
+#endif /* HAVE_NSSA */
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      ospf_flood_through_area (lsa->area, NULL, lsa);
+      break;
+    case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      ospf_flood_through_as (NULL, lsa);
+      break;
+    default:
+      break;
+    }
+}
+#endif /* ORIGINAL_CODING */
+
+int
+ospf_maxage_lsa_remover (struct thread *thread)
+{
+  listnode node;
+  listnode next;
+  int reschedule = 0;
+
+  ospf_top->t_maxage = NULL;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+    zlog_info ("LSA[MaxAge]: remover Start");
+
+  reschedule = !ospf_check_nbr_status ();
+
+  if (!reschedule)
+    for (node = listhead (ospf_top->maxage_lsa); node; node = next)
+      {
+        struct ospf_lsa *lsa = getdata (node);
+        next = node->next;
+
+        if (lsa->retransmit_counter > 0)
+          {
+            reschedule = 1;
+            continue;
+          }
+
+        /* Remove LSA from the LSDB */
+        if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF))
+          if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+            zlog_info ("LSA[Type%d:%s]: This LSA is self-originated: ",
+                       lsa->data->type, inet_ntoa (lsa->data->id));
+
+        if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+          zlog_info ("LSA[Type%d:%s]: MaxAge LSA removed from list",
+                     lsa->data->type, inet_ntoa (lsa->data->id));
+
+	/* Flood max age LSA. */
+#ifdef ORIGINAL_CODING
+	ospf_maxage_flood (lsa);
+#else /* ORIGINAL_CODING */
+        ospf_flood_through (NULL, lsa);
+#endif /* ORIGINAL_CODING */
+
+	/* Remove from lsdb. */
+        ospf_discard_from_db (lsa->lsdb, lsa);
+        ospf_lsdb_delete (lsa->lsdb, lsa);
+      }
+
+  /*    A MaxAge LSA must be removed immediately from the router's link
+        state database as soon as both a) it is no longer contained on any
+        neighbor Link state retransmission lists and b) none of the router's
+        neighbors are in states Exchange or Loading. */
+  if (reschedule)
+    OSPF_SCHEDULE_MAXAGE (ospf_top->t_maxage, ospf_maxage_lsa_remover);
+
+  return 0;
+}
+
+int
+ospf_lsa_maxage_exist (struct ospf_lsa *new)
+{
+  listnode node;
+
+  for (node = listhead (ospf_top->maxage_lsa); node; nextnode (node))
+    if (((struct ospf_lsa *) node->data) == new)
+      return 1;
+
+  return 0;
+}
+
+void
+ospf_lsa_maxage_delete (struct ospf_lsa *lsa)
+{
+  listnode n;
+
+  if ((n = listnode_lookup (ospf_top->maxage_lsa, lsa)))
+    {
+      list_delete_node (ospf_top->maxage_lsa, n);
+      ospf_lsa_unlock (lsa);
+    }
+}
+
+void
+ospf_lsa_maxage (struct ospf_lsa *lsa)
+{
+  /* When we saw a MaxAge LSA flooded to us, we put it on the list
+     and schedule the MaxAge LSA remover. */
+  if (ospf_lsa_maxage_exist (lsa))
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+	zlog_info ("LSA[Type%d:%s]: %p already exists on MaxAge LSA list",
+		   lsa->data->type, inet_ntoa (lsa->data->id), lsa);
+      return;
+    }
+
+  listnode_add (ospf_top->maxage_lsa, ospf_lsa_lock (lsa));
+
+  if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+    zlog_info ("LSA[%s]: MaxAge LSA remover scheduled.", dump_lsa_key (lsa));
+
+  OSPF_SCHEDULE_MAXAGE (ospf_top->t_maxage, ospf_maxage_lsa_remover);
+}
+
+int
+ospf_lsa_maxage_walker_remover (struct ospf_lsa *lsa, void *p_arg, int int_arg)
+{
+#ifdef HAVE_NSSA
+  /* Stay away from any Local Translated Type-7 LSAs */
+  if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
+    return 0;
+#endif /* HAVE_NSSA */
+
+  if (IS_LSA_MAXAGE (lsa))
+    /* Self-originated LSAs should NOT time-out instead,
+       they're flushed and submitted to the max_age list explicitly. */
+    if (!ospf_lsa_is_self_originated (lsa))
+      {
+	if (IS_DEBUG_OSPF (lsa, LSA_FLOODING))
+	  zlog_info("LSA[%s]: is MaxAge", dump_lsa_key (lsa));
+
+        switch (lsa->data->type)
+          {
+          case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+          case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+	    ospf_ase_incremental_update (lsa, ospf_top);
+            break;
+          default:
+	    ospf_spf_calculate_schedule ();
+            break;
+          }
+
+	ospf_lsa_maxage (lsa);
+      }
+
+  return 0;
+}
+
+/* Periodical check of MaxAge LSA. */
+int
+ospf_lsa_maxage_walker (struct thread *t)
+{
+  listnode node;
+
+  ospf_top->t_maxage_walker = NULL;
+
+  for (node = listhead (ospf_top->areas); node; nextnode (node))
+    {
+      struct ospf_area *area = node->data;
+
+      foreach_lsa (ROUTER_LSDB (area), NULL, 0,
+		   ospf_lsa_maxage_walker_remover);
+      foreach_lsa (NETWORK_LSDB (area), NULL, 0,
+		   ospf_lsa_maxage_walker_remover);
+      foreach_lsa (SUMMARY_LSDB (area), NULL, 0,
+		   ospf_lsa_maxage_walker_remover);
+      foreach_lsa (ASBR_SUMMARY_LSDB (area), NULL, 0,
+		   ospf_lsa_maxage_walker_remover);
+#ifdef HAVE_OPAQUE_LSA
+      foreach_lsa (OPAQUE_LINK_LSDB (area), NULL, 0,
+		   ospf_lsa_maxage_walker_remover);
+      foreach_lsa (OPAQUE_AREA_LSDB (area), NULL, 0,
+		   ospf_lsa_maxage_walker_remover);
+#endif /* HAVE_OPAQUE_LSA */
+    }
+
+  /* for AS-eternal-LSAs. */
+  if (ospf_top->lsdb)
+    foreach_lsa (EXTERNAL_LSDB (ospf_top), NULL, 0,
+		 ospf_lsa_maxage_walker_remover);
+
+#ifdef HAVE_OPAQUE_LSA
+  if (ospf_top->lsdb)
+    foreach_lsa (OPAQUE_AS_LSDB (ospf_top), NULL, 0,
+		 ospf_lsa_maxage_walker_remover);
+#endif /* HAVE_OPAQUE_LSA */
+
+  ospf_top->t_maxage_walker = 
+    thread_add_timer (master, ospf_lsa_maxage_walker, NULL,
+                      OSPF_LSA_MAXAGE_CHECK_INTERVAL);
+  return 0;
+}
+
+int
+find_summary (struct ospf_lsa *lsa, void * v, int i)
+{
+  struct prefix_ipv4 *p, pr;
+
+  if ((p = (struct prefix_ipv4 *) v) != NULL)
+    if (lsa != NULL)
+      /* We're looking for self-originated one */
+      if (ospf_lsa_is_self_originated (lsa))
+	{
+	  struct summary_lsa *sl = (struct summary_lsa *) lsa->data;
+
+	  pr.family = AF_INET;
+	  pr.prefix = sl->header.id;
+	  pr.prefixlen = ip_masklen (sl->mask);
+	  apply_mask_ipv4 (&pr);
+
+	  if (prefix_same ((struct prefix*) &pr, (struct prefix*) p))
+	    return 1;
+	}
+
+  return 0;
+}
+
+int
+find_asbr_summary (struct ospf_lsa *lsa, void * v, int i)
+{
+  struct prefix_ipv4 *p;
+
+  if ((p = (struct prefix_ipv4 *) v) != NULL)
+    if (lsa != NULL)
+      /* We're looking for self-originated one */
+      if (ospf_lsa_is_self_originated (lsa))
+	{
+	  struct summary_lsa *sl = (struct summary_lsa *) lsa->data;
+
+	  if (IPV4_ADDR_SAME (&p->prefix, &sl->header.id))
+	    return 1;
+	}
+
+  return 0;
+}
+
+struct ospf_lsa *
+ospf_lsa_lookup (struct ospf_area *area, u_int32_t type,
+                 struct in_addr id, struct in_addr adv_router)
+{
+  switch (type)
+    {
+    case OSPF_ROUTER_LSA:
+    case OSPF_NETWORK_LSA:
+    case OSPF_SUMMARY_LSA:
+    case OSPF_ASBR_SUMMARY_LSA:
+#ifdef HAVE_NSSA
+    case OSPF_AS_NSSA_LSA:
+#endif /* HAVE_NSSA */
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      return ospf_lsdb_lookup_by_id (area->lsdb, type, id, adv_router);
+      break;
+    case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_AS_LSA:
+#endif /* HAVE_OPAQUE_LSA */
+      return ospf_lsdb_lookup_by_id (ospf_top->lsdb, type, id, adv_router);
+      break;
+    default:
+      break;
+    }
+
+  return NULL;
+}
+
+struct ospf_lsa *
+ospf_lsa_lookup_by_id (struct ospf_area *area, u_int32_t type, 
+                       struct in_addr id)
+{
+  struct ospf_lsa *lsa;
+  struct route_node *rn;
+
+  switch (type)
+    {
+    case OSPF_ROUTER_LSA:
+      return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id);
+      break;
+    case OSPF_NETWORK_LSA:
+      for (rn = route_top (NETWORK_LSDB (area)); rn; rn = route_next (rn))
+	if ((lsa = rn->info))
+	  if (IPV4_ADDR_SAME (&lsa->data->id, &id))
+	    {
+	      route_unlock_node (rn);
+	      return lsa;
+	    }
+      break;
+    case OSPF_SUMMARY_LSA:
+    case OSPF_ASBR_SUMMARY_LSA:
+      /* Currently not used. */
+      assert (1);
+      return ospf_lsdb_lookup_by_id (area->lsdb, type, id, id);
+      break;
+    case OSPF_AS_EXTERNAL_LSA:
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+    case OSPF_OPAQUE_AS_LSA:
+      /* Currently not used. */
+      break;
+#endif /* HAVE_OPAQUE_LSA */
+    default:
+      break;
+    }
+
+  return NULL;
+}
+
+struct ospf_lsa *
+ospf_lsa_lookup_by_header (struct ospf_area *area, struct lsa_header *lsah)
+{
+  struct ospf_lsa *match;
+
+#ifdef HAVE_OPAQUE_LSA
+  /*
+   * Strictly speaking, the LSA-ID field for Opaque-LSAs (type-9/10/11)
+   * is redefined to have two subfields; opaque-type and opaque-id.
+   * However, it is harmless to treat the two sub fields together, as if
+   * they two were forming a unique LSA-ID.
+   */
+#endif /* HAVE_OPAQUE_LSA */
+
+  match = ospf_lsa_lookup (area, lsah->type, lsah->id, lsah->adv_router);
+
+  if (match == NULL)
+    if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA)
+      zlog_info ("LSA[Type%d:%s]: Lookup by header, NO MATCH",
+		 lsah->type, inet_ntoa (lsah->id));
+
+  return match;
+}
+
+/* return +n, l1 is more recent.
+   return -n, l2 is more recent.
+   return 0, l1 and l2 is identical. */
+int
+ospf_lsa_more_recent (struct ospf_lsa *l1, struct ospf_lsa *l2)
+{
+  int r;
+  int x, y;
+
+  if (l1 == NULL && l2 == NULL)
+    return 0;
+  if (l1 == NULL)
+    return -1;
+  if (l2 == NULL)
+    return 1;
+
+  /* compare LS sequence number. */
+  x = (int) ntohl (l1->data->ls_seqnum);
+  y = (int) ntohl (l2->data->ls_seqnum);
+  if (x > y)
+    return 1;
+  if (x < y)
+    return -1;
+
+  /* compare LS checksum. */
+  r = ntohs (l1->data->checksum) - ntohs (l2->data->checksum);
+  if (r)
+    return r;
+
+  /* compare LS age. */
+  if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2))
+    return 1;
+  else if (!IS_LSA_MAXAGE (l1) && IS_LSA_MAXAGE (l2))
+    return -1;
+
+  /* compare LS age with MaxAgeDiff. */
+  if (LS_AGE (l1) - LS_AGE (l2) > OSPF_LSA_MAXAGE_DIFF)
+    return -1;
+  else if (LS_AGE (l2) - LS_AGE (l1) > OSPF_LSA_MAXAGE_DIFF)
+    return 1;
+
+  /* LSAs are identical. */
+  return 0;
+}
+
+/* If two LSAs are different, return 1, otherwise return 0. */
+int
+ospf_lsa_different (struct ospf_lsa *l1, struct ospf_lsa *l2)
+{
+  char *p1, *p2;
+  assert (l1);
+  assert (l2);
+  assert (l1->data);
+  assert (l2->data);
+
+  if (l1->data->options != l2->data->options)
+    return 1;
+
+  if (IS_LSA_MAXAGE (l1) && !IS_LSA_MAXAGE (l2))
+    return 1;
+
+  if (IS_LSA_MAXAGE (l2) && !IS_LSA_MAXAGE (l1))
+    return 1;
+
+  if (l1->data->length != l2->data->length)
+    return 1;
+
+  if (l1->data->length ==  0)
+    return 1;
+
+  assert (l1->data->length > OSPF_LSA_HEADER_SIZE);
+
+  p1 = (char *) l1->data;
+  p2 = (char *) l2->data;
+
+  if (memcmp (p1 + OSPF_LSA_HEADER_SIZE, p2 + OSPF_LSA_HEADER_SIZE,
+              ntohs( l1->data->length ) - OSPF_LSA_HEADER_SIZE) != 0)
+    return 1;
+
+  return 0;
+}
+
+#ifdef ORIGINAL_CODING
+void
+ospf_lsa_flush_self_originated (struct ospf_neighbor *nbr,
+                                struct ospf_lsa *self,
+                                struct ospf_lsa *new)
+{
+  u_int32_t seqnum;
+
+  /* Adjust LS Sequence Number. */
+  seqnum = ntohl (new->data->ls_seqnum) + 1;
+  self->data->ls_seqnum = htonl (seqnum);
+
+  /* Recalculate LSA checksum. */
+  ospf_lsa_checksum (self->data);
+
+  /* Reflooding LSA. */
+  /*  RFC2328  Section 13.3
+	    On non-broadcast networks, separate	Link State Update
+	    packets must be sent, as unicasts, to each adjacent	neighbor
+	    (i.e., those in state Exchange or greater).	 The destination
+	    IP addresses for these packets are the neighbors' IP
+	    addresses.   */
+  if (nbr->oi->type == OSPF_IFTYPE_NBMA)
+    {
+      struct route_node *rn;
+      struct ospf_neighbor *onbr;
+
+      for (rn = route_top (nbr->oi->nbrs); rn; rn = route_next (rn))
+	if ((onbr = rn->info) != NULL)
+	  if (onbr != nbr->oi->nbr_self && onbr->status >= NSM_Exchange)
+	    ospf_ls_upd_send_lsa (onbr, self, OSPF_SEND_PACKET_DIRECT);
+    }
+  else
+  ospf_ls_upd_send_lsa (nbr, self, OSPF_SEND_PACKET_INDIRECT);
+
+  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+    zlog_info ("LSA[Type%d:%s]: Flush self-originated LSA",
+	       self->data->type, inet_ntoa (self->data->id));
+}
+#else /* ORIGINAL_CODING */
+static int
+ospf_lsa_flush_schedule (struct ospf_lsa *lsa, void *v, int i)
+{
+  if (lsa == NULL || !IS_LSA_SELF (lsa))
+    return 0;
+
+  if (IS_DEBUG_OSPF_EVENT)
+    zlog_info ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id));
+
+  /* Force given lsa's age to MaxAge. */
+  lsa->data->ls_age = htons (OSPF_LSA_MAXAGE);
+
+  switch (lsa->data->type)
+    {
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+    case OSPF_OPAQUE_AS_LSA:
+      ospf_opaque_lsa_refresh (lsa);
+      break;
+#endif /* HAVE_OPAQUE_LSA */
+    default:
+      ospf_lsa_maxage (lsa);
+      break;
+    }
+
+  return 0;
+}
+
+void
+ospf_flush_self_originated_lsas_now (struct ospf *top)
+{
+  listnode n1, n2;
+  struct ospf_area *area;
+  struct ospf_interface *oi;
+  struct ospf_lsa *lsa;
+  int need_to_flush_ase = 0;
+
+  for (n1 = listhead (top->areas); n1; nextnode (n1))
+    {
+      if ((area = getdata (n1)) == NULL)
+        continue;
+
+      if ((lsa = area->router_lsa_self) != NULL)
+        {
+          if (IS_DEBUG_OSPF_EVENT)
+            zlog_info ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id));
+
+          ospf_lsa_flush_area (lsa, area);
+          ospf_lsa_unlock (area->router_lsa_self);
+          area->router_lsa_self = NULL;
+          OSPF_TIMER_OFF (area->t_router_lsa_self);
+        }
+
+      for (n2 = listhead (area->oiflist); n2; nextnode (n2))
+        {
+          if ((oi = getdata (n2)) == NULL)
+            continue;
+
+          if ((lsa = oi->network_lsa_self) != NULL
+          &&   oi->state == ISM_DR
+          &&   oi->full_nbrs > 0)
+            {
+              if (IS_DEBUG_OSPF_EVENT)
+                zlog_info ("LSA[Type%d:%s]: Schedule self-originated LSA to FLUSH", lsa->data->type, inet_ntoa (lsa->data->id));
+
+              ospf_lsa_flush_area (oi->network_lsa_self, area);
+              ospf_lsa_unlock (oi->network_lsa_self);
+              oi->network_lsa_self = NULL;
+              OSPF_TIMER_OFF (oi->t_network_lsa_self);
+            }
+
+          if (oi->type != OSPF_IFTYPE_VIRTUALLINK
+          &&  area->external_routing == OSPF_AREA_DEFAULT)
+            need_to_flush_ase = 1;
+        }
+
+      foreach_lsa (SUMMARY_LSDB (area), NULL, 0, ospf_lsa_flush_schedule);
+      foreach_lsa (ASBR_SUMMARY_LSDB (area), NULL, 0, ospf_lsa_flush_schedule);
+#ifdef HAVE_OPAQUE_LSA
+      foreach_lsa (OPAQUE_LINK_LSDB (area),
+                   NULL, 0, ospf_lsa_flush_schedule);
+      foreach_lsa (OPAQUE_AREA_LSDB (area),
+                   NULL, 0, ospf_lsa_flush_schedule);
+#endif /* HAVE_OPAQUE_LSA */
+    }
+
+  if (need_to_flush_ase)
+    {
+        foreach_lsa (EXTERNAL_LSDB (top), NULL, 0, ospf_lsa_flush_schedule);
+#ifdef HAVE_OPAQUE_LSA
+        foreach_lsa (OPAQUE_AS_LSDB (top),
+                     NULL, 0, ospf_lsa_flush_schedule);
+#endif /* HAVE_OPAQUE_LSA */
+    }
+
+  /*
+   * Make sure that the MaxAge LSA remover is executed immediately,
+   * without conflicting to other threads.
+   */
+  if (top->t_maxage != NULL)
+    {
+      OSPF_TIMER_OFF (top->t_maxage);
+      thread_execute (master, ospf_maxage_lsa_remover, top, 0);
+    }
+
+  return;
+}
+#endif /* ORIGINAL_CODING */
+
+/* If there is self-originated LSA, then return 1, otherwise return 0. */
+/* An interface-independent version of ospf_lsa_is_self_originated */
+int 
+ospf_lsa_is_self_originated (struct ospf_lsa *lsa)
+{
+  listnode node;
+
+  /* This LSA is already checked. */
+  if (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED))
+    return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF);
+
+  /* Make sure LSA is self-checked. */
+  SET_FLAG (lsa->flags, OSPF_LSA_SELF_CHECKED);
+
+  /* AdvRouter and Router ID is the same. */
+  if (IPV4_ADDR_SAME (&lsa->data->adv_router, &ospf_top->router_id))
+    SET_FLAG (lsa->flags, OSPF_LSA_SELF);
+
+  /* LSA is router-LSA. */
+  else if (lsa->data->type == OSPF_ROUTER_LSA &&
+      IPV4_ADDR_SAME (&lsa->data->id, &ospf_top->router_id))
+    SET_FLAG (lsa->flags, OSPF_LSA_SELF);
+
+  /* LSA is network-LSA.  Compare Link ID with all interfaces. */
+  else if (lsa->data->type == OSPF_NETWORK_LSA)
+    for (node = listhead (ospf_top->oiflist); node; nextnode (node))
+      {
+	struct ospf_interface *oi = getdata (node);
+
+	/* Ignore virtual link. */
+        if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
+	  if (oi->address->family == AF_INET)
+	    if (IPV4_ADDR_SAME (&lsa->data->id, &oi->address->u.prefix4))
+	      {
+		/* to make it easier later */
+		SET_FLAG (lsa->flags, OSPF_LSA_SELF);
+		return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF);
+	      }
+      }
+
+  return CHECK_FLAG (lsa->flags, OSPF_LSA_SELF);
+}
+
+/* Get unique Link State ID. */
+struct in_addr
+ospf_lsa_unique_id (struct ospf_lsdb *lsdb, u_char type, struct prefix_ipv4 *p)
+{
+  struct ospf_lsa *lsa;
+  struct in_addr mask, id;
+
+  id = p->prefix;
+
+  /* Check existence of LSA instance. */
+  lsa = ospf_lsdb_lookup_by_id (lsdb, type, id, ospf_top->router_id);
+  if (lsa)
+    {
+      struct as_external_lsa *al = (struct as_external_lsa *) lsa->data;
+      if (ip_masklen (al->mask) == p->prefixlen)
+	{
+	  if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+	    zlog_warn ("ospf_lsa_unique_id(): "
+		       "Can't get Link State ID for %s/%d",
+		       inet_ntoa (p->prefix), p->prefixlen);
+	  /*	  id.s_addr = 0; */
+	  id.s_addr = 0xffffffff;
+	  return id;
+	}
+      /* Masklen differs, then apply wildcard mask to Link State ID. */
+      else
+	{
+	  masklen2ip (p->prefixlen, &mask);
+
+	  id.s_addr = p->prefix.s_addr | (~mask.s_addr);
+	  lsa = ospf_lsdb_lookup_by_id (ospf_top->lsdb, type,
+				       id, ospf_top->router_id);
+	  if (lsa)
+	    {
+	      if (IS_DEBUG_OSPF (lsa, LSA_GENERATE))
+		zlog_warn ("ospf_lsa_unique_id(): "
+			   "Can't get Link State ID for %s/%d",
+			   inet_ntoa (p->prefix), p->prefixlen);
+	      /* 	      id.s_addr = 0; */
+	      id.s_addr = 0xffffffff;
+	      return id;
+	    }
+	}
+    }
+
+  return id;
+}
+
+
+#define LSA_ACTION_ORIGN_RTR  1
+#define LSA_ACTION_ORIGN_NET  2
+#define LSA_ACTION_FLOOD_AREA 3
+#define LSA_ACTION_FLOOD_AS   4
+#define LSA_ACTION_FLUSH_AREA 5
+#define LSA_ACTION_FLUSH_AS   6
+
+struct lsa_action
+{
+  u_char action;
+  struct ospf_area *area;
+  struct ospf_interface *oi; 
+  struct ospf_lsa *lsa;
+};
+
+int
+ospf_lsa_action (struct thread *t)
+{
+  struct lsa_action *data;
+
+  data = THREAD_ARG (t);
+
+  if (IS_DEBUG_OSPF (lsa, LSA) == OSPF_DEBUG_LSA)
+    zlog_info ("LSA[Action]: Performing scheduled LSA action: %d",
+	       data->action);
+
+  switch (data->action)
+    {
+    case LSA_ACTION_ORIGN_RTR:
+      ospf_router_lsa_refresh (data->area->router_lsa_self);
+      break;
+    case LSA_ACTION_ORIGN_NET:
+      ospf_network_lsa_originate (data->oi);
+      break;
+    case LSA_ACTION_FLOOD_AREA:
+      ospf_flood_through_area (data->area, NULL, data->lsa);
+      break;
+    case LSA_ACTION_FLOOD_AS:
+      ospf_flood_through_as (NULL, data->lsa);
+      break;
+    case LSA_ACTION_FLUSH_AREA:
+      ospf_lsa_flush_area (data->lsa, data->area);
+      break;
+    case LSA_ACTION_FLUSH_AS:
+      ospf_lsa_flush_as (data->lsa);
+      break;
+    }
+
+  ospf_lsa_unlock (data->lsa);
+  XFREE (MTYPE_OSPF_MESSAGE, data);
+  return 0;
+}
+
+void
+ospf_schedule_lsa_flood_area (struct ospf_area *area, struct ospf_lsa *lsa)
+{
+  struct lsa_action *data;
+
+  data = XMALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action));
+  memset (data, 0, sizeof (struct lsa_action));
+
+  data->action = LSA_ACTION_FLOOD_AREA;
+  data->area = area;
+  data->lsa  = ospf_lsa_lock (lsa);
+
+  thread_add_event (master, ospf_lsa_action, data, 0);
+}
+
+void
+ospf_schedule_lsa_flush_area (struct ospf_area *area, struct ospf_lsa *lsa)
+{
+  struct lsa_action *data;
+
+  data = XMALLOC (MTYPE_OSPF_MESSAGE, sizeof (struct lsa_action));
+  memset (data, 0, sizeof (struct lsa_action));
+
+  data->action = LSA_ACTION_FLUSH_AREA;
+  data->area = area;
+  data->lsa  = ospf_lsa_lock (lsa);
+
+  thread_add_event (master, ospf_lsa_action, data, 0);
+}
+
+
+/* LSA Refreshment functions. */
+void
+ospf_lsa_refresh (struct ospf_lsa *lsa)
+{
+  struct external_info *ei;
+  assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF));
+
+  switch (lsa->data->type)
+    {
+      /* Router and Network LSAs are processed differently. */
+    case OSPF_ROUTER_LSA:
+    case OSPF_NETWORK_LSA: 
+      break;
+    case OSPF_SUMMARY_LSA:
+      ospf_summary_lsa_refresh (lsa);
+      break;
+    case OSPF_ASBR_SUMMARY_LSA:
+      ospf_summary_asbr_lsa_refresh (lsa);
+      break;
+    case OSPF_AS_EXTERNAL_LSA:
+      ei = ospf_external_info_check (lsa);
+      if (ei)
+	ospf_external_lsa_refresh (lsa, ei, LSA_REFRESH_FORCE);
+      else
+	ospf_lsa_flush_as (lsa);
+      break;
+#ifdef HAVE_OPAQUE_LSA
+    case OSPF_OPAQUE_LINK_LSA:
+    case OSPF_OPAQUE_AREA_LSA:
+    case OSPF_OPAQUE_AS_LSA:
+      ospf_opaque_lsa_refresh (lsa);
+      break;
+    default:
+      break;
+#endif /* HAVE_OPAQUE_LSA */
+    }
+}
+
+void
+ospf_refresher_register_lsa (struct ospf *top, struct ospf_lsa *lsa)
+{
+  u_int16_t index, current_index;
+  
+  assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF));
+
+  if (lsa->refresh_list < 0)
+    {
+      int delay;
+
+      if (LS_AGE (lsa) == 0 &&
+	  ntohl (lsa->data->ls_seqnum) == OSPF_INITIAL_SEQUENCE_NUMBER)
+	/* Randomize first update by  OSPF_LS_REFRESH_SHIFT factor */ 
+	delay = OSPF_LS_REFRESH_SHIFT + (random () % OSPF_LS_REFRESH_TIME);
+      else
+	/* Randomize another updates by +-OSPF_LS_REFRESH_JITTER factor */
+	delay = OSPF_LS_REFRESH_TIME - LS_AGE (lsa) - OSPF_LS_REFRESH_JITTER
+	  + (random () % (2*OSPF_LS_REFRESH_JITTER)); 
+
+      if (delay < 0)
+	delay = 0;
+
+      current_index = top->lsa_refresh_queue.index +
+	(time (NULL) - top->lsa_refresher_started)/OSPF_LSA_REFRESHER_GRANULARITY;
+      
+      index = (current_index + delay/OSPF_LSA_REFRESHER_GRANULARITY)
+	% (OSPF_LSA_REFRESHER_SLOTS);
+
+      if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+	zlog_info ("LSA[Refresh]: lsa with age %d added to index %d",
+		   LS_AGE (lsa), index);
+      if (!top->lsa_refresh_queue.qs[index])
+	top->lsa_refresh_queue.qs[index] = list_new ();
+      listnode_add (top->lsa_refresh_queue.qs[index], ospf_lsa_lock (lsa));
+      lsa->refresh_list = index;
+    }
+}
+
+void
+ospf_refresher_unregister_lsa (struct ospf *top, struct ospf_lsa *lsa)
+{
+  assert (CHECK_FLAG (lsa->flags, OSPF_LSA_SELF));
+  if (lsa->refresh_list >= 0)
+    {
+      list refresh_list = top->lsa_refresh_queue.qs[lsa->refresh_list];
+      listnode_delete (refresh_list, lsa);
+      if (!listcount (refresh_list))
+	{
+	  list_free (refresh_list);
+	  top->lsa_refresh_queue.qs[lsa->refresh_list] = NULL;
+	}
+      ospf_lsa_unlock (lsa);
+      lsa->refresh_list = -1;
+    }
+}
+
+int
+ospf_lsa_refresh_walker (struct thread *t)
+{
+  list refresh_list;
+  listnode node;
+  struct ospf *top = THREAD_ARG (t);
+  int i;
+  list lsa_to_refresh = list_new ();
+
+  if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+    zlog_info ("LSA[Refresh]:ospf_lsa_refresh_walker(): start");
+
+  
+  i = top->lsa_refresh_queue.index;
+  
+  top->lsa_refresh_queue.index =
+    (top->lsa_refresh_queue.index +
+     (time (NULL) - top->lsa_refresher_started) / OSPF_LSA_REFRESHER_GRANULARITY)
+    % OSPF_LSA_REFRESHER_SLOTS;
+
+  if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+    zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): next index %d",
+	       top->lsa_refresh_queue.index);
+
+  for (;i != top->lsa_refresh_queue.index;
+       i = (i + 1) % OSPF_LSA_REFRESHER_SLOTS)
+    {
+      if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+	zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): refresh index %d", i);
+
+      refresh_list = top->lsa_refresh_queue.qs [i];
+      
+      top->lsa_refresh_queue.qs [i] = NULL;
+      
+      if (refresh_list)
+	{
+	  for (node = listhead (refresh_list); node;)
+	    {
+	      listnode next;
+	      struct ospf_lsa *lsa = getdata (node);
+	      next = node->next;
+	      
+	      if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+		zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): refresh lsa %p", lsa);
+	      
+	      list_delete_node (refresh_list, node);
+	      ospf_lsa_unlock (lsa);
+	      lsa->refresh_list = -1;
+	      listnode_add (lsa_to_refresh, lsa);
+	      node = next;
+	    }
+	  list_free (refresh_list);
+	}
+    }
+
+  top->t_lsa_refresher = thread_add_timer (master, ospf_lsa_refresh_walker,
+					   top, top->lsa_refresh_interval);
+  top->lsa_refresher_started = time (NULL);
+
+  for (node = listhead (lsa_to_refresh); node; nextnode (node))
+    ospf_lsa_refresh (getdata (node));
+  
+  list_delete (lsa_to_refresh);
+  
+  if (IS_DEBUG_OSPF (lsa, LSA_REFRESH))
+    zlog_info ("LSA[Refresh]: ospf_lsa_refresh_walker(): end");
+  
+  return 0;
+}
+