Add support for running 464xlat on wifi as well.

1. Add a command to NetworkManagementService to enable/disable
   IPv6 ND offload via netd.
2. Make Nat464Xlat enable offload if clatd successfully comes up
   on a wifi network (which means it detected a NAT64), and
   correspondingly re-enable offload when the clatd interface
   goes down.

This change does not enable clatd on wifi yet, that requires an
extra 2 lines to enable it.

Bug: 12111730
Change-Id: I4318611762a37487c9a84f8c4867ec5aece98be8
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index d0ba4b8..5d5d2b3 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -92,6 +92,11 @@
     void enableIpv6(String iface);
 
     /**
+     * Enables or enables IPv6 ND offload.
+     */
+    void setInterfaceIpv6NdOffload(String iface, boolean enable);
+
+    /**
      * Retrieves the network routes currently configured on the specified
      * interface
      */
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index d03a154..0f033d7 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -940,6 +940,17 @@
     }
 
     @Override
+    public void setInterfaceIpv6NdOffload(String iface, boolean enable) {
+        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        try {
+            mConnector.execute(
+                    "interface", "ipv6ndoffload", iface, (enable ? "enable" : "disable"));
+        } catch (NativeDaemonConnectorException e) {
+            throw e.rethrowAsParcelableException();
+        }
+    }
+
+    @Override
     public void addRoute(int netId, RouteInfo route) {
         modifyRoute("add", "" + netId, route);
     }
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index c7a2ce1..c145ca3 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity;
 
 import static android.net.ConnectivityManager.TYPE_MOBILE;
+import static android.net.ConnectivityManager.TYPE_WIFI;
 
 import java.net.Inet4Address;
 
@@ -53,7 +54,7 @@
     // ConnectivityService Handler for LinkProperties updates.
     private final Handler mHandler;
 
-    // The network we're running on.
+    // The network we're running on, and its type.
     private final NetworkAgentInfo mNetwork;
 
     // Internal state variables.
@@ -211,23 +212,41 @@
         return stacked;
     }
 
+    private LinkAddress getLinkAddress(String iface) {
+        try {
+            InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
+            return config.getLinkAddress();
+        } catch(RemoteException|IllegalStateException e) {
+            Slog.e(TAG, "Error getting link properties: " + e);
+            return null;
+        }
+    }
+
+    private void maybeSetIpv6NdOffload(String iface, boolean on) {
+        if (mNetwork.networkInfo.getType() != TYPE_WIFI) {
+            return;
+        }
+        try {
+            Slog.d(TAG, (on ? "En" : "Dis") + "abling ND offload on " + iface);
+            mNMService.setInterfaceIpv6NdOffload(iface, on);
+        } catch(RemoteException|IllegalStateException e) {
+            Slog.w(TAG, "Changing IPv6 ND offload on " + iface + "failed: " + e);
+        }
+    }
+
     @Override
     public void interfaceAdded(String iface) {
         // Called by the InterfaceObserver on its own thread, so can race with stop().
         if (isStarted() && mIface.equals(iface)) {
             Slog.i(TAG, "interface " + iface + " added, mIsRunning " + mIsRunning + "->true");
 
-            LinkAddress clatAddress;
-            try {
-                InterfaceConfiguration config = mNMService.getInterfaceConfig(iface);
-                clatAddress = config.getLinkAddress();
-            } catch(RemoteException e) {
-                Slog.e(TAG, "Error getting link properties: " + e);
-                return;
-            }
-
             if (!mIsRunning) {
+                LinkAddress clatAddress = getLinkAddress(iface);
+                if (clatAddress == null) {
+                    return;
+                }
                 mIsRunning = true;
+                maybeSetIpv6NdOffload(mBaseIface, false);
                 LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
                 lp.addStackedLink(makeLinkProperties(clatAddress));
                 Slog.i(TAG, "Adding stacked link " + mIface + " on top of " + mBaseIface);
@@ -255,6 +274,7 @@
                 } catch (RemoteException|IllegalStateException e) {
                     // Well, we tried.
                 }
+                maybeSetIpv6NdOffload(mBaseIface, true);
                 LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
                 lp.removeStackedLink(mIface);
                 clear();