2003-09-24 sowmini.varadhan@sun.com
* zebra/kernel_socket.c: Fix up WRAPUP macro to deal with multiple
address families in the absence of sa_len element in struct
sockaddr.
(ifm_read): Handle solaris 9 if_msghdr_t.
Deal with interfaces which are incomplete, lookup on name rather
than the placeholder interface index of -1.
diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c
index 05eec59..e4f85aa 100644
--- a/zebra/kernel_socket.c
+++ b/zebra/kernel_socket.c
@@ -48,7 +48,13 @@
#ifdef HAVE_SA_LEN
#define WRAPUP(X) ROUNDUP(((struct sockaddr *)(X))->sa_len)
#else
-#define WRAPUP(X) ROUNDUP(sizeof (struct sockaddr))
+#define WRAPUP(X) \
+ (((struct sockaddr *)(X))->sa_family == AF_INET ? \
+ ROUNDUP(sizeof(struct sockaddr_in)):\
+ (((struct sockaddr *)(X))->sa_family == AF_INET6 ? \
+ ROUNDUP(sizeof(struct sockaddr_in6)) : \
+ (((struct sockaddr *)(X))->sa_family == AF_LINK ? \
+ ROUNDUP(sizeof(struct sockaddr_dl)) : sizeof(struct sockaddr))))
#endif /* HAVE_SA_LEN */
/* Routing socket message types. */
@@ -201,15 +207,55 @@
int
ifm_read (struct if_msghdr *ifm)
{
- struct interface *ifp;
+ struct interface *ifp = NULL;
struct sockaddr_dl *sdl = NULL;
+ char ifname[IFNAMSIZ];
+#ifdef SUNOS_5
+ int i;
+ struct sockaddr *sa;
+ u_char *cp = (u_char *)(ifm + 1);
+
+ /*
+ * if_msghdr_t on 64 bit kernels in Solaris 9 and earlier versions
+ * is 12 bytes larger than the 32 bit version, so make adjustment
+ * here.
+ */
+ sa = (struct sockaddr *)cp;
+ if (sa->sa_family == AF_UNSPEC)
+ cp = cp + 12;
+
+ for (i = 1; i != 0; i <<= 1)
+ {
+ if (i & ifm->ifm_addrs)
+ {
+ sa = (struct sockaddr *)cp;
+ cp += WRAPUP(sa);
+ if (i & RTA_IFP)
+ {
+ sdl = (struct sockaddr_dl *)sa;
+ break;
+ }
+ }
+ }
+#else
sdl = (struct sockaddr_dl *)(ifm + 1);
+#endif
- /* Use sdl index. */
- ifp = if_lookup_by_index (ifm->ifm_index);
+ /*
+ * Check if ifp already exists. If the interface has already been specified
+ * in the conf file, but is just getting created, we would have an
+ * entry in the iflist with incomplete data (e.g., ifindex == -1),
+ * so we lookup on name.
+ */
+ if (sdl != NULL)
+ {
+ bcopy(sdl->sdl_data, ifname, sdl->sdl_nlen);
+ ifname[sdl->sdl_nlen] = '\0';
+ ifp = if_lookup_by_name (ifname);
+ }
- if (ifp == NULL)
+ if ((ifp == NULL) || (ifp->ifindex == -1))
{
/* Check interface's address.*/
if (! (ifm->ifm_addrs & RTA_IFP))
@@ -219,7 +265,8 @@
return -1;
}
- ifp = if_create (sdl->sdl_data, sdl->sdl_nlen);
+ if (ifp == NULL)
+ ifp = if_create (sdl->sdl_data, sdl->sdl_nlen);
ifp->ifindex = ifm->ifm_index;
ifp->flags = ifm->ifm_flags;