]> git.proxmox.com Git - mirror_frr.git/blobdiff - ospfd/ospf_packet.c
Merge remote-tracking branch 'polymorf/master'
[mirror_frr.git] / ospfd / ospf_packet.c
index 74caaa77c167c8b556851fed934f4e372fb23583..be137d911604db244ef120301783daa01ca13dd4 100644 (file)
@@ -125,6 +125,20 @@ ospf_fifo_push (struct ospf_fifo *fifo, struct ospf_packet *op)
   fifo->count++;
 }
 
+/* Add new packet to head of fifo. */
+static void
+ospf_fifo_push_head (struct ospf_fifo *fifo, struct ospf_packet *op)
+{
+  op->next = fifo->head;
+  
+  if (fifo->tail == NULL)
+    fifo->tail = op;
+  
+  fifo->head = op;
+  
+  fifo->count++;
+}
+
 /* Delete first packet from fifo. */
 struct ospf_packet *
 ospf_fifo_pop (struct ospf_fifo *fifo)
@@ -199,6 +213,27 @@ ospf_packet_add (struct ospf_interface *oi, struct ospf_packet *op)
   /* ospf_fifo_debug (oi->obuf); */
 }
 
+static void
+ospf_packet_add_top (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 head of queue. */
+  ospf_fifo_push_head (oi->obuf, op);
+
+  /* Debug of packet fifo*/
+  /* ospf_fifo_debug (oi->obuf); */
+}
+
 void
 ospf_packet_delete (struct ospf_interface *oi)
 {
@@ -216,8 +251,9 @@ ospf_packet_dup (struct ospf_packet *op)
   struct ospf_packet *new;
 
   if (stream_get_endp(op->s) != op->length)
-    zlog_warn ("ospf_packet_dup stream %ld ospf_packet %d size mismatch",
-              STREAM_SIZE(op->s), op->length);
+    /* XXX size_t */
+    zlog_warn ("ospf_packet_dup stream %lu ospf_packet %u size mismatch",
+              (u_long)STREAM_SIZE(op->s), op->length);
 
   /* Reserve space for MD5 authentication that may be added later. */
   new = ospf_packet_new (stream_get_endp(op->s) + OSPF_AUTH_MD5_SIZE);
@@ -337,7 +373,9 @@ ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op)
     return 0;
 
   /* We do this here so when we dup a packet, we don't have to
-     waste CPU rewriting other headers. */
+     waste CPU rewriting other headers.
+     
+     Note that quagga_time /deliberately/ is not used here */
   t = (time(NULL) & 0xFFFFFFFF);
   if (t > oi->crypt_seqnum)
     oi->crypt_seqnum = t;
@@ -369,7 +407,9 @@ ospf_make_md5_digest (struct ospf_interface *oi, struct ospf_packet *op)
   op->length = ntohs (ospfh->length) + OSPF_AUTH_MD5_SIZE;
 
   if (stream_get_endp(op->s) != op->length)
-    zlog_warn("ospf_make_md5_digest: length mismatch stream %ld ospf_packet %d", stream_get_endp(op->s), op->length);
+    /* XXX size_t */
+    zlog_warn("ospf_make_md5_digest: length mismatch stream %lu ospf_packet %u",
+             (u_long)stream_get_endp(op->s), op->length);
 
   return OSPF_AUTH_MD5_SIZE;
 }
@@ -444,7 +484,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 (recent_time, lsa->tv_recv), 
+               if (tv_cmp (tv_sub (recent_relative_time (), lsa->tv_recv), 
                            int2tv (retransmit_interval)) >= 0)
                  listnode_add (update, rn->info);
            }
@@ -597,8 +637,12 @@ ospf_write (struct thread *thread)
     ipid = (time(NULL) & 0xffff);
 #endif /* WANT_OSPF_WRITE_FRAGMENT */
 
-  /* convenience - max OSPF data per packet */
-  maxdatasize = oi->ifp->mtu - sizeof (struct ip);
+  /* convenience - max OSPF data per packet,
+   * and reliability - not more data, than our
+   * socket can accept
+   */
+  maxdatasize = MIN (oi->ifp->mtu, ospf->maxsndbuflen) -
+    sizeof (struct ip);
   
   /* Get one packet from queue. */
   op = ospf_fifo_head (oi->obuf);
