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