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

	* connected.{c,h}: Include memory.h
	  (connected_add_ipv4) Use MTYPE for ifc label.
	  (connected_add_ipv6) Also should accept label. Store it in ifp.
	  (connected_del_ipv4) Taking label as argument is pointless.
	* rt_netlink.c: (netlink_interface_addr) update label usage
	  for connected_{add,delete} functions.
	* if_ioctl.c: (if_getaddrs) NULL label for connected_add_ipv6.
	* if_ioctl_solaris.c: (interface_list_ioctl) Pass LIFC_NOXMIT
	  so we also find out about NOXMIT interfaces like VNI.
	  Bit of hackery to turn interface names into the primary
	  interface name, later with routing socket messages we only
	  will about primary interfaces anyway, so we must normalise
	  the name.
	  (if_get_addr) take label as argument, so it can
	  be passed to connected_add.
	  If label is provided, then it is interface name to issue the
	  ioctl for address information on, not the ifp name.
	  (interface_list) List AF_UNSPEC too, just in case.
	* if_proc.c: (ifaddr_proc_ipv6) label for connected_add_ipv6.
	* interface.c: (if_addr_wakeup) Some very bogus code - sets
	  IFF_RUNNING - add comment.
	  (if_refresh)
	  (ip_address_install) Use MTYPE for ifc label.
	* ioctl_solaris.c: (if_mangle_up) New function. Hackery to make
	  IFF_UP reflect whether any addresses are left on the
	  interface, as we get signalled for IFF_UP flags change on the
	  primary interface only. Logical interfaces dont generate
	  IFINFO, but we do get an RTM_DELADDR.
	  (if_get_flags) Call if_mangle_up before return.
	* kernel_socket.c: (ifam_read) Fixup calls to
	  connected_{add,delete} to match above changes. Rename gate
	  variable to brd, less confusing.
	  Pass the interface name as a label, if it is not same name
	  as ifp->name.
diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c
index 43e1e83..ec1d2c4 100644
--- a/zebra/ioctl_solaris.c
+++ b/zebra/ioctl_solaris.c
@@ -274,11 +274,35 @@
   return 0;
 }
 
+/* Solaris IFF_UP flag reflects only the primary interface as the
+ * routing socket only sends IFINFO for the primary interface.  Hence  
+ * ~IFF_UP does not per se imply all the logical interfaces are also   
+ * down - which we only know of as addresses. Instead we must determine
+ * whether the interface really is up or not according to how many   
+ * addresses are still attached. (Solaris always sends RTM_DELADDR if
+ * an interface, logical or not, goes ~IFF_UP).
+ *
+ * Ie, we mangle IFF_UP to reflect whether or not there are addresses
+ * left in struct connected, not the actual underlying IFF_UP flag
+ * (which corresponds to just one address of all the logical interfaces)
+ *
+ * Setting IFF_UP within zebra to administratively shutdown the
+ * interface will affect only the primary interface/address on Solaris.
+ */
+static inline void
+if_mangle_up (struct interface *ifp)
+{
+  if (listcount(ifp->connected) > 0)
+    SET_FLAG (ifp->flags, IFF_UP);
+  else
+    UNSET_FLAG (ifp->flags, IFF_UP);
+}
+
 /* get interface flags */
 void
 if_get_flags (struct interface *ifp)
 {
-  int ret;
+  int ret4, ret6;
   struct lifreq lifreq;
   unsigned long flags4 = 0, flags6 = 0;
 
@@ -286,25 +310,27 @@
     {
       lifreq_set_name (&lifreq, ifp);
       
-      ret = AF_IOCTL (AF_INET, SIOCGLIFFLAGS, (caddr_t) & lifreq);
-
-      flags4 = (lifreq.lifr_flags & 0xffffffff);
-      if (!(flags4 & IFF_UP))
-        flags4 &= ~IFF_IPV4;
+      ret4 = AF_IOCTL (AF_INET, SIOCGLIFFLAGS, (caddr_t) & lifreq);
+      
+      if (!ret4)
+        flags4 = (lifreq.lifr_flags & 0xffffffff);
     }
 
   if (ifp->flags & IFF_IPV6)
     {
       lifreq_set_name (&lifreq, ifp);
       
-      ret = AF_IOCTL (AF_INET6, SIOCGLIFFLAGS, (caddr_t) & lifreq);
-              
-      flags6 = (lifreq.lifr_flags & 0xffffffff);
-      if (!(flags6 & IFF_UP))
-        flags6 &= ~IFF_IPV6;
+      ret6 = AF_IOCTL (AF_INET6, SIOCGLIFFLAGS, (caddr_t) & lifreq);
+      
+      if (!ret6)
+        flags6 = (lifreq.lifr_flags & 0xffffffff);
     }
+  
+  /* only update flags if one of above succeeded */
+  if ( !(ret4 && ret6) )
+    ifp->flags = (flags4 | flags6);
 
-  ifp->flags = (flags4 | flags6);
+  if_mangle_up (ifp);
 }
 
 /* Set interface flags */