@@ -623,9 +667,9 @@ ospf_write (struct thread *thread)
   memset (&sa_dst, 0, sizeof (sa_dst));
   
   sa_dst.sin_family = AF_INET;
-#ifdef HAVE_SIN_LEN
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
   sa_dst.sin_len = sizeof(sa_dst);
-#endif /* HAVE_SIN_LEN */
+#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
   sa_dst.sin_addr = op->dst;
   sa_dst.sin_port = htons (0);
 
@@ -644,6 +688,13 @@ ospf_write (struct thread *thread)
   iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
   iph.ip_len = (iph.ip_hl << OSPF_WRITE_IPHL_SHIFT) + op->length;
 
+#if defined(__DragonFly__)
+  /*
+   * DragonFly's raw socket expects ip_len/ip_off in network byte order.
+   */
+  iph.ip_len = htons(iph.ip_len);
+#endif
+
 #ifdef WANT_OSPF_WRITE_FRAGMENT
   /* XXX-MT: not thread-safe at all..
    * XXX: this presumes this is only programme sending OSPF packets 
@@ -756,24 +807,6 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
       return;
     }
 
-  /* If incoming interface is passive one, ignore Hello. */
-  if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE) {
-    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. */
-        OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
-        ospf_if_set_multicast(oi);
-      }
-    return;
-  }
-
   /* get neighbor prefix. */
   p.family = AF_INET;
   p.prefixlen = ip_masklen (hello->network_mask);
@@ -794,8 +827,10 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
   /* Compare Router Dead Interval. */
   if (OSPF_IF_PARAM (oi, v_wait) != ntohl (hello->dead_interval))
     {
-      zlog_warn ("Packet %s [Hello:RECV]: RouterDeadInterval mismatch.",
-                inet_ntoa (ospfh->router_id));
+      zlog_warn ("Packet %s [Hello:RECV]: RouterDeadInterval mismatch "
+                "(expected %u, but received %u).",
+                inet_ntoa(ospfh->router_id),
+                OSPF_IF_PARAM(oi, v_wait), ntohl(hello->dead_interval));
       return;
     }
 
@@ -804,8 +839,10 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
     {
       if (OSPF_IF_PARAM (oi, v_hello) != ntohs (hello->hello_interval))
         {
-          zlog_warn ("Packet %s [Hello:RECV]: HelloInterval mismatch.",
-                     inet_ntoa (ospfh->router_id));
+          zlog_warn ("Packet %s [Hello:RECV]: HelloInterval mismatch "
+                    "(expected %u, but received %u).",
+                    inet_ntoa(ospfh->router_id),
+                    OSPF_IF_PARAM(oi, v_hello), ntohs(hello->hello_interval));
           return;
         }
     }
@@ -886,7 +923,7 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
   old_state = nbr->state;
 
   /* Add event to thread. */
-  OSPF_NSM_EVENT_EXECUTE (nbr, NSM_HelloReceived);
+  OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
 
   /*  RFC2328  Section 9.5.1
       If the router is not eligible to become Designated Router,
@@ -906,7 +943,7 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
   if (oi->type == OSPF_IFTYPE_NBMA &&
       (old_state == NSM_Down || old_state == NSM_Attempt))
     {
-      OSPF_NSM_EVENT_EXECUTE (nbr, NSM_OneWayReceived);
+      OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_OneWayReceived);
       nbr->priority = hello->priority;
       nbr->d_router = hello->d_router;
       nbr->bd_router = hello->bd_router;
@@ -916,12 +953,12 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
   if (ospf_nbr_bidirectional (&oi->ospf->router_id, hello->neighbors,
                              size - OSPF_HELLO_MIN_SIZE))
     {
-      OSPF_NSM_EVENT_EXECUTE (nbr, NSM_TwoWayReceived);
+      OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_TwoWayReceived);
       nbr->options |= hello->options;
     }
   else
     {
-      OSPF_NSM_EVENT_EXECUTE (nbr, NSM_OneWayReceived);
+      OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_OneWayReceived);
       /* Set neighbor information. */
       nbr->priority = hello->priority;
       nbr->d_router = hello->d_router;
@@ -1035,20 +1072,40 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi,
 
       /* Lookup received LSA, then add LS request list. */
       find = ospf_lsa_lookup_by_header (oi->area, lsah);
