2005-10-06 Alain Ritoux <alain.ritoux@6wind.com>

        * ospf_snmp.c: Avoid mixing interface and ospf_interface objects
          which now allows snmpwalk to work with ospfIfTable and
          also with ospfIfMetricTable
diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c
index 05e4de8..71cb308 100644
--- a/ospfd/ospf_snmp.c
+++ b/ospfd/ospf_snmp.c
@@ -1458,12 +1458,13 @@
     {
       if (addr)
 	{
+	  /* Usual interfaces --> Sort them based on interface IPv4 addresses */
 	  if (ntohl (osif->addr.s_addr) > ntohl (addr->s_addr))
 	    break;
 	}
       else
 	{
-	  /* Unnumbered interface. */
+	  /* Unnumbered interfaces --> Sort them based on interface indexes */
 	  if (osif->addr.s_addr != 0 || osif->ifindex > ifindex)
 	    break;
 	}
@@ -1471,77 +1472,131 @@
     }
 
   osif = ospf_snmp_if_new ();
-  if (addr)
+  if (addr) /* Usual interface */
+  {
     osif->addr = *addr;
-  else
+    
+    /* This field is used for storing ospfAddressLessIf OID value,
+     * conform to RFC1850 OSPF-MIB specification, it must be 0 for
+     * usual interface */
+    osif->ifindex = 0;
+  }
+  else  /* Unnumbered interface */
     osif->ifindex = ifindex;
   osif->ifp = ifp;
 
   listnode_add_after (ospf_snmp_iflist, pn, osif);
 }
 
-struct interface *
+int
+ospf_snmp_is_if_have_addr (struct interface *ifp)
+{
+  struct prefix *p;
+  struct listnode *nn;
+  struct connected *ifc;
+
+  /* Is this interface having any connected IPv4 address ? */
+  for (ALL_LIST_ELEMENTS_RO (ifp->connected, nn, ifc))
+  {
+    if (if_is_pointopoint (ifp))
+      p = ifc->destination;
+    else
+      p = ifc->address;
+
+    if (p->family == AF_INET)
+      return 1;
+  }
+  
+  return 0;
+}
+
+struct ospf_interface *
 ospf_snmp_if_lookup (struct in_addr *ifaddr, unsigned int *ifindex)
 {
   struct listnode *node;
   struct ospf_snmp_if *osif;
+  struct ospf_interface *oi = NULL;
+  struct ospf *ospf = ospf_lookup ();
 
   for (ALL_LIST_ELEMENTS_RO (ospf_snmp_iflist, node, osif))
     {  
       if (ifaddr->s_addr)
-	{
-	  if (IPV4_ADDR_SAME (&osif->addr, ifaddr))
-	    return osif->ifp;
-	}
+        {
+	      if (IPV4_ADDR_SAME (&osif->addr, ifaddr))
+            oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr);
+        }
       else
-	{
-	  if (osif->ifindex == *ifindex)
-	    return osif->ifp;
-	}
+        {
+	      if (osif->ifindex == *ifindex)
+            oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr);
+        }
     }
-  return NULL;
+  return oi;
 }
 
-struct interface *
+struct ospf_interface *
 ospf_snmp_if_lookup_next (struct in_addr *ifaddr, unsigned int *ifindex,
 			  int ifaddr_next, int ifindex_next)
 {
   struct ospf_snmp_if *osif;
   struct listnode *nn;
+  struct ospf *ospf = ospf_lookup ();
+  struct ospf_interface *oi = NULL;
 
+  if (ospf == NULL)
+    return NULL;
+
+  /* No instance is specified --> Return the first OSPF interface */
   if (ifaddr_next)
     {
-      nn = listhead (ospf_snmp_iflist);
-      if (nn)
+      for (ALL_LIST_ELEMENTS_RO (ospf_snmp_iflist, nn, osif))
 	{
 	  osif = listgetdata (nn);
 	  *ifaddr = osif->addr;
 	  *ifindex = osif->ifindex;
-	  return osif->ifp;
+          /* Because no instance is specified, we don't care about the kind of 
+           * interface (usual or unnumbered), just returning the first valid 
+           * OSPF interface */
+          oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr);
+          if (oi)
+            return (oi);
 	}
       return NULL;
     }
 
+  /* An instance is specified --> Return the next OSPF interface */
   for (ALL_LIST_ELEMENTS_RO (ospf_snmp_iflist, nn, osif))
     {
-      if (ifaddr->s_addr)
-	{
-	  if (ntohl (osif->addr.s_addr) > ntohl (ifaddr->s_addr))
-	    {
-	      *ifaddr = osif->addr;
-	      *ifindex = osif->ifindex;
-	      return osif->ifp;
-	    }
-	}
-      else
-	{
-	  if (osif->ifindex > *ifindex || osif->addr.s_addr)
-	    {
-	      *ifaddr = osif->addr;
-	      *ifindex = osif->ifindex;
-	      return osif->ifp;
-	    }
-	}
+      /* Usual interface */
+      if (ifaddr->s_addr) 
+        /* The interface must have valid AF_INET connected address */
+        /* it must have lager IPv4 address value than the lookup entry */
+        if ((ospf_snmp_is_if_have_addr(osif->ifp)) &&
+            (ntohl (osif->addr.s_addr) > ntohl (ifaddr->s_addr)))
+          {
+            *ifaddr = osif->addr;
+            *ifindex = osif->ifindex;
+        
+            /* and it must be an OSPF interface */
+            oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr);
+            if (oi)
+              return oi;
+          }
+      /* Unnumbered interface */
+      else  
+        /* The interface must NOT have valid AF_INET connected address */
+        /* it must have lager interface index than the lookup entry */
+        if ((!ospf_snmp_is_if_have_addr(osif->ifp)) &&
+            (osif->ifindex > *ifindex))
+          {
+            *ifaddr = osif->addr;
+            *ifindex = osif->ifindex;
+        
+            /* and it must be an OSPF interface */
+            oi = ospf_if_lookup_by_local_addr (ospf, osif->ifp, *ifaddr);
+            if (oi)
+              return oi;
+          }
     }
   return NULL;
 }
