[solaris] Extra debug and cross-checks for kernel_socket, two Sol9 fixes.

2005-11-12 Alexander Gall <gall@switch.ch>

	* See [quagga-dev 1815]
	* kernel_socket.c: (rtm_write) Use SAROUNDUP when HAVE_SIN_LEN
	  is not available.
	* rt_socket.c: (kernel_rtm_ipv6(_multipath)) set family to
	  AF_INET6 on ipv6 routes.

2005-11-12 Paul Jakma <paul.jakma@sun.com>

	* kernel_socket.c: Add RTA_NAME_GET macro to extract name from
	  sockaddr_dl. Add some more RTF_ flags.
	* (ifan_read) Add some debug messages.
	* (ifm_read) Add more debug messages. More robust cross-checks
	  of index against name.
	  Fall back to by-name lookup if the index lookup fails, future
	  proofing more than anything else.
	  (ifam_read_mesg) Read RTA_IFP. Add debug messages.
	  (ifam_read) More debug. If there's an RTA_IFP and it isn't
	  the name of the interface, save it as the label.
	  (rtm_read_mesg) Read RTA_IFP.
	  (rtm_read) allow name to be retrieved.
	  (rtmsg_debug) expand on the debug message.
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
index dfd1df4..f943d65 100644
--- a/zebra/ChangeLog
+++ b/zebra/ChangeLog
@@ -1,3 +1,27 @@
+2005-11-12 Alexander Gall <gall@switch.ch>
+
+	* See [quagga-dev 1815]
+	* kernel_socket.c: (rtm_write) Use SAROUNDUP when HAVE_SIN_LEN
+	  is not available.
+	* rt_socket.c: (kernel_rtm_ipv6(_multipath)) set family to 
+	  AF_INET6 on ipv6 routes.
+
+2005-11-12 Paul Jakma <paul.jakma@sun.com> 
+
+	* kernel_socket.c: Add RTA_NAME_GET macro to extract name from
+	  sockaddr_dl. Add some more RTF_ flags.
+	* (ifan_read) Add some debug messages.
+	* (ifm_read) Add more debug messages. More robust cross-checks
+	  of index against name.
+	  Fall back to by-name lookup if the index lookup fails, future
+	  proofing more than anything else.
+	  (ifam_read_mesg) Read RTA_IFP. Add debug messages.
+	  (ifam_read) More debug. If there's an RTA_IFP and it isn't
+	  the name of the interface, save it as the label.
+	  (rtm_read_mesg) Read RTA_IFP.
+	  (rtm_read) allow name to be retrieved.
+	  (rtmsg_debug) expand on the debug message.
+
 2005-11-11 Paul Jakma <paul.jakma@sun.com>
 
 	* kernel_socket.c: (ifm_read) arithmetic on void pointer
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index b1b143e..b4643dc 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -83,7 +83,7 @@
       int len = SAROUNDUP ((PNT)); \
       if ( ((DEST) != NULL) && \
            af_check (((struct sockaddr *)(PNT))->sa_family)) \
-        memcpy ((caddr_t)(DEST), (PNT), len); \
+        memcpy ((DEST), (PNT), len); \
       (PNT) += len; \
     }
 #define RTA_ATTR_GET(DEST, RTA, RTMADDRS, PNT) \
@@ -91,10 +91,31 @@
     { \
       int len = SAROUNDUP ((PNT)); \
       if ( ((DEST) != NULL) ) \
-        memcpy ((caddr_t)(DEST), (PNT), len); \
+        memcpy ((DEST), (PNT), len); \
       (PNT) += len; \
     }
 