-      if (!find || ospf_lsa_more_recent (find, new) < 0)
-       {
-         ospf_ls_request_add (nbr, new);
-         ospf_lsa_discard (new);
-       }
-      else
-       {
-         /* Received LSA is not recent. */
-         if (IS_DEBUG_OSPF_EVENT)
-           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;
-       }
+      
+      /* ospf_lsa_more_recent is fine with NULL pointers */
+      switch (ospf_lsa_more_recent (find, new))
+        {
+          case -1:
+            /* Neighbour has a more recent LSA, we must request it */
+            ospf_ls_request_add (nbr, new);
+          case 0:
+            /* If we have a copy of this LSA, it's either less recent
+             * and we're requesting it from neighbour (the case above), or
+             * it's as recent and we both have same copy (this case).
+             *
+             * In neither of these two cases is there any point in
+             * describing our copy of the LSA to the neighbour in a
+             * DB-Summary packet, if we're still intending to do so.
+             *
+             * See: draft-ogier-ospf-dbex-opt-00.txt, describing the
+             * backward compatible optimisation to OSPF DB Exchange /
+             * DB Description process implemented here.
+             */
+            if (find)
+              ospf_lsdb_delete (&nbr->db_sum, find);
+            ospf_lsa_discard (new);
+            break;
+          default:
+            /* We have the more recent copy, nothing specific to do:
+             * - no need to request neighbours stale copy
+             * - must leave DB summary list copy alone
+             */
+            if (IS_DEBUG_OSPF_EVENT)
+              zlog_debug ("Packet [DD:RECV]: LSA received Type %d, "
+                         "ID %s is not recent.", lsah->type, inet_ntoa (lsah->id));
+            ospf_lsa_discard (new);
+        }
     }
 
   /* Master */
@@ -1176,6 +1233,9 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
     }
 #endif /* HAVE_OPAQUE_LSA */
 
+  /* Add event to thread. */
+  OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
+
   /* Process DD packet by neighbor status. */
   switch (nbr->state)
     {
@@ -1343,7 +1403,7 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
          else
            {
              struct timeval t, now;
-             gettimeofday (&now, NULL);
+             quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
              t = tv_sub (now, nbr->last_send_ts);
              if (tv_cmp (t, int2tv (nbr->v_inactivity)) < 0)
                {
@@ -1397,6 +1457,9 @@ ospf_ls_req (struct ip *iph, struct ospf_header *ospfh,
       return;
     }
 
+  /* Add event to thread. */
+  OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
+
   /* Neighbor State should be Exchange or later. */
   if (nbr->state != NSM_Exchange &&
       nbr->state != NSM_Loading &&
@@ -1629,6 +1692,9 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
       return;
     }
 
+  /* Add event to thread. */
+  OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
+
   /* Check neighbor state. */
   if (nbr->state < NSM_Exchange)
     {
@@ -1709,17 +1775,17 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
         /* Reject from STUB or NSSA */
         if (nbr->oi->area->external_routing != OSPF_AREA_DEFAULT) 
          {
-           DISCARD_LSA (lsa, 1);
            if (IS_DEBUG_OSPF_NSSA)
              zlog_debug("Incoming External LSA Discarded: We are NSSA/STUB Area");
+           DISCARD_LSA (lsa, 1);
          }
 
       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_debug("Incoming NSSA LSA Discarded:  Not NSSA Area");
+           DISCARD_LSA (lsa,2);
          }
 
       /* Find the LSA in the current database. */
@@ -1928,17 +1994,18 @@ ospf_ls_upd (struct ip *iph, struct ospf_header *ospfh,
            {
              struct timeval now;
              
-             gettimeofday (&now, NULL);
+             quagga_gettime (QUAGGA_CLK_MONOTONIC, &now);
              
              if (tv_cmp (tv_sub (now, current->tv_orig), 
-                         int2tv (OSPF_MIN_LS_ARRIVAL)) > 0)
+                         int2tv (OSPF_MIN_LS_ARRIVAL)) >= 0)
                /* Trap NSSA type later.*/
                ospf_ls_upd_send_lsa (nbr, current, OSPF_SEND_PACKET_DIRECT);
              DISCARD_LSA (lsa, 8);
            }
        }
     }
-  
+#undef DISCARD_LSA
+
   assert (listcount (lsas) == 0);
   list_delete (lsas);
 }