@@ -1560,14 +1615,14 @@
   return ospf_snmp_iftype_broadcast;
 }
 
-struct interface *
+struct ospf_interface *
 ospfIfLookup (struct variable *v, oid *name, size_t *length,
 	      struct in_addr *ifaddr, unsigned int *ifindex, int exact)
 {
   unsigned int len;
   int ifaddr_next = 0;
   int ifindex_next = 0;
-  struct interface *ifp;
+  struct ospf_interface *oi;
   oid *offset;
 
   if (exact)
@@ -1599,16 +1654,16 @@
       if (len == 1)
 	*ifindex = name[v->namelen + IN_ADDR_SIZE];
 
-      ifp = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next,
+      oi = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next,
 				      ifindex_next);
-      if (ifp)
+      if (oi)
 	{
 	  *length = v->namelen + IN_ADDR_SIZE + 1;
 	  offset = name + v->namelen;
 	  oid_copy_addr (offset, ifaddr, IN_ADDR_SIZE);
 	  offset += IN_ADDR_SIZE;
 	  *offset = *ifindex;
-	  return ifp;
+	  return oi;
 	}
     }
   return NULL;
@@ -1618,7 +1673,6 @@
 ospfIfEntry (struct variable *v, oid *name, size_t *length, int exact,
 	     size_t  *var_len, WriteMethod **write_method)
 {
-  struct interface *ifp;
   unsigned int ifindex;
   struct in_addr ifaddr;
   struct ospf_interface *oi;
@@ -1632,11 +1686,7 @@
   if (ospf == NULL)
     return NULL;
 
-  ifp = ospfIfLookup (v, name, length, &ifaddr, &ifindex, exact);
-  if (ifp == NULL)
-    return NULL;
-
-  oi = ospf_if_lookup_by_local_addr (ospf, ifp, ifaddr);
+  oi = ospfIfLookup (v, name, length, &ifaddr, &ifindex, exact);
   if (oi == NULL)
     return NULL;
 
@@ -1656,7 +1706,7 @@
 	return SNMP_IPADDRESS (ospf_empty_addr);
       break;
     case OSPFIFTYPE:		/* 4 */
-      return SNMP_INTEGER (ospf_snmp_iftype (ifp));
+      return SNMP_INTEGER (ospf_snmp_iftype (oi->ifp));
       break;
     case OSPFIFADMINSTAT:	/* 5 */
       if (oi)
@@ -1725,14 +1775,14 @@
 
 #define OSPF_SNMP_METRIC_VALUE 1
 
-struct interface *
+struct ospf_interface *
 ospfIfMetricLookup (struct variable *v, oid *name, size_t *length,
 		    struct in_addr *ifaddr, unsigned int *ifindex, int exact)
 {
   unsigned int len;
   int ifaddr_next = 0;
   int ifindex_next = 0;
-  struct interface *ifp;
+  struct ospf_interface *oi;
   oid *offset;
   int metric;
 
@@ -1769,9 +1819,9 @@
       if (len == 1)
 	*ifindex = name[v->namelen + IN_ADDR_SIZE];
 
-      ifp = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next,
+      oi = ospf_snmp_if_lookup_next (ifaddr, ifindex, ifaddr_next,
 				      ifindex_next);
-      if (ifp)
+      if (oi)
 	{
 	  *length = v->namelen + IN_ADDR_SIZE + 1 + 1;
 	  offset = name + v->namelen;
@@ -1780,7 +1830,7 @@
 	  *offset = *ifindex;
 	  offset++;
 	  *offset = OSPF_SNMP_METRIC_VALUE;
-	  return ifp;
+	  return oi;
 	}
     }
   return NULL;
@@ -1791,7 +1841,6 @@
 		   size_t *var_len, WriteMethod **write_method)
 {
   /* Currently we support metric 1 only. */
-  struct interface *ifp;
   unsigned int ifindex;
   struct in_addr ifaddr;
   struct ospf_interface *oi;
@@ -1805,11 +1854,7 @@
   if (ospf == NULL)
     return NULL;
 
-  ifp = ospfIfMetricLookup (v, name, length, &ifaddr, &ifindex, exact);
-  if (ifp == NULL)
-    return NULL;
-
-  oi = ospf_if_lookup_by_local_addr (ospf, ifp, ifaddr);
+  oi = ospfIfMetricLookup (v, name, length, &ifaddr, &ifindex, exact);
   if (oi == NULL)
     return NULL;