+#define RTA_NAME_GET(DEST, RTA, RTMADDRS, PNT, LEN) \
+  if ((RTMADDRS) & (RTA)) \
+    { \
+      int len = SAROUNDUP ((PNT)); \
+      struct sockaddr_dl *sdl = (struct sockaddr_dl *)(PNT); \
+      if (IS_ZEBRA_DEBUG_KERNEL) \
+        zlog_debug ("%s: RTA_SDL_GET nlen %d, alen %d", \
+                    __func__, sdl->sdl_nlen, sdl->sdl_alen); \
+      if ( ((DEST) != NULL) && (sdl->sdl_family == AF_LINK) \
+           && (sdl->sdl_nlen < IFNAMSIZ) && (sdl->sdl_nlen <= len) ) \
+        { \
+          memcpy ((DEST), sdl->sdl_data, sdl->sdl_nlen); \
+          (DEST)[sdl->sdl_nlen] = '\0'; \
+          (LEN) = sdl->sdl_nlen; \
+        } \
+      (PNT) += len; \
+    } \
+  else \
+    { \
+      (LEN) = 0; \
+    }
 /* Routing socket message types. */
 struct message rtm_type_str[] =
 {
@@ -144,6 +165,9 @@
   {RTF_LLINFO,    "LLINFO"},
   {RTF_STATIC,    "STATIC"},
   {RTF_BLACKHOLE, "BLACKHOLE"},
+#ifdef RTF_PRIVATE
+  {RTF_PRIVATE,	  "PRIVATE"},
+#endif /* RTF_PRIVATE */
   {RTF_PROTO1,    "PROTO1"},
   {RTF_PROTO2,    "PROTO2"},
 #ifdef RTF_PRCLONING
@@ -167,6 +191,12 @@
 #ifdef RTF_MULTICAST
   {RTF_MULTICAST, "MULTICAST"},
 #endif /* RTF_MULTICAST */
+#ifdef RTF_MULTIRT
+  {RTF_MULTIRT,   "MULTIRT"},
+#endif /* RTF_MULTIRT */
+#ifdef RTF_SETSRC
+  {RTF_SETSRC,    "SETSRC"},
+#endif /* RTF_SETSRC */
   {0,             NULL}
 };
 
