[zebra 14631] Generic PtP and RFC3021 interface addressing support
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index 24a113d..ad932b5 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -663,7 +663,7 @@
       p.family = AF_INET;
       p.prefixlen = addr->prefixlen;
 
-      if (if_is_pointopoint (ifp))
+      if (ifc_pointopoint (ifc))
 	p.u.prefix4 = dest->u.prefix4;
       else
 	p.u.prefix4 = addr->u.prefix4;
@@ -694,7 +694,7 @@
       p.family = AF_INET6;
       p.prefixlen = addr->prefixlen;
 
-      if (if_is_pointopoint (ifp))
+      if (ifc_pointopoint (ifc))
 	p.u.prefix6 = dest->u.prefix6;
       else
 	p.u.prefix6 = addr->u.prefix6;
@@ -748,7 +748,7 @@
       p.family = AF_INET;
       p.prefixlen = addr->prefixlen;
 
-      if (if_is_pointopoint (ifp))
+      if (ifc_pointopoint (ifc))
 	p.u.prefix4 = dest->u.prefix4;
       else
 	p.u.prefix4 = addr->u.prefix4;
@@ -779,7 +779,7 @@
       p.family = AF_INET6;
       p.prefixlen = addr->prefixlen;
 
-      if (if_is_pointopoint (ifp))
+      if (ifc_pointopoint (ifc))
 	p.u.prefix6 = dest->u.prefix6;
       else
 	p.u.prefix6 = addr->u.prefix6;
diff --git a/lib/if.c b/lib/if.c
index ce3595d..e1a1839 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -189,11 +189,13 @@
   listnode node;
   struct prefix addr;
   struct prefix best;
+  struct prefix peer;
   listnode cnode;
   struct interface *ifp;
   struct prefix *p;
   struct connected *c;
   struct interface *match;
+  int prefixlen;
 
   /* Zero structures - get rid of rubbish from stack */
   memset(&addr, 0, sizeof(addr));
@@ -212,34 +214,24 @@
       for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
 	{
 	  c = getdata (cnode);
+	  p = c->address;
 
-	  if (if_is_pointopoint (ifp))
+	  if (p->family == AF_INET)
 	    {
-	      p = c->address;
+	      prefixlen = p->prefixlen;
 
-	      if (p && p->family == AF_INET)
+	      if (if_is_pointopoint (ifp) ||
+		  prefixlen >= IPV4_MAX_PREFIXLEN - 1)
 		{
-#ifdef OLD_RIB	 /* PTP  links are conventionally identified 
-		     by the address of the far end - MAG */
-		  if (IPV4_ADDR_SAME (&p->u.prefix4, &src))
-		    return ifp;
-#endif
-		  p = c->destination;
-		  if (p && IPV4_ADDR_SAME (&p->u.prefix4, &src))
-		    return ifp;
+		  peer = *c->destination;
+		  peer.prefixlen = prefixlen;
+		  p = &peer;
 		}
-	    }
-	  else
-	    {
-	      p = c->address;
 
-	      if (p->family == AF_INET)
+	      if (prefix_match (p, &addr) && prefixlen > best.prefixlen)
 		{
-		  if (prefix_match (p, &addr) && p->prefixlen > best.prefixlen)
-		    {
-		      best = *p;
-		      match = ifp;
-		    }
+		  best = *p;
+		  match = ifp;
 		}
 	    }
 	}
diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c
index 6187977..4ed0ecd 100644
--- a/ospfd/ospf_snmp.c
+++ b/ospfd/ospf_snmp.c
@@ -1413,7 +1413,7 @@
   /* Lookup first IPv4 address entry. */
   LIST_LOOP (ifp->connected, ifc, nn)
     {
-      if (if_is_pointopoint (ifp))
+      if (ifc_pointopoint (ifc))
 	p = ifc->destination;
       else
 	p = ifc->address;
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index e8bd360..19bc1e5 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -699,17 +699,17 @@
 	  struct connected *co = getdata (cn);
 	  struct prefix *addr;
 
-	  if (if_is_pointopoint (ifp))
+	  if (ifc_pointopoint (co))
 	    addr = co->destination;
 	  else 
 	    addr = co->address;
 
 	  if (p->family == co->address->family &&
 	      ! ospf_if_is_configured (&(addr->u.prefix4)))
-	    if ((if_is_pointopoint (ifp) &&
+	    if ((ifc_pointopoint (co) &&
 		 IPV4_ADDR_SAME (&(addr->u.prefix4), &(p->u.prefix4))) ||
 		prefix_match (p, addr)) 
-	    {
+	      {
 	        struct ospf_interface *oi;
 		
 		oi = ospf_if_new (ifp, co->address);
diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c
index bdfca57..9432717 100644
--- a/ripd/rip_interface.c
+++ b/ripd/rip_interface.c
@@ -391,106 +391,6 @@
 						
   return count;
 }
-						
-						
-						
-
-/* Does this address belongs to me ? */
-int
-if_check_address (struct in_addr addr)
-{
-  listnode node;
-
-  for (node = listhead (iflist); node; nextnode (node))
-    {
-      listnode cnode;
-      struct interface *ifp;
-
-      ifp = getdata (node);
-
-      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
-	{
-	  struct connected *connected;
-	  struct prefix_ipv4 *p;
-
-	  connected = getdata (cnode);
-	  p = (struct prefix_ipv4 *) connected->address;
-
-	  if (p->family != AF_INET)
-	    continue;
-
-	  if (IPV4_ADDR_CMP (&p->prefix, &addr) == 0)
-	    return 1;
-	}
-    }
-  return 0;
-}
-
-/* is this address from a valid neighbor? (RFC2453 - Sec. 3.9.2) */
-int
-if_valid_neighbor (struct in_addr addr)
-{
-  listnode node;
-  struct connected *connected = NULL;
-  struct prefix_ipv4 *p;
-
-  for (node = listhead (iflist); node; nextnode (node))
-    {
-      listnode cnode;
-      struct interface *ifp;
-
-      ifp = getdata (node);
-
-      for (cnode = listhead (ifp->connected); cnode; nextnode (cnode))
-	{
-	  struct prefix *pxn = NULL; /* Prefix of the neighbor */
-	  struct prefix *pxc = NULL; /* Prefix of the connected network */
-
-	  connected = getdata (cnode);
-
-	  if (if_is_pointopoint (ifp))
-	    {
-	      p = (struct prefix_ipv4 *) connected->address;
-
-	      if (p && p->family == AF_INET)
-		{
-		  if (IPV4_ADDR_SAME (&p->prefix, &addr))
-		    return 1;
-
-		  p = (struct prefix_ipv4 *) connected->destination;
-		  if (p && IPV4_ADDR_SAME (&p->prefix, &addr))
-		    return 1;
-		}
-	    }
-	  else
-	    {
-	      p = (struct prefix_ipv4 *) connected->address;
-
-	      if (p->family != AF_INET)
-		continue;
-
-	      pxn = prefix_new();
-	      pxn->family = AF_INET;
-	      pxn->prefixlen = 32;
-	      pxn->u.prefix4 = addr;
-	      
-	      pxc = prefix_new();
-	      prefix_copy(pxc, (struct prefix *) p);
-	      apply_mask(pxc);
-	  
-	      if (prefix_match (pxc, pxn)) 
-		{
-		  prefix_free (pxn);
-		  prefix_free (pxc);
-		  return 1;
-		}
-	      prefix_free(pxc);
-	      prefix_free(pxn);
-	    }
-	}
-    }
-  return 0;
-}
 
 /* Inteface link down message processing. */
 int
diff --git a/ripd/ripd.c b/ripd/ripd.c
index c63bf10..62ebd47 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -976,7 +976,7 @@
   /* The datagram's IPv4 source address should be checked to see
      whether the datagram is from a valid neighbor; the source of the
      datagram must be on a directly connected network  */
-  if (! if_valid_neighbor (from->sin_addr)) 
+  if (if_lookup_address (from->sin_addr) == NULL)
     {
       zlog_info ("This datagram doesn't came from a valid neighbor: %s",
 		 inet_ntoa (from->sin_addr));
@@ -1535,7 +1535,7 @@
     }
 
   /* Check is this packet comming from myself? */
-  if (if_check_address (from.sin_addr)) 
+  if (if_lookup_exact_address (from.sin_addr)) 
     {
       if (IS_RIP_DEBUG_PACKET)
 	zlog_warn ("ignore packet comes from myself");
diff --git a/ripd/ripd.h b/ripd/ripd.h
index 2545db0..17301c3 100644
--- a/ripd/ripd.h
+++ b/ripd/ripd.h
@@ -359,8 +359,6 @@
 void rip_zclient_start ();
 void rip_zclient_reset ();
 void rip_offset_init ();
-int if_check_address (struct in_addr addr);
-int if_valid_neighbor (struct in_addr addr);
 
 int rip_request_send (struct sockaddr_in *, struct interface *, u_char);
 int rip_neighbor_lookup (struct sockaddr_in *);
diff --git a/zebra/connected.c b/zebra/connected.c
index cb43074..22c9a1f 100644
--- a/zebra/connected.c
+++ b/zebra/connected.c
@@ -69,7 +69,7 @@
   p.prefixlen = addr->prefixlen;
 
   /* Point-to-point check. */
-  if (if_is_pointopoint (ifp))
+  if (ifc_pointopoint (ifc))
     p.prefix = dest->prefix;
   else
     p.prefix = addr->prefix;
@@ -162,7 +162,7 @@
   p.family = AF_INET;
   p.prefixlen = addr->prefixlen;
 
-  if (if_is_pointopoint (ifp))
+  if (ifc_pointopoint (ifc))
     p.prefix = dest->prefix;
   else
     p.prefix = addr->prefix;
@@ -249,7 +249,7 @@
   p.family = AF_INET6;
   p.prefixlen = addr->prefixlen;
 
-  if (if_is_pointopoint (ifp) && dest)
+  if (ifc_pointopoint (ifc) && dest)
     {
       if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
 	p.prefix = addr->prefix;
@@ -339,7 +339,7 @@
   p.family = AF_INET6;
   p.prefixlen = addr->prefixlen;
 
-  if (if_is_pointopoint (ifp) && dest)
+  if (ifc_pointopoint (ifc) && dest)
     {
       if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
 	p.prefix = addr->prefix;
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index fa4dc54..1e39d8a 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -388,6 +388,7 @@
   void *broad = NULL;
   u_char flags = 0;
   char *label = NULL;
+  int peeronly = 0;
 
   ifa = NLMSG_DATA (h);
 
@@ -416,40 +417,51 @@
       return -1;
     }
 
-  if (tb[IFA_ADDRESS] == NULL)
-    tb[IFA_ADDRESS] = tb[IFA_LOCAL];
-
-  if (ifp->flags & IFF_POINTOPOINT)
+  if (IS_ZEBRA_DEBUG_KERNEL)	/* remove this line to see initial ifcfg */
     {
+      char buf[BUFSIZ];
+      zlog_info ("netlink_interface_addr %s %s/%d:",
+		 lookup (nlmsg_str, h->nlmsg_type),
+		 ifp->name, ifa->ifa_prefixlen);
       if (tb[IFA_LOCAL])
-	{
-	  addr = RTA_DATA (tb[IFA_LOCAL]);
-	  if (tb[IFA_ADDRESS]) 
-	    broad = RTA_DATA (tb[IFA_ADDRESS]);
-	  else
-	    broad = NULL;
-	}
-      else
-	{
-	  if (tb[IFA_ADDRESS])
-	    addr = RTA_DATA (tb[IFA_ADDRESS]);
-	  else
-	    addr = NULL;
-	}
-    }
-  else
-    {
+	zlog_info ("  IFA_LOCAL     %s", inet_ntop (ifa->ifa_family,
+		  RTA_DATA (tb[IFA_LOCAL]), buf, BUFSIZ));
       if (tb[IFA_ADDRESS])
-	addr = RTA_DATA (tb[IFA_ADDRESS]);
-      else
-	addr = NULL;
-
+	zlog_info ("  IFA_ADDRESS   %s", inet_ntop (ifa->ifa_family,
+		  RTA_DATA (tb[IFA_ADDRESS]), buf, BUFSIZ));
       if (tb[IFA_BROADCAST])
-	broad = RTA_DATA(tb[IFA_BROADCAST]);
-      else
-	broad = NULL;
+	zlog_info ("  IFA_BROADCAST %s", inet_ntop (ifa->ifa_family,
+		  RTA_DATA (tb[IFA_BROADCAST]), buf, BUFSIZ));
+      if (tb[IFA_LABEL] && strcmp (ifp->name, RTA_DATA (tb[IFA_LABEL])))
+	zlog_info ("  IFA_LABEL     %s", RTA_DATA (tb[IFA_LABEL]));
     }
 
+  /* peer or broadcast network? */
+  if (ifa->ifa_family == AF_INET)
+    peeronly = if_is_pointopoint (ifp) ||
+	       ifa->ifa_prefixlen >= IPV4_MAX_PREFIXLEN - 1;
+#ifdef HAVE_IPV6
+  if (ifa->ifa_family == AF_INET6)
+    peeronly = if_is_pointopoint (ifp) ||
+	       ifa->ifa_prefixlen >= IPV6_MAX_PREFIXLEN - 1;
+#endif /* HAVE_IPV6*/
+
+  /* network. prefixlen applies to IFA_ADDRESS rather than IFA_LOCAL */
+  if (tb[IFA_ADDRESS] && !peeronly)
+    addr = RTA_DATA (tb[IFA_ADDRESS]);
+  else if (tb[IFA_LOCAL])
+    addr = RTA_DATA (tb[IFA_LOCAL]);
+  else
+    addr = NULL;
+
+  /* broadcast/peer */
+  if (tb[IFA_BROADCAST])
+    broad = RTA_DATA (tb[IFA_BROADCAST]);
+  else if (tb[IFA_ADDRESS] && peeronly)
+    broad = RTA_DATA (tb[IFA_ADDRESS]);		/* peer address specified */
+  else
+    broad = NULL;
+
   /* Flags. */
   if (ifa->ifa_flags & IFA_F_SECONDARY)
     SET_FLAG (flags, ZEBRA_IFA_SECONDARY);