pimd: FIXED C14 T32 Detection of interface primary address changes may fail.
diff --git a/pimd/CAVEATS b/pimd/CAVEATS
index ba6426d..7e2820b 100644
--- a/pimd/CAVEATS
+++ b/pimd/CAVEATS
@@ -109,8 +109,8 @@
 
     See also pim_sock_delete().
 
-C14 Detection of interface primary address changes may fail when there
-    are multiple addresses.
+C14 FIXED Detection of interface primary address changes may fail when
+    there are multiple addresses.
     See also TODO T32.
 
 C15 Changes in interface secondary address list are not immediately
diff --git a/pimd/TODO b/pimd/TODO
index 3a3330d..80835e4 100644
--- a/pimd/TODO
+++ b/pimd/TODO
@@ -267,8 +267,8 @@
     See also CAVEAT C15.
     See also RFC 4601: 4.3.1.  Sending Hello Messages
 
-T32 Detection of interface primary address changes may fail when there
-    are multiple addresses.
+T32 FIXED Detection of interface primary address changes may fail when
+    there are multiple addresses.
     See also CAVEAT C14.
 
     pim_find_primary_addr() should return interface primary address
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index 72626ec..3dee751 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -286,6 +286,7 @@
 {
   struct pim_interface *pim_ifp;
   struct in_addr new_prim_addr;
+  int changed;
 
   pim_ifp = ifp->info;
   if (!pim_ifp)
@@ -293,17 +294,20 @@
 
   new_prim_addr = pim_find_primary_addr(ifp);
 
+  changed = new_prim_addr.s_addr != pim_ifp->primary_address.s_addr;
+
   if (PIM_DEBUG_ZEBRA) {
     char new_prim_str[100];
     char old_prim_str[100];
     pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
     pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
-    zlog_debug("%s: old primary addr %s, new primary addr %s on interface %s",
+    zlog_debug("%s: old=%s new=%s on interface %s: %s",
 	       __PRETTY_FUNCTION__, 
-	       old_prim_str, new_prim_str, ifp->name);
+	       old_prim_str, new_prim_str, ifp->name,
+	       changed ? "changed" : "unchanged");
   }
 
-  if (new_prim_addr.s_addr != pim_ifp->primary_address.s_addr) {
+  if (changed) {
     struct in_addr old_addr = pim_ifp->primary_address;
     pim_ifp->primary_address = new_prim_addr;
 
@@ -328,6 +332,16 @@
   if (!if_is_operative(ifp))
     return;
 
+  if (PIM_DEBUG_ZEBRA) {
+    char buf[BUFSIZ];
+    prefix2str(ifc->address, buf, BUFSIZ);
+    zlog_debug("%s: %s connected IP address %s %s",
+	       __PRETTY_FUNCTION__,
+	       ifp->name, buf,
+	       CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
+	       "secondary" : "primary");
+  }
+
   ifaddr = ifc->address->u.prefix4;
 
   detect_primary_address_change(ifp, __PRETTY_FUNCTION__);
@@ -437,6 +451,16 @@
   ifp = ifc->ifp;
   zassert(ifp);
 
+  if (PIM_DEBUG_ZEBRA) {
+    char buf[BUFSIZ];
+    prefix2str(ifc->address, buf, BUFSIZ);
+    zlog_debug("%s: %s disconnected IP address %s %s",
+	       __PRETTY_FUNCTION__,
+	       ifp->name, buf,
+	       CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ?
+	       "secondary" : "primary");
+  }
+
   detect_primary_address_change(ifp, __PRETTY_FUNCTION__);
 
   pim_if_addr_del_igmp(ifc);
@@ -523,7 +547,7 @@
   }
 }
 
-static struct in_addr find_first_addr(struct interface *ifp)
+static struct in_addr find_first_nonsec_addr(struct interface *ifp)
 {
   struct connected *ifc;
   struct listnode *node;
@@ -541,6 +565,9 @@
       continue;
     }
 
+    if (CHECK_FLAG (ifc->flags, ZEBRA_IFA_SECONDARY))
+      continue;
+
     return p->u.prefix4;
   }
 
@@ -551,7 +578,7 @@
 
 struct in_addr pim_find_primary_addr(struct interface *ifp)
 {
-  return find_first_addr(ifp);
+  return find_first_nonsec_addr(ifp);
 }
 
 /*
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 820b0ef..f0aa84f 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -203,10 +203,12 @@
     if (p->family != AF_INET)
       continue;
     
-    zlog_debug("%s %s: interface %s address %s",
+    zlog_debug("%s %s: interface %s address %s %s",
 	       __FILE__, __PRETTY_FUNCTION__,
 	       ifp->name,
-	       inet_ntoa(p->u.prefix4));
+	       inet_ntoa(p->u.prefix4),
+	       CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY) ? 
+	       "secondary" : "primary");
   }
 }
 #endif
@@ -238,15 +240,36 @@
   if (PIM_DEBUG_ZEBRA) {
     char buf[BUFSIZ];
     prefix2str(p, buf, BUFSIZ);
-    zlog_debug("%s: %s connected IP address %s flags %u",
+    zlog_debug("%s: %s connected IP address %s flags %u %s",
 	       __PRETTY_FUNCTION__,
-	       c->ifp->name, buf, c->flags);
+	       c->ifp->name, buf, c->flags,
+	       CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
     
 #ifdef PIM_DEBUG_IFADDR_DUMP
     dump_if_address(c->ifp);
 #endif
   }
 
+  if (!CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY)) {
+    /* trying to add primary address */
+
+    struct in_addr primary_addr = pim_find_primary_addr(c->ifp);
+    if (primary_addr.s_addr != p->u.prefix4.s_addr) {
+      /* but we had a primary address already */
+
+      char buf[BUFSIZ];
+      char old[100];
+
+      prefix2str(p, buf, BUFSIZ);
+      pim_inet4_dump("<old?>", primary_addr, old, sizeof(old));
+
+      zlog_warn("%s: %s primary addr old=%s: forcing secondary flag on new=%s",
+		__PRETTY_FUNCTION__,
+		c->ifp->name, old, buf);
+      SET_FLAG(c->flags, ZEBRA_IFA_SECONDARY);
+    }
+  }
+
   pim_if_addr_add(c);
 
   return 0;
@@ -279,15 +302,16 @@
   if (PIM_DEBUG_ZEBRA) {
     char buf[BUFSIZ];
     prefix2str(p, buf, BUFSIZ);
-    zlog_debug("%s: %s disconnected IP address %s flags %u",
+    zlog_debug("%s: %s disconnected IP address %s flags %u %s",
 	       __PRETTY_FUNCTION__,
-	       c->ifp->name, buf, c->flags);
+	       c->ifp->name, buf, c->flags,
+	       CHECK_FLAG(c->flags, ZEBRA_IFA_SECONDARY) ? "secondary" : "primary");
     
 #ifdef PIM_DEBUG_IFADDR_DUMP
     dump_if_address(c->ifp);
 #endif
   }
-  
+
   pim_if_addr_del(c);
   
   return 0;