@@ -214,10 +244,20 @@
 ifan_read (struct if_announcemsghdr *ifan)
 {
   struct interface *ifp;
-
+  
   ifp = if_lookup_by_index (ifan->ifan_index);
-  if (ifp == NULL && ifan->ifan_what == IFAN_ARRIVAL)
+  
+  if (ifp)
+    assert ( (ifp->ifindex == ifan->ifan_index) 
+             || (ifp->ifindex == IFINDEX_INTERNAL) );
+
+  if ( (ifp == NULL || (ifp->ifindex == IFINDEX_INTERNAL)
+      && ifan->ifan_what == IFAN_ARRIVAL)
     {
+      if (IS_ZEBRA_DEBUG_KERNEL)
+        zlog_debug ("%s: creating interface for ifindex %d, name %s",
+                    __func__, ifan->ifan_index, ifan->ifan_name);
+      
       /* Create Interface */
       ifp = if_get_by_name_len(ifan->ifan_name,
 			       strnlen(ifan->ifan_name,
@@ -234,7 +274,8 @@
   if_get_metric (ifp);
 
   if (IS_ZEBRA_DEBUG_KERNEL)
-    zlog_debug ("interface %s index %d", ifp->name, ifp->ifindex);
+    zlog_debug ("%s: interface %s index %d", 
+                __func__, ifan->ifan_name, ifan->ifan_index);
 
   return 0;
 }
@@ -249,10 +290,13 @@
 ifm_read (struct if_msghdr *ifm)
 {
   struct interface *ifp = NULL;
-  struct sockaddr_dl *sdl = NULL;
+  char ifname[IFNAMSIZ];
+  short ifnlen = 0;
   caddr_t *cp;
-  unsigned int i;
-
+  
+  /* terminate ifname at head (for strnlen) and tail (for safety) */
+  ifname[IFNAMSIZ - 1] = '\0';
+  
   /* paranoia: sanity check structure */
   if (ifm->ifm_msglen < sizeof(struct if_msghdr))
     {
@@ -279,68 +323,56 @@
   	cp = cp + 12;
 #endif
 
+  RTA_ADDR_GET (NULL, RTA_DST, ifm->ifm_addrs, cp);
+  RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifm_addrs, cp);
+  RTA_ATTR_GET (NULL, RTA_NETMASK, ifm->ifm_addrs, cp);
+  RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifm_addrs, cp);
+  RTA_NAME_GET (ifname, RTA_IFP, ifm->ifm_addrs, cp, ifnlen);
+  RTA_ADDR_GET (NULL, RTA_IFA, ifm->ifm_addrs, cp);
+  RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifm_addrs, cp);
+  RTA_ADDR_GET (NULL, RTA_BRD, ifm->ifm_addrs, cp);
+  
+  if (IS_ZEBRA_DEBUG_KERNEL)
+    zlog_debug ("%s: sdl ifname %s", __func__, (ifnlen ? ifname : "(nil)"));
+  
   /* 
-   * Check for each sockaddr in turn, advancing over it.  After this
-   * loop, sdl should point to a sockaddr_dl iff one was present.
+   * Look up on ifindex first, because ifindices are the primary handle for
+   * interfaces across the user/kernel boundary, for most systems.  (Some
+   * messages, such as up/down status changes on NetBSD, do not include a
+   * sockaddr_dl).
    */
-  for (i = 1; i != 0; i <<= 1) 
+  if ( (ifp = if_lookup_by_index (ifm->ifm_index)) != NULL )
     {
-      if (i & ifm->ifm_addrs)
+      /* we have an ifp, verify that the name matches as some systems,
+       * eg Solaris, have a 1:many association of ifindex:ifname
+       * if they dont match, we dont have the correct ifp and should
+       * set it back to NULL to let next check do lookup by name
+       */
+      if (ifnlen && (strncmp (ifp->name, ifname, IFNAMSIZ) != 0) )
         {
-	  if (i == RTA_IFP)
-	    {
-	      sdl = (struct sockaddr_dl *)cp;
-	      break;
-            }
-	  /* XXX warning: pointer of type `void *' used in arithmetic */
-	  cp += SAROUNDUP(cp);
+          if (IS_ZEBRA_DEBUG_KERNEL)
+            zlog_debug ("%s: ifp name %s doesnt match sdl name %s",
+                        __func__, ifp->name, ifname);
+          ifp = NULL;
         }
     }
-
-  /* Ensure that sdl, if present, is actually a sockaddr_dl. */
-  if (sdl != NULL && sdl->sdl_family != AF_LINK)
-    {
-      zlog_err ("ifm_read: sockaddr_dl bad AF %d\n",
-		sdl->sdl_family);
-      return -1;
-    }
-
+  
   /* 
-   * Look up on ifindex first, because ifindices are the primary
-   * handle for interfaces across the user/kernel boundary.  (Some
-   * messages, such as up/down status changes on NetBSD, do not
-   * include a sockaddr_dl).
+   * If we dont have an ifp, try looking up by name.  Particularly as some
+   * systems (Solaris) have a 1:many mapping of ifindex:ifname - the ifname
+   * is therefore our unique handle to that interface.
+   *
+   * Interfaces specified in the configuration file for which the ifindex
+   * has not been determined will have ifindex == IFINDEX_INTERNAL, and such
+   * interfaces are found by this search, and then their ifindex values can
+   * be filled in.
    */
-  ifp = if_lookup_by_index (ifm->ifm_index);
-
-  /* 
-   * If lookup by index was unsuccessful and we have a name, try
-   * looking up by name.  Interfaces specified in the configuration
-   * file for which the ifindex has not been determined will have
-   * ifindex == IFINDEX_INTERNAL, and such interfaces are found by this search,
-   * and then their ifindex values can be filled in.
-   */
-  if (ifp == NULL && sdl != NULL)
-    {
-      /*
-       * paranoia: sanity check name length.  nlen does not include
-       * trailing zero, but IFNAMSIZ max length does.
-       *
-       * XXX Is this test correct?  Should it be '>=' or '>'?  And is it even
-       * necessary now that we are using if_lookup_by_name_len?
-       */
-      if (sdl->sdl_nlen >= IFNAMSIZ)
-	{
-	  zlog_err ("ifm_read: illegal sdl_nlen %d\n", sdl->sdl_nlen);
-	  return -1;
-	}
-
-      ifp = if_lookup_by_name_len (sdl->sdl_data, sdl->sdl_nlen);
-    }
+  if ( (ifp == NULL) && ifnlen)
+    ifp = if_lookup_by_name (ifname);
 
   /*
-   * If ifp does not exist or has an invalid index (IFINDEX_INTERNAL), create or
-   * fill in an interface.
+   * If ifp still does not exist or has an invalid index (IFINDEX_INTERNAL),
+   * create or fill in an interface.
    */
   if ((ifp == NULL) || (ifp->ifindex == IFINDEX_INTERNAL))
     {
@@ -348,17 +380,25 @@
        * To create or fill in an interface, a sockaddr_dl (via
        * RTA_IFP) is required.
        */
-      if (sdl == NULL)
+      if (!ifnlen)
 	{
-	  zlog_warn ("Interface index %d (new) missing RTA_IFP sockaddr_dl\n",
+	  zlog_warn ("Interface index %d (new) missing ifname\n",
 		     ifm->ifm_index);
 	  return -1;
 	}
-
+      
       if (ifp == NULL)
-	/* Interface that zebra was not previously aware of, so create. */ 
-      	ifp = if_create (sdl->sdl_data, sdl->sdl_nlen);
+        {
+	  /* Interface that zebra was not previously aware of, so create. */ 
+	  ifp = if_create (ifname, ifnlen);
+	  if (IS_ZEBRA_DEBUG_KERNEL)
+	    zlog_debug ("%s: creating ifp for ifindex %d", 
+	                __func__, ifm->ifm_index);
+        }
 
+      if (IS_ZEBRA_DEBUG_KERNEL)
+        zlog_debug ("%s: updated/created ifp, ifname %s, ifindex %d",
+                    __func__, ifp->name, ifp->ifindex);
       /* 
        * Fill in newly created interface structure, or larval
        * structure with ifindex IFINDEX_INTERNAL.
@@ -372,13 +412,6 @@
 #endif /* __bsdi__ */
       if_get_metric (ifp);
 
-      /* 
-       * XXX sockaddr_dl contents can be larger than the structure
-       * definition, so the user of the stored structure must be
-       * careful not to read off the end.
-       */
-      memcpy (&ifp->sdl, sdl, sizeof (struct sockaddr_dl));
-
       if_add_update (ifp);
     }
   else
@@ -390,6 +423,14 @@
      * but apparently do not trigger action.)
      */
     {
+      if (ifp->ifindex != ifm->ifm_index)
+        {
+          zlog_warn ("%s: index mismatch, ifname %s, ifp index %d, "
+                     "ifm index %d", 
+                     __func__, ifp->name, ifp->ifindex, ifm->ifm_index);
+          return -1;
+        }
+      
       if (if_is_up (ifp))
 	{
 	  ifp->flags = ifm->ifm_flags;
@@ -423,7 +464,8 @@
 #endif /* HAVE_NET_RT_IFLIST */
 
   if (IS_ZEBRA_DEBUG_KERNEL)
-    zlog_debug ("interface %s index %d", ifp->name, ifp->ifindex);
+    zlog_debug ("%s: interface %s index %d", 
+                __func__, ifp->name, ifp->ifindex);
 
   return 0;
 }
@@ -433,7 +475,9 @@
 ifam_read_mesg (struct ifa_msghdr *ifm,
 		union sockunion *addr,
 		union sockunion *mask,
-		union sockunion *dest)
+		union sockunion *brd,
+		char *ifname,
+		short *ifnlen)
 {
   caddr_t pnt, end;
 
@@ -450,11 +494,16 @@
   RTA_ADDR_GET (NULL, RTA_GATEWAY, ifm->ifam_addrs, pnt);
   RTA_ATTR_GET (mask, RTA_NETMASK, ifm->ifam_addrs, pnt);
   RTA_ADDR_GET (NULL, RTA_GENMASK, ifm->ifam_addrs, pnt);
-  RTA_ADDR_GET (NULL, RTA_IFP, ifm->ifam_addrs, pnt);
+  RTA_NAME_GET (ifname, RTA_IFP, ifm->ifam_addrs, pnt, *ifnlen);
   RTA_ADDR_GET (addr, RTA_IFA, ifm->ifam_addrs, pnt);
   RTA_ADDR_GET (NULL, RTA_AUTHOR, ifm->ifam_addrs, pnt);
-  RTA_ADDR_GET (dest, RTA_BRD, ifm->ifam_addrs, pnt);
+  RTA_ADDR_GET (brd, RTA_BRD, ifm->ifam_addrs, pnt);
 
+  if (IS_ZEBRA_DEBUG_KERNEL)
+      zlog_debug ("%s: ifindex %d, ifname %s, ifam_addrs 0x%x", 
+                  __func__, ifm->ifam_index, 
+                  (ifnlen ? ifname : "(nil)"), ifm->ifam_addrs);
+  
   /* Assert read up end point matches to end point */
   if (pnt != end)
     zlog_warn ("ifam_read() does't read all socket data");
@@ -464,20 +513,27 @@
 int
 ifam_read (struct ifa_msghdr *ifam)
 {
-  struct interface *ifp;
+  struct interface *ifp = NULL;
   union sockunion addr, mask, brd;
-
-  /* Check does this interface exist or not. */
-  ifp = if_lookup_by_index (ifam->ifam_index);
-  if (ifp == NULL) 
+  char ifname[INTERFACE_NAMSIZ];
+  short ifnlen = 0;
+  char isalias = 0;
+  
+  ifname[0] = ifname[INTERFACE_NAMSIZ - 1] = '\0';
+  
+  /* Allocate and read address information. */
+  ifam_read_mesg (ifam, &addr, &mask, &brd, ifname, &ifnlen);
+  
+  if ((ifp = if_lookup_by_index(ifam->ifam_index)) == NULL)
     {
-      zlog_warn ("no interface for index %d", ifam->ifam_index); 
+      zlog_warn ("%s: no interface for ifname %s, index %d", 
+                 __func__, ifname, ifam->ifam_index);
       return -1;
     }
-
-  /* Allocate and read address information. */
-  ifam_read_mesg (ifam, &addr, &mask, &brd);
-
+  
+  if (ifnlen && strncmp (ifp->name, ifname, INTERFACE_NAMSIZ))
+    isalias = 1;
+  
   /* Check interface flag for implicit up of the interface. */
   if_refresh (ifp);
 
@@ -525,7 +581,9 @@
 rtm_read_mesg (struct rt_msghdr *rtm,
 	       union sockunion *dest,
 	       union sockunion *mask,
-	       union sockunion *gate)
+	       union sockunion *gate,
+	       char *ifname,
+	       short *ifnlen)
 {
   caddr_t pnt, end;
 
@@ -549,7 +607,7 @@
   RTA_ADDR_GET (gate, RTA_GATEWAY, rtm->rtm_addrs, pnt);
   RTA_ATTR_GET (mask, RTA_NETMASK, rtm->rtm_addrs, pnt);
   RTA_ADDR_GET (NULL, RTA_GENMASK, rtm->rtm_addrs, pnt);
-  RTA_ADDR_GET (NULL, RTA_IFP, rtm->rtm_addrs, pnt);
+  RTA_NAME_GET (ifname, RTA_IFP, rtm->rtm_addrs, pnt, *ifnlen);
   RTA_ADDR_GET (NULL, RTA_IFA, rtm->rtm_addrs, pnt);
   RTA_ADDR_GET (NULL, RTA_AUTHOR, rtm->rtm_addrs, pnt);
   RTA_ADDR_GET (NULL, RTA_BRD, rtm->rtm_addrs, pnt);
@@ -572,6 +630,8 @@
   int flags;
   u_char zebra_flags;
   union sockunion dest, mask, gate;
+  char ifname[INTERFACE_NAMSIZ + 1];
+  short ifnlen = 0;
 
   zebra_flags = 0;
 
@@ -582,7 +642,7 @@
 
   /* Read destination and netmask and gateway from rtm message
      structure. */
-  flags = rtm_read_mesg (rtm, &dest, &mask, &gate);
+  flags = rtm_read_mesg (rtm, &dest, &mask, &gate, ifname, &ifnlen);
 
 #ifdef RTF_CLONED	/*bsdi, netbsd 1.6*/
   if (flags & RTF_CLONED)
@@ -790,7 +850,7 @@
 #define SOCKADDRSET(X,R) \
   if (msg.rtm.rtm_addrs & (R)) \
     { \
-      int len = ROUNDUP (sizeof((X)->sa)); \
+      int len = SAROUNDUP (X); \
       memcpy (pnt, (caddr_t)(X), len); \
       pnt += len; \
     }
@@ -841,7 +901,7 @@
   zlog_debug ("Kernel: Len: %d Type: %s", rtm->rtm_msglen, type);
   rtm_flag_dump (rtm->rtm_flags);
   zlog_debug ("Kernel: message seq %d", rtm->rtm_seq);
-  zlog_debug ("Kernel: pid %d", rtm->rtm_pid);
+  zlog_debug ("Kernel: pid %d, rtm_addrs 0x%x", rtm->rtm_pid, rtm->rtm_addrs);
 }
 
 /* This is pretty gross, better suggestions welcome -- mhandler */
diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c
index f447d8c..fa2f172 100644
--- a/zebra/rt_socket.c
+++ b/zebra/rt_socket.c
@@ -290,7 +290,7 @@
   else
     {
       masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr);
-      sin_mask.sin6_family = AF_UNSPEC;
+      sin_mask.sin6_family = AF_INET6;
 #ifdef SIN6_LEN
       sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
 #endif /* SIN6_LEN */
@@ -400,7 +400,7 @@
       else
 	{
 	  masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
-	  sin_mask.sin6_family = AF_UNSPEC;
+	  sin_mask.sin6_family = AF_INET6;
 #ifdef SIN6_LEN
 	  sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
 #endif /* SIN6_LEN */