FileDocCategorySizeDatePackage
Nat464Xlat.javaAPI DocAndroid 5.1 API10975Thu Mar 12 22:22:42 GMT 2015com.android.server.connectivity

Nat464Xlat

public class Nat464Xlat extends com.android.server.net.BaseNetworkObserver
hide
Class to manage a 464xlat CLAT daemon.

Fields Summary
private static final String
TAG
private static final String
CLAT_PREFIX
private final android.os.INetworkManagementService
mNMService
private final android.os.Handler
mHandler
private final NetworkAgentInfo
mNetwork
private String
mBaseIface
private String
mIface
private boolean
mIsRunning
Constructors Summary
public Nat464Xlat(android.content.Context context, android.os.INetworkManagementService nmService, android.os.Handler handler, NetworkAgentInfo nai)


     
               
                
        mNMService = nmService;
        mHandler = handler;
        mNetwork = nai;
    
Methods Summary
private voidclear()
Clears internal state. Must not be called by ConnectivityService.

        mIface = null;
        mBaseIface = null;
        mIsRunning = false;
    
public voidfixupLinkProperties(android.net.LinkProperties oldLp)
Copies the stacked clat link in oldLp, if any, to the LinkProperties in mNetwork. This is necessary because the LinkProperties in mNetwork come from the transport layer, which has no idea that 464xlat is running on top of it.

        if (mNetwork.clatd != null &&
                mIsRunning &&
                mNetwork.linkProperties != null &&
                !mNetwork.linkProperties.getAllInterfaceNames().contains(mIface)) {
            Slog.d(TAG, "clatd running, updating NAI for " + mIface);
            for (LinkProperties stacked: oldLp.getStackedLinks()) {
                if (mIface.equals(stacked.getInterfaceName())) {
                    mNetwork.linkProperties.addStackedLink(stacked);
                    break;
                }
            }
        }
    
private android.net.LinkAddressgetLinkAddress(java.lang.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;
        }
    
public voidinterfaceLinkStateChanged(java.lang.String iface, boolean up)

        // Called by the InterfaceObserver on its own thread, so can race with stop().
        if (isStarted() && up && mIface.equals(iface)) {
            Slog.i(TAG, "interface " + iface + " is up, mIsRunning " + mIsRunning + "->true");

            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);
                updateConnectivityService(lp);
            }
        }
    
public voidinterfaceRemoved(java.lang.String iface)

        if (isStarted() && mIface.equals(iface)) {
            Slog.i(TAG, "interface " + iface + " removed, mIsRunning " + mIsRunning + "->false");

            if (mIsRunning) {
                // The interface going away likely means clatd has crashed. Ask netd to stop it,
                // because otherwise when we try to start it again on the same base interface netd
                // will complain that it's already started.
                //
                // Note that this method can be called by the interface observer at the same time
                // that ConnectivityService calls stop(). In this case, the second call to
                // stopClatd() will just throw IllegalStateException, which we'll ignore.
                try {
                    mNMService.unregisterObserver(this);
                    mNMService.stopClatd(mBaseIface);
                } catch (RemoteException|IllegalStateException e) {
                    // Well, we tried.
                }
                maybeSetIpv6NdOffload(mBaseIface, true);
                LinkProperties lp = new LinkProperties(mNetwork.linkProperties);
                lp.removeStackedLink(mIface);
                clear();
                updateConnectivityService(lp);
            }
        }
    
public booleanisStarted()
Determines whether clatd is started. Always true, except a) if start has not yet been called, or b) if our interface was removed.

        return mIface != null;
    
private android.net.LinkPropertiesmakeLinkProperties(android.net.LinkAddress clatAddress)

        LinkProperties stacked = new LinkProperties();
        stacked.setInterfaceName(mIface);

        // Although the clat interface is a point-to-point tunnel, we don't
        // point the route directly at the interface because some apps don't
        // understand routes without gateways (see, e.g., http://b/9597256
        // http://b/9597516). Instead, set the next hop of the route to the
        // clat IPv4 address itself (for those apps, it doesn't matter what
        // the IP of the gateway is, only that there is one).
        RouteInfo ipv4Default = new RouteInfo(
                new LinkAddress(Inet4Address.ANY, 0),
                clatAddress.getAddress(), mIface);
        stacked.addRoute(ipv4Default);
        stacked.addLinkAddress(clatAddress);
        return stacked;
    
private voidmaybeSetIpv6NdOffload(java.lang.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);
        }
    
public static booleanrequiresClat(NetworkAgentInfo nai)
Determines whether a network requires clat.

param
network the NetworkAgentInfo corresponding to the network.
return
true if the network requires clat, false otherwise.

        final int netType = nai.networkInfo.getType();
        final boolean connected = nai.networkInfo.isConnected();
        final boolean hasIPv4Address =
                (nai.linkProperties != null) ? nai.linkProperties.hasIPv4Address() : false;
        // Only support clat on mobile and wifi for now, because these are the only IPv6-only
        // networks we can connect to.
        return connected && !hasIPv4Address && (netType == TYPE_MOBILE || netType == TYPE_WIFI);
    
public voidstart()
Starts the clat daemon. Called by ConnectivityService on the handler thread.

        if (isStarted()) {
            Slog.e(TAG, "startClat: already started");
            return;
        }

        if (mNetwork.linkProperties == null) {
            Slog.e(TAG, "startClat: Can't start clat with null LinkProperties");
            return;
        }

        try {
            mNMService.registerObserver(this);
        } catch(RemoteException e) {
            Slog.e(TAG, "startClat: Can't register interface observer for clat on " + mNetwork);
            return;
        }

        mBaseIface = mNetwork.linkProperties.getInterfaceName();
        if (mBaseIface == null) {
            Slog.e(TAG, "startClat: Can't start clat on null interface");
            return;
        }
        mIface = CLAT_PREFIX + mBaseIface;
        // From now on, isStarted() will return true.

        Slog.i(TAG, "Starting clatd on " + mBaseIface);
        try {
            mNMService.startClatd(mBaseIface);
        } catch(RemoteException|IllegalStateException e) {
            Slog.e(TAG, "Error starting clatd: " + e);
        }
    
public voidstop()
Stops the clat daemon. Called by ConnectivityService on the handler thread.

        if (isStarted()) {
            Slog.i(TAG, "Stopping clatd");
            try {
                mNMService.stopClatd(mBaseIface);
            } catch(RemoteException|IllegalStateException e) {
                Slog.e(TAG, "Error stopping clatd: " + e);
            }
            // When clatd stops and its interface is deleted, interfaceRemoved() will notify
            // ConnectivityService and call clear().
        } else {
            Slog.e(TAG, "clatd: already stopped");
        }
    
private voidupdateConnectivityService(android.net.LinkProperties lp)

        Message msg = mHandler.obtainMessage(NetworkAgent.EVENT_NETWORK_PROPERTIES_CHANGED, lp);
        msg.replyTo = mNetwork.messenger;
        Slog.i(TAG, "sending message to ConnectivityService: " + msg);
        msg.sendToTarget();