]> 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 54b30ca750d41db0b61100062424228f7abe3f59..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. */
-        SET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
-        ospf_if_set_multicast(oi);
-      }
-    return;
-  }
-
   /* get neighbor prefix. */
   p.family = AF_INET;
   p.prefixlen = ip_masklen (hello->network_mask);
@@ -785,16 +818,19 @@ ospf_hello (struct ip *iph, struct ospf_header *ospfh,
       && oi->type != OSPF_IFTYPE_VIRTUALLINK)
     if (oi->address->prefixlen != p.prefixlen)
       {
-       zlog_warn ("Packet %s [Hello:RECV]: NetworkMask mismatch.",
-                  inet_ntoa (ospfh->router_id));
+       zlog_warn ("Packet %s [Hello:RECV]: NetworkMask mismatch on %s (configured prefix length is %d, but hello packet indicates %d).",
+                  inet_ntoa(ospfh->router_id), IF_NAME(oi),
+                  (int)oi->address->prefixlen, (int)p.prefixlen);
        return;
       }
 
   /* 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;
     }
 
@@ -803,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;
         }
     }
@@ -885,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,
@@ -905,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;
@@ -915,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;
@@ -1034,31 +1072,51 @@ 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 */
   if (IS_SET_DD_MS (nbr->dd_flags))
     {
       nbr->dd_seqnum++;
-      /* Entire DD packet sent. */
+
+      /* Both sides have no More, then we're done with Exchange */
       if (!IS_SET_DD_M (dd->flags) && !IS_SET_DD_M (nbr->dd_flags))
        OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone);
       else
-       /* Send new DD packet. */
        ospf_db_desc_send (nbr);
     }
   /* Slave */
@@ -1066,17 +1124,21 @@ ospf_db_desc_proc (struct stream *s, struct ospf_interface *oi,
     {
       nbr->dd_seqnum = ntohl (dd->dd_seqnum);
 
-      /* When master's more flags is not set. */
-      if (!IS_SET_DD_M (dd->flags) && ospf_db_summary_isempty (nbr))
-       {
-         nbr->dd_flags &= ~(OSPF_DD_FLAG_M);
-         OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone);
-       }
-
-      /* Send DD packet in reply. */
+      /* Send DD packet in reply. 
+       * 
+       * Must be done to acknowledge the Master's DD, regardless of
+       * whether we have more LSAs ourselves to describe.
+       *
+       * This function will clear the 'More' bit, if after this DD
+       * we have no more LSAs to describe to the master..
+       */
       ospf_db_desc_send (nbr);
+      
+      /* Slave can raise ExchangeDone now, if master is also done */
+      if (!IS_SET_DD_M (dd->flags) && !IS_SET_DD_M (nbr->dd_flags))
+       OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_ExchangeDone);
     }
-
+  
   /* Save received neighbor values from DD. */
   ospf_db_desc_save_current (nbr, dd);
 }
@@ -1171,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)
     {
@@ -1199,7 +1264,9 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
              zlog_info ("Packet[DD]: Neighbor %s Negotiation done (Slave).",
                         inet_ntoa(nbr->router_id));
              nbr->dd_seqnum = ntohl (dd->dd_seqnum);
-             nbr->dd_flags &= ~(OSPF_DD_FLAG_MS|OSPF_DD_FLAG_I); /* Reset I/MS */
+             
+             /* Reset I/MS */
+             UNSET_FLAG (nbr->dd_flags, (OSPF_DD_FLAG_MS|OSPF_DD_FLAG_I));
            }
          else
            {
@@ -1216,7 +1283,8 @@ ospf_db_desc (struct ip *iph, struct ospf_header *ospfh,
        {
          zlog_info ("Packet[DD]: Neighbor %s Negotiation done (Master).",
                     inet_ntoa(nbr->router_id));
-         nbr->dd_flags &= ~OSPF_DD_FLAG_I;
+          /* Reset I, leaving MS */
+          UNSET_FLAG (nbr->dd_flags, OSPF_DD_FLAG_I);
        }
       else
        {
@@ -1335,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)
                {
@@ -1389,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 &&
@@ -1621,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)
     {
@@ -1701,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. */
@@ -1920,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);
 }
@@ -1953,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: "
@@ -2056,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);
@@ -2253,8 +2340,8 @@ ospf_verify_header (struct stream *ibuf, struct ospf_interface *oi,
   /* Check authentication. */
   if (ospf_auth_type (oi) != ntohs (ospfh->auth_type))
     {
-      zlog_warn ("interface %s: ospf_read authentication type mismatch.",
-                IF_NAME (oi));
+      zlog_warn ("interface %s: auth-type mismatch, local %d, rcvd %d",
+                IF_NAME (oi), ospf_auth_type (oi), ntohs (ospfh->auth_type));
       return -1;
     }
 
@@ -2350,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
@@ -2363,20 +2476,22 @@ ospf_read (struct thread *thread)
     {
       if ((oi = ospf_associate_packet_vl (ospf, ifp, iph, ospfh)) == NULL)
         {
-          zlog_debug ("Packet from [%s] received on link %s"
-                     " but no ospf_interface",
-                     inet_ntoa (iph->ip_src), ifp->name);
+          if (IS_DEBUG_OSPF_EVENT)
+            zlog_debug ("Packet from [%s] received on link %s"
+                        " but no ospf_interface",
+                        inet_ntoa (iph->ip_src), ifp->name);
           return 0;
         }
     }
-    
+
   /* else it must be a local ospf interface, check it was received on 
    * correct link 
    */
   else if (oi->ifp != ifp)
     {
-      zlog_warn ("Packet from [%s] received on wrong link %s",
-                 inet_ntoa (iph->ip_src), ifp->name); 
+      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)
@@ -2389,9 +2504,9 @@ ospf_read (struct thread *thread)
                 ifp->name, if_flag_dump(ifp->flags));
       /* Fix multicast memberships? */
       if (iph->ip_dst.s_addr == htonl(OSPF_ALLSPFROUTERS))
