[tun] Migrate to fuchsia.net.interfaces

Bug: 75554, 80064
Change-Id: I3e578c7d65056fe6f26f6be06fdcd3e1d6afb1f9
diff --git a/src/include/BUILD.gn b/src/include/BUILD.gn
index 141f492..0309536 100644
--- a/src/include/BUILD.gn
+++ b/src/include/BUILD.gn
@@ -14,7 +14,6 @@
     "-Wno-deprecated-anon-enum-enum-conversion",
   ]
 
-
   # Once the file generation in mainline is fixed, we can remove this exception.
   # Until then, certain generated files have lower-case instead of upper-case paths.
   if (host_os == "mac") {
@@ -787,8 +786,8 @@
 group("common") {
   public_deps = [
     ":public_headers",
+    "//sdk/fidl/fuchsia.net.interfaces",
     "//sdk/fidl/fuchsia.net.interfaces.admin",
-    "//sdk/fidl/fuchsia.net.stack",
     "//sdk/fidl/fuchsia.net.tun",
     "//sdk/fidl/fuchsia.netstack",
     "//sdk/lib/sys/cpp",
diff --git a/src/inet/TunEndPoint.cpp b/src/inet/TunEndPoint.cpp
index 8656867..8ab9525 100644
--- a/src/inet/TunEndPoint.cpp
+++ b/src/inet/TunEndPoint.cpp
@@ -140,11 +140,6 @@
     WeaveLogError(Inet, "PlatformData is NULL");
     return INET_ERROR_BAD_ARGS;
   }
-  err = platformData->ctx->svc()->Connect(mStackPtr.NewRequest());
-  if (err != ZX_OK) {
-    WeaveLogError(Inet, "connect to stack fidl failed");
-    return err;
-  }
 
   fuchsia::hardware::network::DeviceHandle device;
   err = mTunDevice->GetDevice(device.NewRequest());
@@ -375,51 +370,97 @@
  * @returns \c true if the tunnel interface is active,
  *          otherwise \c false.
  */
-bool TunEndPoint::IsInterfaceUp (void) const
+bool TunEndPoint::IsInterfaceUp(void)
 {
-    bool ret = false;
-
 #if WEAVE_SYSTEM_CONFIG_USE_LWIP
     // Lock LwIP stack
     LOCK_TCPIP_CORE();
 
-    ret = netif_is_up(&mTunNetIf);
+    bool ret = netif_is_up(&mTunNetIf);
 
     // UnLock LwIP stack
     UNLOCK_TCPIP_CORE();
 
-    ExitNow();
+    return ret;
 #endif // WEAVE_SYSTEM_CONFIG_USE_LWIP
 
 #if WEAVE_SYSTEM_CONFIG_USE_FUCHSIA_TUN
-    // TODO(https://fxbug.dev/80064): Migrate away from stack.GetInterfaceInfo.
-    // NOTE: This is the last use of mStackPtr (fuchsia.net.stack/Stack) in this
-    // class.
-    if (!mStackPtr.is_bound()) {
-      WeaveLogError(Inet, "mControlPtr is not bound");
-      ExitNow(ret = false);
+    if (!mInterfacesStatePtr.is_bound())
+    {
+        InetLayer::FuchsiaPlatformData * platformData = static_cast<InetLayer::FuchsiaPlatformData *>(Layer().GetPlatformData());
+        zx_status_t err                               = platformData->ctx->svc()->Connect(mInterfacesStatePtr.NewRequest());
+        if (err != ZX_OK)
+        {
+            WeaveLogError(Inet, "connect to interfaces state fidl failed: %s", zx_status_get_string(err));
+            return false;
+        }
     }
-    else {
-      zx_status_t err;
-      fuchsia::net::stack::Stack_GetInterfaceInfo_Result result;
-      err = mStackPtr->GetInterfaceInfo(mInterfaceId, &result);
-      if (err != ZX_OK) {
-        WeaveLogError(Inet, "GetInterfaceInfo failed: %s", zx_status_get_string(err));
-        ExitNow(ret = false);
-      }
-      fuchsia::net::stack::Stack_GetInterfaceInfo_Response resp = std::move(result.response());
-      if (resp.info.properties.administrative_status == fuchsia::net::stack::AdministrativeStatus::ENABLED &&
-          resp.info.properties.physical_status == fuchsia::net::stack::PhysicalStatus::UP) {
-        ExitNow(ret = true);
-      }
+    fuchsia::net::interfaces::WatcherSyncPtr watcher;
+    zx_status_t err = mInterfacesStatePtr->GetWatcher(fuchsia::net::interfaces::WatcherOptions(), watcher.NewRequest());
+    if (err != ZX_OK)
+    {
+        WeaveLogError(Inet, "interfaces state get watcher call failed: %s", zx_status_get_string(err));
+        return false;
+    }
+    while (true)
+    {
+        fuchsia::net::interfaces::Event event;
+        zx_status_t err = watcher->Watch(&event);
+        if (err != ZX_OK)
+        {
+            WeaveLogError(Inet, "interface watcher failed: %s", zx_status_get_string(err));
+            return false;
+        }
+        switch (event.Which())
+        {
+        case fuchsia::net::interfaces::Event::kExisting: {
+            const fuchsia::net::interfaces::Properties & properties = event.existing();
+            if (!properties.has_id())
+            {
+                WeaveLogError(Inet, "interface watcher existing event without ID");
+                return false;
+            }
+            if (properties.id() != mInterfaceId)
+            {
+                continue;
+            }
+            if (!properties.has_online())
+            {
+                WeaveLogError(Inet, "interface watcher existing event without online");
+                return false;
+            }
+            return properties.online();
+        }
+        case fuchsia::net::interfaces::Event::kIdle: {
+            WeaveLogError(Inet, "interface watcher idle event before existing; interface with ID %d doesn't exist", mInterfaceId);
+            return false;
+        }
+        case fuchsia::net::interfaces::Event::kAdded: {
+            WeaveLogError(Inet, "unexpected interface watcher added event");
+            return false;
+        }
+        case fuchsia::net::interfaces::Event::kChanged: {
+            WeaveLogError(Inet, "unexpected interface watcher changed event");
+            return false;
+        }
+        case fuchsia::net::interfaces::Event::kRemoved: {
+            WeaveLogError(Inet, "unexpected interface watcher removed event");
+            return false;
+        }
+        case fuchsia::net::interfaces::Event::Invalid: {
+            WeaveLogError(Inet, "interface watcher invalid event");
+            return false;
+        }
+        }
     }
 #elif WEAVE_SYSTEM_CONFIG_USE_SOCKETS
+    bool ret   = false;
     int sockfd = INET_INVALID_SOCKET_FD;
     struct ::ifreq ifr;
 
     memset(&ifr, 0, sizeof(ifr));
 
-    //Get interface
+    // Get interface
     if (TunGetInterface(mSocket, &ifr) < 0)
     {
         ExitNow();
@@ -431,25 +472,23 @@
         ExitNow();
     }
 
-    //Get interface flags
+    // Get interface flags
     if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0)
     {
         ExitNow();
     }
 
     ret = ((ifr.ifr_flags & IFF_UP) == IFF_UP);
-
 #endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 
-exit:
 #if WEAVE_SYSTEM_CONFIG_USE_SOCKETS && !WEAVE_SYSTEM_CONFIG_USE_FUCHSIA_TUN
+exit:
     if (sockfd >= 0)
     {
         close(sockfd);
     }
-#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
-
     return ret;
+#endif // WEAVE_SYSTEM_CONFIG_USE_SOCKETS
 }
 
 /**
@@ -1001,7 +1040,6 @@
 void TunEndPoint::TunDevClose (void)
 {
 #if WEAVE_SYSTEM_CONFIG_USE_FUCHSIA_TUN
-  fuchsia::net::stack::Stack_DelEthernetInterface_Result result;
   if (!mControlPtr.is_bound()) {
     WeaveLogError(Inet, "TunDevClose failed as mControlPtr is not bound");
     return;
diff --git a/src/inet/TunEndPoint.h b/src/inet/TunEndPoint.h
index c2af2f6..982a5bd 100644
--- a/src/inet/TunEndPoint.h
+++ b/src/inet/TunEndPoint.h
@@ -34,8 +34,8 @@
 
 #if WEAVE_SYSTEM_CONFIG_USE_FUCHSIA_TUN
 #include <fuchsia/net/interfaces/admin/cpp/fidl.h>
+#include <fuchsia/net/interfaces/cpp/fidl.h>
 #include <fuchsia/net/tun/cpp/fidl.h>
-#include <fuchsia/net/stack/cpp/fidl.h>
 #include <lib/sys/cpp/component_context.h>
 #endif
 
@@ -152,7 +152,7 @@
 
     INET_ERROR Send(Weave::System::PacketBuffer *message);
 
-    bool IsInterfaceUp(void) const;
+    bool IsInterfaceUp(void);
 
     INET_ERROR InterfaceUp(void);
 
@@ -208,7 +208,7 @@
     fuchsia::net::tun::ControlSyncPtr mTunCtl;
     fuchsia::net::tun::DeviceSyncPtr mTunDevice;
     fuchsia::net::tun::PortSyncPtr mTunPort;
-    fuchsia::net::stack::StackSyncPtr mStackPtr;
+    fuchsia::net::interfaces::StateSyncPtr mInterfacesStatePtr;
     fuchsia::net::interfaces::admin::ControlSyncPtr mControlPtr;
     fuchsia::net::interfaces::admin::DeviceControlSyncPtr mDeviceControlPtr;
     uint64_t mInterfaceId;