2005-02-08 Andrew J. Schorr <ajschorr@alumni.princeton.edu>

	* ospf_interface.h: Improve passive_interface comment.  Add new
	  multicast_memberships bitmask to struct ospf_interface to track
	  active multicast subscriptions.  Declare new function
	  ospf_if_set_multicast.
	* ospf_interface.c: (ospf_if_set_multicast) New function to configure
	  multicast memberships properly based on the current
	  multicast_memberships status and the current values of the
	  ospf_interface state, type, and passive_interface status.
	  (ospf_if_up) Remove call to ospf_if_add_allspfrouters (this is
	  now handled by ism_change_state's call to ospf_if_set_multicast).
	  (ospf_if_down) Remove call to ospf_if_drop_allspfrouters (now
	  handled by ism_change_state).
	* ospf_ism.c: (ospf_dr_election) Remove logic to join or leave
	  the DRouters multicast group (now handled by ism_change_state's call
	  to ospf_if_set_multicast).
	  (ism_change_state) Add call to ospf_if_set_multicast to change
	  multicast memberships as necessary to reflect the new interface state.
	* ospf_packet.c: (ospf_hello) When a Hello packet is received on a
	  passive interface: 1. Increase the severity of the error message
	  from LOG_INFO to LOG_WARNING; 2. Add more information to the error
	  message (packet destination address and interface address);
	  and 3. If the packet was sent to ospf-all-routers, then try
	  to fix the multicast group memberships.
	  (ospf_read) When a packet is received on an interface whose state
	  is ISM_Down, enhance the warning message to show the packet
	  destination address, and try to update/fix the multicast group
	  memberships if the packet was sent to a multicast address.
	  When a packet is received for ospf-designated-routers, but the
	  current interface state is not DR or BDR, then increase the
	  severity level of the error message from LOG_INFO to LOG_WARNING,
	  and try to fix the multicast group memberships.
	* ospf_vty.c: (ospf_passive_interface) Call ospf_if_set_multicast for
	  any ospf interface that may have changed from active to passive.
	  (no_ospf_passive_interface) Call ospf_if_set_multicast for
	  any ospf interface that may have changed from passive to active.
	  (show_ip_ospf_interface_sub) Show multicast group memberships.
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index da08360..df71fad 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -727,6 +727,60 @@
   return 0;
 }
 
+void
+ospf_if_set_multicast(struct ospf_interface *oi)
+{
+  if ((oi->state > ISM_Loopback) &&
+      (oi->type != OSPF_IFTYPE_LOOPBACK) &&
+      (oi->type != OSPF_IFTYPE_VIRTUALLINK) &&
+      (OSPF_IF_PARAM(oi, passive_interface) == OSPF_IF_ACTIVE))
+    {
+      /* The interface should belong to the OSPF-all-routers group. */
+      if (!CHECK_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS) &&
+	  (ospf_if_add_allspfrouters(oi->ospf, oi->address,
+				     oi->ifp->ifindex) >= 0))
+	/* Set the flag only if the system call to join succeeded. */
+        SET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
+    }
+  else
+    {
+      /* The interface should NOT belong to the OSPF-all-routers group. */
+      if (CHECK_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS))
+        {
+	  ospf_if_drop_allspfrouters (oi->ospf, oi->address, oi->ifp->ifindex);
+	  /* Unset the flag regardless of whether the system call to leave
+	     the group succeeded, since it's much safer to assume that
+	     we are not a member. */
+	  UNSET_FLAG(oi->multicast_memberships, MEMBER_ALLROUTERS);
+        }
+    }
+
+  if (((oi->type == OSPF_IFTYPE_BROADCAST) ||
+       (oi->type == OSPF_IFTYPE_POINTOPOINT)) &&
+      ((oi->state == ISM_DR) || (oi->state == ISM_Backup)) &&
+      (OSPF_IF_PARAM(oi, passive_interface) == OSPF_IF_ACTIVE))
+    {
+      /* The interface should belong to the OSPF-designated-routers group. */
+      if (!CHECK_FLAG(oi->multicast_memberships, MEMBER_DROUTERS) &&
+	  (ospf_if_add_alldrouters(oi->ospf, oi->address,
+	  			   oi->ifp->ifindex) >= 0))
+	/* Set the flag only if the system call to join succeeded. */
+        SET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
+    }
+  else
+    {
+      /* The interface should NOT belong to the OSPF-designated-routers group */
+      if (CHECK_FLAG(oi->multicast_memberships, MEMBER_DROUTERS))
+        {
+	  ospf_if_drop_alldrouters(oi->ospf, oi->address, oi->ifp->ifindex);
+	  /* Unset the flag regardless of whether the system call to leave
+	     the group succeeded, since it's much safer to assume that
+	     we are not a member. */
+          UNSET_FLAG(oi->multicast_memberships, MEMBER_DROUTERS);
+        }
+    }
+}
+
 int
 ospf_if_up (struct ospf_interface *oi)
 {
@@ -737,8 +791,6 @@
     OSPF_ISM_EVENT_SCHEDULE (oi, ISM_LoopInd);
   else
     {
-      if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
-	ospf_if_add_allspfrouters (oi->ospf, oi->address, oi->ifp->ifindex);
       ospf_if_stream_set (oi);
       OSPF_ISM_EVENT_SCHEDULE (oi, ISM_InterfaceUp);
     }
@@ -755,9 +807,6 @@
   OSPF_ISM_EVENT_EXECUTE (oi, ISM_InterfaceDown);
   /* Shutdown packet reception and sending */
   ospf_if_stream_unset (oi);
-  if (oi->type != OSPF_IFTYPE_VIRTUALLINK)
-    ospf_if_drop_allspfrouters (oi->ospf, oi->address, oi->ifp->ifindex);
-
 
   return 1;
 }