Fix IPv6 on wifi

Bug: 5388757
Change-Id: I3c8c776c26dad1daa9801d0455fde749c0206401
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 66373fe..be87946 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -79,6 +79,16 @@
     void setInterfaceIpv6PrivacyExtensions(String iface, boolean enable);
 
     /**
+     * Disable IPv6 on an interface
+     */
+    void disableIpv6(String iface);
+
+    /**
+     * Enable IPv6 on an interface
+     */
+    void enableIpv6(String iface);
+
+    /**
      * Retrieves the network routes currently configured on the specified
      * interface
      */
diff --git a/services/java/com/android/server/NetworkManagementService.java b/services/java/com/android/server/NetworkManagementService.java
index 6fcf399..aacaa6a 100644
--- a/services/java/com/android/server/NetworkManagementService.java
+++ b/services/java/com/android/server/NetworkManagementService.java
@@ -508,6 +508,28 @@
         }
     }
 
+    public void enableIpv6(String iface) throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+        try {
+            mConnector.doCommand(String.format("interface ipv6 %s enable", iface));
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate to native daemon for enabling ipv6");
+        }
+    }
+
+    public void disableIpv6(String iface) throws IllegalStateException {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
+        try {
+            mConnector.doCommand(String.format("interface ipv6 %s disable", iface));
+        } catch (NativeDaemonConnectorException e) {
+            throw new IllegalStateException(
+                    "Unable to communicate to native daemon for disabling ipv6");
+        }
+    }
+
     public void addRoute(String interfaceName, RouteInfo route) {
         modifyRoute(interfaceName, ADD, route);
     }
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 41fc55d..d1522fb 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -1560,8 +1560,9 @@
 
         try {
             mNwService.clearInterfaceAddresses(mInterfaceName);
+            mNwService.disableIpv6(mInterfaceName);
         } catch (Exception e) {
-            Log.e(TAG, "Failed to clear IP addresses on disconnect" + e);
+            Log.e(TAG, "Failed to clear addresses or disable ipv6" + e);
         }
 
         /* Reset data structures */
@@ -1841,6 +1842,21 @@
             mWifiP2pManager = (WifiP2pManager) mContext.getSystemService(Context.WIFI_P2P_SERVICE);
             mWifiP2pChannel.connect(mContext, getHandler(), mWifiP2pManager.getMessenger());
 
+            /* IPv6 is disabled at boot time and is controlled by framework
+             * to be enabled only as long as we are connected to an access point
+             *
+             * This fixes issues, a few being:
+             * - IPv6 addresses and routes stick around after disconnection
+             * - When connected, the kernel is unaware and can fail to start IPv6 negotiation
+             * - The kernel sometimes starts autoconfiguration when 802.1x is not complete
+             */
+            try {
+                mNwService.disableIpv6(mInterfaceName);
+            } catch (RemoteException re) {
+                Log.e(TAG, "Failed to disable IPv6: " + re);
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "Failed to disable IPv6: " + e);
+            }
         }
     }
 
@@ -2734,7 +2750,15 @@
             if (DBG) Log.d(TAG, getName() + "\n");
             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
 
-             if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
+            try {
+                mNwService.enableIpv6(mInterfaceName);
+            } catch (RemoteException re) {
+                Log.e(TAG, "Failed to enable IPv6: " + re);
+            } catch (IllegalStateException e) {
+                Log.e(TAG, "Failed to enable IPv6: " + e);
+            }
+
+            if (!WifiConfigStore.isUsingStaticIp(mLastNetworkId)) {
                 //start DHCP
                 mDhcpStateMachine = DhcpStateMachine.makeDhcpStateMachine(
                         mContext, WifiStateMachine.this, mInterfaceName);
@@ -2758,7 +2782,7 @@
                     sendMessage(CMD_STATIC_IP_FAILURE);
                 }
             }
-         }
+        }
       @Override
       public boolean processMessage(Message message) {
           if (DBG) Log.d(TAG, getName() + message.toString() + "\n");