[zebra] Make BSD link-state deal more gracefully with GIFMEDIA ioctl error

2008-07-01 Paul Jakma <paul.jakma@sun.com>

	* ioctl.c: (if_get_flags) Deal more gracefully with failure
	  of the BSD link-state SIOCGIFMEDIA ioctl, as some interfaces
	  apparently don't implement it (e.g. tun).
	  Also, make BSD link-state checking be conditional on the
	  'link-detect' interface configuration flag, as it should be.
	  Fixes bug #465.
diff --git a/zebra/ChangeLog b/zebra/ChangeLog
index 6483f2c..341c42a 100644
--- a/zebra/ChangeLog
+++ b/zebra/ChangeLog
@@ -1,3 +1,12 @@
+2008-07-01 Paul Jakma <paul.jakma@sun.com>
+
+	* ioctl.c: (if_get_flags) Deal more gracefully with failure
+	  of the BSD link-state SIOCGIFMEDIA ioctl, as some interfaces
+	  apparently don't implement it (e.g. tun).
+	  Also, make BSD link-state checking be conditional on the 
+	  'link-detect' interface configuration flag, as it should be.
+	  Fixes bug #465.
+
 2008-06-02 Denis Ovsienko
 
 	* connected.c: (connected_up_ipv4, connected_down_ipv4,
diff --git a/zebra/ioctl.c b/zebra/ioctl.c
index d536771..5cf9e7b 100644
--- a/zebra/ioctl.c
+++ b/zebra/ioctl.c
@@ -362,22 +362,29 @@
       return;
     }
 #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
-  (void) memset(&ifmr, 0, sizeof(ifmr));
-  strncpy (&ifmr.ifm_name, ifp->name, IFNAMSIZ);
-  if (if_ioctl(SIOCGIFMEDIA, (caddr_t) &ifmr) < 0)
+
+  /* Per-default, IFF_RUNNING is held high, unless link-detect says
+   * otherwise - we abuse IFF_RUNNING inside zebra as a link-state flag,
+   * following practice on Linux and Solaris kernels
+   */
+  SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
+  
+  if (CHECK_FLAG (ifp->status, ZEBRA_INTERFACE_LINKDETECTION))
     {
-      zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno));
-      return;
-    }
-  if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */
-    {
-      if (ifmr.ifm_status & IFM_ACTIVE)
-	SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
-      else
-	UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
-    }
-  else /* Force always up */
-    SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
+      (void) memset(&ifmr, 0, sizeof(ifmr));
+      strncpy (&ifmr.ifm_name, ifp->name, IFNAMSIZ);
+      
+      /* Seems not all interfaces implement this ioctl */
+      if (if_ioctl(SIOCGIFMEDIA, (caddr_t) &ifmr) < 0)
+        zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s", safe_strerror(errno));
+      else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */
+        {
+          if (ifmr.ifm_status & IFM_ACTIVE)
+            SET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
+          else
+            UNSET_FLAG(ifreq.ifr_flags, IFF_RUNNING);
+        }
+  }
 #endif /* HAVE_BSD_LINK_DETECT */
 
   if_flags_update (ifp, (ifreq.ifr_flags & 0x0000ffff));