-       SET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
+        OI_MEMBER_JOINED(oi, MEMBER_ALLROUTERS);
       else if (iph->ip_dst.s_addr == htonl(OSPF_ALLDROUTERS))
-       SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
+       OI_MEMBER_JOINED(oi, MEMBER_DROUTERS);
       if (oi->multicast_memberships)
        ospf_if_set_multicast(oi);
       return 0;
@@ -2674,23 +2789,16 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
 #endif /* HAVE_OPAQUE_LSA */
   stream_putc (s, options);
 
-  /* Keep pointer to flags. */
+  /* DD flags */
   pp = stream_get_endp (s);
   stream_putc (s, nbr->dd_flags);
 
   /* Set DD Sequence Number. */
   stream_putl (s, nbr->dd_seqnum);
 
+  /* shortcut unneeded walk of (empty) summary LSDBs */
   if (ospf_db_summary_isempty (nbr))
-    {
-      if (nbr->state >= NSM_Exchange)
-       {
-         nbr->dd_flags &= ~OSPF_DD_FLAG_M;
-         /* Set DD flags again */
-         stream_putc_at (s, pp, nbr->dd_flags);
-       }
-      return length;
-    }
+    goto empty;
 
   /* Describe LSA Header from Database Summary List. */
   lsdb = &nbr->db_sum;
@@ -2742,6 +2850,21 @@ ospf_make_db_desc (struct ospf_interface *oi, struct ospf_neighbor *nbr,
          }
     }
 
+  /* Update 'More' bit */
+  if (ospf_db_summary_isempty (nbr))
+    {
+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;
 }
 
@@ -2762,7 +2885,7 @@ ospf_make_ls_req_func (struct stream *s, u_int16_t *length,
   stream_put_ipv4 (s, lsa->data->id.s_addr);
   stream_put_ipv4 (s, lsa->data->adv_router.s_addr);
   
-  ospf_lsa_unlock (nbr->ls_req_last);
+  ospf_lsa_unlock (&nbr->ls_req_last);
   nbr->ls_req_last = ospf_lsa_lock (lsa);
   
   *length += 12;
@@ -2811,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;
@@ -2822,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);
@@ -2858,7 +2982,7 @@ ospf_make_ls_upd (struct ospf_interface *oi, struct list *update, struct stream
       count++;
 
       list_delete_node (update, node);
-      ospf_lsa_unlock (lsa);
+      ospf_lsa_unlock (&lsa); /* oi->ls_upd_queue */
     }
 
   /* Now set #LSAs. */
@@ -2872,17 +2996,13 @@ ospf_make_ls_upd (struct ospf_interface *oi, struct list *update, struct stream
 static int
 ospf_make_ls_ack (struct ospf_interface *oi, struct list *ack, struct stream *s)
 {
-  struct list *rm_list;
-  struct listnode *node;
+  struct listnode *node, *nnode;
   u_int16_t length = OSPF_LS_ACK_MIN_SIZE;
   unsigned long delta = stream_get_endp(s) + 24;
   struct ospf_lsa *lsa;
 
-  rm_list = list_new ();
-  
-  for (ALL_LIST_ELEMENTS_RO (ack, node, lsa))
+  for (ALL_LIST_ELEMENTS (ack, node, nnode, lsa))
     {
-      lsa = listgetdata (node);
       assert (lsa);
       
       if (length + delta > ospf_packet_max (oi))
@@ -2891,26 +3011,15 @@ ospf_make_ls_ack (struct ospf_interface *oi, struct list *ack, struct stream *s)
       stream_put (s, lsa->data, OSPF_LSA_HEADER_SIZE);
       length += OSPF_LSA_HEADER_SIZE;
       
-      listnode_add (rm_list, lsa);
-    }
-  
-  /* Remove LSA from LS-Ack list. */
-  /* XXX: this loop should be removed and the list move done in previous
-   * loop
-   */
-  for (ALL_LIST_ELEMENTS_RO (rm_list, node, lsa))
-    {
       listnode_delete (ack, lsa);
-      ospf_lsa_unlock (lsa);
+      ospf_lsa_unlock (&lsa); /* oi->ls_ack_direct.ls_ack */
     }
   
-  list_delete (rm_list);
-  
   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;
@@ -2929,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);
@@ -2947,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)
@@ -2963,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
@@ -3002,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;
 }
@@ -3011,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;
@@ -3061,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));
     }
 }
 
@@ -3116,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);
@@ -3128,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. */
@@ -3175,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);
@@ -3249,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,"
@@ -3261,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
@@ -3291,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);
@@ -3368,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
@@ -3394,10 +3486,7 @@ ospf_ls_upd_send (struct ospf_neighbor *nbr, struct list *update, int flag)
     rn->info = list_new ();
 
   for (ALL_LIST_ELEMENTS_RO (update, node, lsa))
-    {
-      ospf_lsa_lock (lsa);
-      listnode_add (rn->info, lsa);
-    }
+    listnode_add (rn->info, ospf_lsa_lock (lsa)); /* oi->ls_upd_queue */
 
   if (oi->t_ls_upd_event == NULL)
     oi->t_ls_upd_event =