@@ -1961,6 +2028,9 @@ ospf_ls_ack (struct ip *iph, struct ospf_header *ospfh,
       return;
     }
 
+  /* Add event to thread. */
+  OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_PacketReceived);
+
   if (nbr->state < NSM_Exchange)
     {
       zlog_warn ("Link State Acknowledgment: "
@@ -2064,6 +2134,15 @@ ospf_recv_packet (int fd, struct interface **ifp, struct stream *ibuf)
   ip_len = ip_len + (iph->ip_hl << 2);
 #endif
   
+#if defined(__DragonFly__)
+  /*
+   * in DragonFly's raw socket, ip_len/ip_off are read 
+   * in network byte order.
+   * As OpenBSD < 200311 adjust ip_len to strip IP header size!
+   */
+  ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2);
+#endif
+
   ifindex = getsockopt_ifindex (AF_INET, &msgh);
   
   *ifp = if_lookup_by_index (ifindex);
@@ -2358,7 +2437,33 @@ ospf_read (struct thread *thread)
   ospfh = (struct ospf_header *) STREAM_PNT (ibuf);
 
   /* associate packet with ospf interface */
-  oi = ospf_if_lookup_recv_if (ospf, iph->ip_src);
+  oi = ospf_if_lookup_recv_if (ospf, iph->ip_src, ifp);
+
+  /* If incoming interface is passive one, ignore it. */
+  if (oi && OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE)
+    {
+      char buf[3][INET_ADDRSTRLEN];
+
+      if (IS_DEBUG_OSPF_EVENT)
+       zlog_debug ("ignoring packet 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.
+          * Some OS:es may have problems in this area,
+          * make sure it is removed.
+          */
+         OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
+         ospf_if_set_multicast(oi);
+       }
+      return 0;
+  }
+
 
   /* if no local ospf_interface, 
    * or header area is backbone but ospf_interface is not
@@ -2378,14 +2483,15 @@ ospf_read (struct thread *thread)
           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); 
+      if (IS_DEBUG_OSPF_EVENT)
+        zlog_warn ("Packet from [%s] received on wrong link %s",
+                   inet_ntoa (iph->ip_src), ifp->name); 
       return 0;
     }
   else if (oi->state == ISM_Down)
@@ -2690,25 +2796,9 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
   /* Set DD Sequence Number. */
   stream_putl (s, nbr->dd_seqnum);
 
+  /* shortcut unneeded walk of (empty) summary LSDBs */
   if (ospf_db_summary_isempty (nbr))
-    {
-      /* Sanity check:
-       *
-       * Must be here either:
-       * - Initial DBD (ospf_nsm.c)
-       *   - M must be set
-       * or
-       * - finishing Exchange, and DB-Summary list empty
-       *   - from ospf_db_desc_proc()
-       *   - M must not be set
-       */
-      if (nbr->state >= NSM_Exchange)
-       assert (!IS_SET_DD_M(nbr->dd_flags));
-      else
-        assert (IS_SET_DD_M(nbr->dd_flags));
-
-      return length;
-    }
+    goto empty;
 
   /* Describe LSA Header from Database Summary List. */
   lsdb = &nbr->db_sum;
@@ -2763,9 +2853,17 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
   /* Update 'More' bit */
   if (ospf_db_summary_isempty (nbr))
     {
-      UNSET_FLAG (nbr->dd_flags, OSPF_DD_FLAG_M);
-      /* Rewrite DD flags */
-      stream_putc_at (s, pp, nbr->dd_flags);
+empty:
+      if (nbr->state >= NSM_Exchange)
+        {
+          UNSET_FLAG (nbr->dd_flags, OSPF_DD_FLAG_M);
+          /* Rewrite DD flags */
+          stream_putc_at (s, pp, nbr->dd_flags);
+        }
+      else
+        {
+          assert (IS_SET_DD_M(nbr->dd_flags));
+        }
     }
   return length;
 }
