113c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti/* 213c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * Copyright (C) 2012 The Android Open Source Project 313c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * 413c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * Licensed under the Apache License, Version 2.0 (the "License"); 513c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * you may not use this file except in compliance with the License. 613c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * You may obtain a copy of the License at 713c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * 813c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * http://www.apache.org/licenses/LICENSE-2.0 913c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * 1013c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * Unless required by applicable law or agreed to in writing, software 1113c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * distributed under the License is distributed on an "AS IS" BASIS, 1213c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1313c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * See the License for the specific language governing permissions and 1413c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti * limitations under the License. 1513c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti */ 1613c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti 1713c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colittipackage com.android.server.connectivity; 1813c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti 1913c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colittiimport android.net.InterfaceConfiguration; 20853d741ce739e0562e8b5386b8165e3d560fe7d4Lorenzo Colittiimport android.net.ConnectivityManager; 2113c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colittiimport android.net.LinkAddress; 2213c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colittiimport android.net.LinkProperties; 2313c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colittiimport android.net.RouteInfo; 2413c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colittiimport android.os.INetworkManagementService; 2513c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colittiimport android.os.RemoteException; 2613c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colittiimport android.util.Slog; 2713c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti 283711910dca8a0104900e21a549a8fd99963a7ff0Hugo Benichiimport com.android.internal.util.ArrayUtils; 293fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichiimport com.android.server.net.BaseNetworkObserver; 3013c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti 31883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichiimport java.net.Inet4Address; 32883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichiimport java.util.Objects; 33883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi 3413c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti/** 353fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * Class to manage a 464xlat CLAT daemon. Nat464Xlat is not thread safe and should be manipulated 363fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * from a consistent and unique thread context. It is the responsibility of ConnectivityService to 373fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * call into this class from its own Handler thread. 386f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi * 396f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi * @hide 4013c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti */ 4113c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colittipublic class Nat464Xlat extends BaseNetworkObserver { 426f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi private static final String TAG = Nat464Xlat.class.getSimpleName(); 43954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti 44954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti // This must match the interface prefix in clatd.c. 45954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti private static final String CLAT_PREFIX = "v4-"; 46954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti 476f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi // The network types we will start clatd on, 486f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi // allowing clat only on networks for which we can support IPv6-only. 49853d741ce739e0562e8b5386b8165e3d560fe7d4Lorenzo Colitti private static final int[] NETWORK_TYPES = { 50853d741ce739e0562e8b5386b8165e3d560fe7d4Lorenzo Colitti ConnectivityManager.TYPE_MOBILE, 51853d741ce739e0562e8b5386b8165e3d560fe7d4Lorenzo Colitti ConnectivityManager.TYPE_WIFI, 52853d741ce739e0562e8b5386b8165e3d560fe7d4Lorenzo Colitti ConnectivityManager.TYPE_ETHERNET, 53853d741ce739e0562e8b5386b8165e3d560fe7d4Lorenzo Colitti }; 54853d741ce739e0562e8b5386b8165e3d560fe7d4Lorenzo Colitti 55954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti private final INetworkManagementService mNMService; 56954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti 57e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti // The network we're running on, and its type. 58954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti private final NetworkAgentInfo mNetwork; 5913c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti 60883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi private enum State { 61883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi IDLE, // start() not called. Base iface and stacked iface names are null. 62883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi STARTING, // start() called. Base iface and stacked iface names are known. 633fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi RUNNING, // start() called, and the stacked iface is known to be up. 643fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi STOPPING; // stop() called, this Nat464Xlat is still registered as a network observer for 653fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi // the stacked interface. 66883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi } 67883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi 68954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti private String mBaseIface; 69954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti private String mIface; 703fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi private State mState = State.IDLE; 7113c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti 723fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi public Nat464Xlat(INetworkManagementService nmService, NetworkAgentInfo nai) { 7313c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti mNMService = nmService; 74954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti mNetwork = nai; 7513c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti } 7613c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti 7713c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti /** 783b75982e39ed9370153ae7f238f1d6041b9506edPaul Jensen * Determines whether a network requires clat. 793b75982e39ed9370153ae7f238f1d6041b9506edPaul Jensen * @param network the NetworkAgentInfo corresponding to the network. 803b75982e39ed9370153ae7f238f1d6041b9506edPaul Jensen * @return true if the network requires clat, false otherwise. 8113c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti */ 821df5fa55c5a5c1ba054b783ea639c99d57c357cfLorenzo Colitti public static boolean requiresClat(NetworkAgentInfo nai) { 836f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi // TODO: migrate to NetworkCapabilities.TRANSPORT_*. 841df5fa55c5a5c1ba054b783ea639c99d57c357cfLorenzo Colitti final int netType = nai.networkInfo.getType(); 856f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi final boolean supported = ArrayUtils.contains(NETWORK_TYPES, nai.networkInfo.getType()); 863fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi // TODO: this should also consider if the network is in SUSPENDED state to avoid stopping 873fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi // clatd in SUSPENDED state. 881df5fa55c5a5c1ba054b783ea639c99d57c357cfLorenzo Colitti final boolean connected = nai.networkInfo.isConnected(); 896f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi // We only run clat on networks that don't have a native IPv4 address. 901df5fa55c5a5c1ba054b783ea639c99d57c357cfLorenzo Colitti final boolean hasIPv4Address = 916f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi (nai.linkProperties != null) && nai.linkProperties.hasIPv4Address(); 926f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi return supported && connected && !hasIPv4Address; 9313c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti } 9413c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti 95954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti /** 96883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi * @return true if clatd has been started and has not yet stopped. 97883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi * A true result corresponds to internal states STARTING and RUNNING. 98954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti */ 99954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti public boolean isStarted() { 100883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi return mState != State.IDLE; 101883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi } 102883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi 103883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi /** 1043fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * @return true if clatd has been started but the stacked interface is not yet up. 1053fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi */ 1063fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi public boolean isStarting() { 1073fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi return mState == State.STARTING; 1083fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } 1093fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi 1103fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi /** 111883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi * @return true if clatd has been started and the stacked interface is up. 112883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi */ 113883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi public boolean isRunning() { 114883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi return mState == State.RUNNING; 115883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi } 116883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi 117883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi /** 1183fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * @return true if clatd has been stopped. 1193fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi */ 1203fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi public boolean isStopping() { 1213fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi return mState == State.STOPPING; 1223fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } 1233fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi 1243fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi /** 1253fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * Start clatd, register this Nat464Xlat as a network observer for the stacked interface, 1263fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * and set internal state. 127883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi */ 128883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi private void enterStartingState(String baseIface) { 1293fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi try { 1303fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi mNMService.registerObserver(this); 1313fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } catch(RemoteException e) { 1323fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi Slog.e(TAG, 1333fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi "startClat: Can't register interface observer for clat on " + mNetwork.name()); 1343fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi return; 1353fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } 1363fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi try { 1373fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi mNMService.startClatd(baseIface); 1383fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } catch(RemoteException|IllegalStateException e) { 1393fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi Slog.e(TAG, "Error starting clatd on " + baseIface, e); 1403fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } 141883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi mIface = CLAT_PREFIX + baseIface; 142883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi mBaseIface = baseIface; 143883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi mState = State.STARTING; 144954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti } 145954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti 146954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti /** 1473fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * Enter running state just after getting confirmation that the stacked interface is up, and 1483fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * turn ND offload off if on WiFi. 1493fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi */ 1503fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi private void enterRunningState() { 1513fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi maybeSetIpv6NdOffload(mBaseIface, false); 1523fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi mState = State.RUNNING; 1533fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } 1543fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi 1553fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi /** 1563fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * Stop clatd, and turn ND offload on if it had been turned off. 1573fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi */ 1583fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi private void enterStoppingState() { 1593fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi if (isRunning()) { 1603fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi maybeSetIpv6NdOffload(mBaseIface, true); 1613fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } 1623fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi 1633fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi try { 1643fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi mNMService.stopClatd(mBaseIface); 1653fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } catch(RemoteException|IllegalStateException e) { 1663fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi Slog.e(TAG, "Error stopping clatd on " + mBaseIface, e); 1673fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } 1683fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi 1693fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi mState = State.STOPPING; 1703fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } 1713fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi 1723fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi /** 1733fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * Unregister as a base observer for the stacked interface, and clear internal state. 174954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti */ 175883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi private void enterIdleState() { 1763fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi try { 1773fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi mNMService.unregisterObserver(this); 1783fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } catch(RemoteException|IllegalStateException e) { 1793fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi Slog.e(TAG, "Error unregistering clatd observer on " + mBaseIface, e); 1803fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } 1813fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi 182954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti mIface = null; 183954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti mBaseIface = null; 184883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi mState = State.IDLE; 185d2ef1e50c491239e43c7b557ea1f7fc03e84f8f9Lorenzo Colitti } 186d2ef1e50c491239e43c7b557ea1f7fc03e84f8f9Lorenzo Colitti 18713c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti /** 1883fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * Starts the clat daemon. 18913c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti */ 190954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti public void start() { 191954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti if (isStarted()) { 192954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti Slog.e(TAG, "startClat: already started"); 1933b75982e39ed9370153ae7f238f1d6041b9506edPaul Jensen return; 1943b75982e39ed9370153ae7f238f1d6041b9506edPaul Jensen } 195954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti 196954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti if (mNetwork.linkProperties == null) { 197954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti Slog.e(TAG, "startClat: Can't start clat with null LinkProperties"); 19813c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti return; 19913c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti } 200954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti 201883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi String baseIface = mNetwork.linkProperties.getInterfaceName(); 202883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi if (baseIface == null) { 203954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti Slog.e(TAG, "startClat: Can't start clat on null interface"); 204954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti return; 205954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti } 206883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi // TODO: should we only do this if mNMService.startClatd() succeeds? 2073fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi Slog.i(TAG, "Starting clatd on " + baseIface); 208883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi enterStartingState(baseIface); 20913c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti } 21013c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti 21113c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti /** 2123fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * Stops the clat daemon. 21313c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti */ 214954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti public void stop() { 215883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi if (!isStarted()) { 216883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi return; 217883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi } 218883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi Slog.i(TAG, "Stopping clatd on " + mBaseIface); 2193711910dca8a0104900e21a549a8fd99963a7ff0Hugo Benichi 2203fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi boolean wasStarting = isStarting(); 2213fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi enterStoppingState(); 2223fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi if (wasStarting) { 2233fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi enterIdleState(); 2243fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } 2253b75982e39ed9370153ae7f238f1d6041b9506edPaul Jensen } 2263b75982e39ed9370153ae7f238f1d6041b9506edPaul Jensen 227954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti /** 228954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti * Copies the stacked clat link in oldLp, if any, to the LinkProperties in mNetwork. 229954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti * This is necessary because the LinkProperties in mNetwork come from the transport layer, which 230954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti * has no idea that 464xlat is running on top of it. 231954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti */ 232954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti public void fixupLinkProperties(LinkProperties oldLp) { 233883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi if (!isRunning()) { 234883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi return; 235883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi } 236883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi LinkProperties lp = mNetwork.linkProperties; 237883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi if (lp == null || lp.getAllInterfaceNames().contains(mIface)) { 238883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi return; 239883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi } 240883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi 241883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi Slog.d(TAG, "clatd running, updating NAI for " + mIface); 242883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi for (LinkProperties stacked: oldLp.getStackedLinks()) { 243883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi if (Objects.equals(mIface, stacked.getInterfaceName())) { 244883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi lp.addStackedLink(stacked); 245883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi return; 2461df5fa55c5a5c1ba054b783ea639c99d57c357cfLorenzo Colitti } 2471df5fa55c5a5c1ba054b783ea639c99d57c357cfLorenzo Colitti } 2481df5fa55c5a5c1ba054b783ea639c99d57c357cfLorenzo Colitti } 2491df5fa55c5a5c1ba054b783ea639c99d57c357cfLorenzo Colitti 250954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti private LinkProperties makeLinkProperties(LinkAddress clatAddress) { 251954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti LinkProperties stacked = new LinkProperties(); 252954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti stacked.setInterfaceName(mIface); 253954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti 254954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti // Although the clat interface is a point-to-point tunnel, we don't 255954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti // point the route directly at the interface because some apps don't 256954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti // understand routes without gateways (see, e.g., http://b/9597256 257954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti // http://b/9597516). Instead, set the next hop of the route to the 258954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti // clat IPv4 address itself (for those apps, it doesn't matter what 259954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti // the IP of the gateway is, only that there is one). 260954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti RouteInfo ipv4Default = new RouteInfo( 261954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti new LinkAddress(Inet4Address.ANY, 0), 262954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti clatAddress.getAddress(), mIface); 263954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti stacked.addRoute(ipv4Default); 264954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti stacked.addLinkAddress(clatAddress); 265954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti return stacked; 266954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti } 267954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti 268e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti private LinkAddress getLinkAddress(String iface) { 269e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti try { 270e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti InterfaceConfiguration config = mNMService.getInterfaceConfig(iface); 271e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti return config.getLinkAddress(); 272e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti } catch(RemoteException|IllegalStateException e) { 273e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti Slog.e(TAG, "Error getting link properties: " + e); 274e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti return null; 275e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti } 276e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti } 277e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti 278e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti private void maybeSetIpv6NdOffload(String iface, boolean on) { 2796f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi // TODO: migrate to NetworkCapabilities.TRANSPORT_*. 280853d741ce739e0562e8b5386b8165e3d560fe7d4Lorenzo Colitti if (mNetwork.networkInfo.getType() != ConnectivityManager.TYPE_WIFI) { 281e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti return; 282e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti } 283e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti try { 284e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti Slog.d(TAG, (on ? "En" : "Dis") + "abling ND offload on " + iface); 285e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti mNMService.setInterfaceIpv6NdOffload(iface, on); 286e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti } catch(RemoteException|IllegalStateException e) { 287e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti Slog.w(TAG, "Changing IPv6 ND offload on " + iface + "failed: " + e); 288e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti } 289e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti } 290e21a26b3ba78b0238f4ed4a09b43319a2320fbaaLorenzo Colitti 291883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi /** 2923fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * Adds stacked link on base link and transitions to RUNNING state. 293883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi */ 2943fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi private void handleInterfaceLinkStateChanged(String iface, boolean up) { 2953fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi if (!isStarting() || !up || !Objects.equals(mIface, iface)) { 296883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi return; 297883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi } 2983fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi 299883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi LinkAddress clatAddress = getLinkAddress(iface); 300883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi if (clatAddress == null) { 3013fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi Slog.e(TAG, "clatAddress was null for stacked iface " + iface); 302883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi return; 30313c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti } 3043fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi 305883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi Slog.i(TAG, String.format("interface %s is up, adding stacked link %s on top of %s", 306883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi mIface, mIface, mBaseIface)); 3073fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi enterRunningState(); 308883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi LinkProperties lp = new LinkProperties(mNetwork.linkProperties); 309883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi lp.addStackedLink(makeLinkProperties(clatAddress)); 3103fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi mNetwork.connService().handleUpdateLinkProperties(mNetwork, lp); 31113c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti } 31213c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti 3133fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi /** 3143fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi * Removes stacked link on base link and transitions to IDLE state. 3153fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi */ 3163fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi private void handleInterfaceRemoved(String iface) { 3173fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi if (!Objects.equals(mIface, iface)) { 3183711910dca8a0104900e21a549a8fd99963a7ff0Hugo Benichi return; 3193711910dca8a0104900e21a549a8fd99963a7ff0Hugo Benichi } 3203fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi if (!isRunning() && !isStopping()) { 321883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi return; 322883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi } 323883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi 324883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi Slog.i(TAG, "interface " + iface + " removed"); 3253fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi if (!isStopping()) { 3263fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi // Ensure clatd is stopped if stop() has not been called: this likely means that clatd 3273fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi // has crashed. 3283fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi enterStoppingState(); 32913c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti } 330883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi enterIdleState(); 3313fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi LinkProperties lp = new LinkProperties(mNetwork.linkProperties); 3323fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi lp.removeStackedLink(iface); 3333fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi mNetwork.connService().handleUpdateLinkProperties(mNetwork, lp); 3343fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } 3353fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi 3363fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi @Override 3373fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi public void interfaceLinkStateChanged(String iface, boolean up) { 3383fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi mNetwork.handler().post(() -> { handleInterfaceLinkStateChanged(iface, up); }); 3393fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi } 3403fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi 3413fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi @Override 3423fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi public void interfaceRemoved(String iface) { 3433fb5f0db3ffe658fe039f0453c6bc0c46fd5441aHugo Benichi mNetwork.handler().post(() -> { handleInterfaceRemoved(iface); }); 34413c9fdefdec907aaa339ffd67c0ded116cccba01Lorenzo Colitti } 3456f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi 3466f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi @Override 3476f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi public String toString() { 348883b6492d7fdf94f0ac3a22af62a11303309827bHugo Benichi return "mBaseIface: " + mBaseIface + ", mIface: " + mIface + ", mState: " + mState; 3496f62b73915296e59390e69b15160ccb7c031f733Hugo Benichi } 350954394653dad05838235f48244a4320893e0f0cfLorenzo Colitti} 351