@@ -2836,7 +2934,7 @@ ospf_make_ls_upd (struct ospf_interface *oi, struct list *update, struct stream
 {
   struct ospf_lsa *lsa;
   struct listnode *node;
-  u_int16_t length = OSPF_LS_UPD_MIN_SIZE;
+  u_int16_t length = 0;
   unsigned int size_noauth;
   unsigned long delta = stream_get_endp (s);
   unsigned long pp;
@@ -2847,6 +2945,7 @@ ospf_make_ls_upd (struct ospf_interface *oi, struct list *update, struct stream
 
   pp = stream_get_endp (s);
   stream_forward_endp (s, OSPF_LS_UPD_MIN_SIZE);
+  length += OSPF_LS_UPD_MIN_SIZE;
 
   /* Calculate amount of packet usable for data. */
   size_noauth = stream_get_size(s) - ospf_packet_authspace(oi);
@@ -2919,8 +3018,8 @@ ospf_make_ls_ack (struct ospf_interface *oi, struct list *ack, struct stream *s)
   return length;
 }
 
-void
-ospf_hello_send_sub (struct ospf_interface *oi, struct in_addr *addr)
+static void
+ospf_hello_send_sub (struct ospf_interface *oi, in_addr_t addr)
 {
   struct ospf_packet *op;
   u_int16_t length = OSPF_HEADER_SIZE;
@@ -2939,10 +3038,12 @@ ospf_hello_send_sub (struct ospf_interface *oi, struct in_addr *addr)
   /* Set packet length. */
   op->length = length;
 
-  op->dst.s_addr = addr->s_addr;
+  op->dst.s_addr = addr;
 
-  /* Add packet to the interface output queue. */
-  ospf_packet_add (oi, op);
+  /* Add packet to the top of the interface output queue, so that they
+   * can't get delayed by things like long queues of LS Update packets
+   */
+  ospf_packet_add_top (oi, op);
 
   /* Hook thread to write packet. */
   OSPF_ISM_WRITE_ON (oi->ospf);
@@ -2957,7 +3058,7 @@ ospf_poll_send (struct ospf_nbr_nbma *nbr_nbma)
   assert(oi);
 
   /* If this is passive interface, do not send OSPF Hello. */
-  if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE)
+  if (OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE)
     return;
 
   if (oi->type != OSPF_IFTYPE_NBMA)
@@ -2973,7 +3074,7 @@ ospf_poll_send (struct ospf_nbr_nbma *nbr_nbma)
       && oi->state != ISM_DR && oi->state != ISM_Backup)
     return;
 
-  ospf_hello_send_sub (oi, &nbr_nbma->addr);
+  ospf_hello_send_sub (oi, nbr_nbma->addr.s_addr);
 }
 
 int
@@ -3012,7 +3113,7 @@ ospf_hello_reply_timer (struct thread *thread)
     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);
+  ospf_hello_send_sub (nbr->oi, nbr->address.u.prefix4.s_addr);
 
   return 0;
 }
@@ -3021,27 +3122,10 @@ ospf_hello_reply_timer (struct thread *thread)
 void
 ospf_hello_send (struct ospf_interface *oi)
 {
-  struct ospf_packet *op;
-  u_int16_t length = OSPF_HEADER_SIZE;
-
   /* If this is passive interface, do not send OSPF Hello. */
-  if (OSPF_IF_PARAM (oi, passive_interface) == OSPF_IF_PASSIVE)
+  if (OSPF_IF_PASSIVE_STATUS (oi) == OSPF_IF_PASSIVE)
     return;
 
-  op = ospf_packet_new (oi->ifp->mtu);
-
-  /* Prepare OSPF common header. */
-  ospf_make_header (OSPF_MSG_HELLO, oi, op->s);
-
-  /* Prepare OSPF Hello body. */
-  length += ospf_make_hello (oi, op->s);
-
-  /* Fill OSPF header. */
-  ospf_fill_header (oi, op->s, length);
-
-  /* Set packet length. */
-  op->length = length;
-
   if (oi->type == OSPF_IFTYPE_NBMA)
     {
       struct ospf_neighbor *nbr;
@@ -3071,34 +3155,16 @@ ospf_hello_send (struct ospf_interface *oi)
                if (nbr->priority == 0 && oi->state == ISM_DROther)
                  continue;
                /* if oi->state == Waiting, send hello to all neighbors */
-               {
-                 struct ospf_packet *op_dup;
-
-                 op_dup = ospf_packet_dup(op);
-                 op_dup->dst = nbr->address.u.prefix4;
-
-                 /* Add packet to the interface output queue. */
-                 ospf_packet_add (oi, op_dup);
-
-                 OSPF_ISM_WRITE_ON (oi->ospf);
-               }
-
+               ospf_hello_send_sub (oi, nbr->address.u.prefix4.s_addr);
              }
-      ospf_packet_free (op);
     }
   else
     {
       /* Decide destination address. */
       if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
-       op->dst.s_addr = oi->vl_data->peer_addr.s_addr;
-      else 
-       op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
-
-      /* Add packet to the interface output queue. */
-      ospf_packet_add (oi, op);
-
-      /* Hook thread to write packet. */
-      OSPF_ISM_WRITE_ON (oi->ospf);
+        ospf_hello_send_sub (oi, oi->vl_data->peer_addr.s_addr);
+      else
+        ospf_hello_send_sub (oi, htonl (OSPF_ALLSPFROUTERS));
     }
 }
 
@@ -3126,7 +3192,10 @@ ospf_db_desc_send (struct ospf_neighbor *nbr)
   op->length = length;
 
   /* Decide destination address. */
-  op->dst = nbr->address.u.prefix4;
+  if (oi->type == OSPF_IFTYPE_POINTOPOINT) 
+    op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
+  else
+    op->dst = nbr->address.u.prefix4;
 
   /* Add packet to the interface output queue. */
   ospf_packet_add (oi, op);
@@ -3138,7 +3207,7 @@ ospf_db_desc_send (struct ospf_neighbor *nbr)
   if (nbr->last_send)
     ospf_packet_free (nbr->last_send);
   nbr->last_send = ospf_packet_dup (op);
-  gettimeofday (&nbr->last_send_ts, NULL);
+  quagga_gettime (QUAGGA_CLK_MONOTONIC, &nbr->last_send_ts);
 }
 
 /* Re-send Database Description. */
@@ -3185,7 +3254,10 @@ ospf_ls_req_send (struct ospf_neighbor *nbr)
   op->length = length;
 
   /* Decide destination address. */
-  op->dst = nbr->address.u.prefix4;
+  if (oi->type == OSPF_IFTYPE_POINTOPOINT) 
+    op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
+  else
+    op->dst = nbr->address.u.prefix4;
 
   /* Add packet to the interface output queue. */
   ospf_packet_add (oi, op);
@@ -3259,7 +3331,6 @@ ospf_ls_upd_packet_new (struct list *update, struct ospf_interface *oi)
   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,"
@@ -3271,7 +3342,16 @@ ospf_ls_upd_packet_new (struct list *update, struct ospf_interface *oi)
       return NULL;
     }
 
-  return ospf_packet_new (size);
+  /* IP header is built up separately by ospf_write(). This means, that we must
+   * reduce the "affordable" size just calculated by length of an IP header.
+   * This makes sure, that even if we manage to fill the payload with LSA data
+   * completely, the final packet (our data plus IP header) still fits into
+   * outgoing interface MTU. This correction isn't really meaningful for an
+   * oversized LSA, but for consistency the correction is done for both cases.
+   *
+   * P.S. OSPF_MAX_PACKET_SIZE above already includes IP header size
+   */
+  return ospf_packet_new (size - sizeof (struct ip));
 }
 
 static void
@@ -3301,7 +3381,10 @@ ospf_ls_upd_queue_send (struct ospf_interface *oi, struct list *update,
   op->length = length;
 
   /* Decide destination address. */
-  op->dst.s_addr = addr.s_addr;
+  if (oi->type == OSPF_IFTYPE_POINTOPOINT) 
+    op->dst.s_addr = htonl (OSPF_ALLSPFROUTERS);
+  else
+    op->dst.s_addr = addr.s_addr;
 
   /* Add packet to the interface output queue. */
   ospf_packet_add (oi, op);
@@ -3378,13 +3461,12 @@ ospf_ls_upd_send (struct ospf_neighbor *nbr, struct list *update, int flag)
   /* Decide destination address. */
   if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
     p.prefix = oi->vl_data->peer_addr;
+  else if (oi->type == OSPF_IFTYPE_POINTOPOINT) 
+     p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS);
   else if (flag == OSPF_SEND_PACKET_DIRECT)
      p.prefix = nbr->address.u.prefix4;
   else if (oi->state == ISM_DR || oi->state == ISM_Backup)
      p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS);
-  else if ((oi->type == OSPF_IFTYPE_POINTOPOINT) 
-          && (flag == OSPF_SEND_PACKET_INDIRECT))
-     p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS);
   else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
      p.prefix.s_addr = htonl (OSPF_ALLSPFROUTERS);
   else