Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3b28e9a3 authored by Robert Greenwalt's avatar Robert Greenwalt
Browse files

Start using IP tool for advanced routing.

bug:5495862
bug:5396842
Change-Id: I5e31b352b14a4dc746cacce4d61cf8d9ad7382a0
parent 8c49b81b
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -104,6 +104,18 @@ interface INetworkManagementService
     */
    void removeRoute(String iface, in RouteInfo route);

    /**
     * Add the specified route to a secondary interface
     * This will go into a special route table to be accessed
     * via ip rules
     */
    void addSecondaryRoute(String iface, in RouteInfo route);

    /**
     * Remove the specified secondary route.
     */
    void removeSecondaryRoute(String iface, in RouteInfo route);

    /**
     * Shuts down the service
     */
+50 −27
Original line number Diff line number Diff line
@@ -171,6 +171,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
    private static final int ENABLED  = 1;
    private static final int DISABLED = 0;

    private static final boolean ADD = true;
    private static final boolean REMOVE = false;

    private static final boolean TO_DEFAULT_TABLE = true;
    private static final boolean TO_SECONDARY_TABLE = false;

    // Share the event space with NetworkStateTracker (which can't see this
    // internal class but sends us events).  If you change these, change
    // NetworkStateTracker.java too.
@@ -501,7 +507,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE);
        INetworkManagementService nmService = INetworkManagementService.Stub.asInterface(b);

        mTethering = new Tethering(mContext, nmService, statsService, mHandler.getLooper());
        mTethering = new Tethering(mContext, nmService, statsService, this, mHandler.getLooper());
        mTetheringConfigValid = ((mTethering.getTetherableUsbRegexs().length != 0 ||
                                  mTethering.getTetherableWifiRegexs().length != 0 ||
                                  mTethering.getTetherableBluetoothRegexs().length != 0) &&
@@ -1146,23 +1152,24 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        return false;
    }

    private boolean addRoute(LinkProperties p, RouteInfo r) {
        return modifyRoute(p.getInterfaceName(), p, r, 0, true);
    private boolean addRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
        return modifyRoute(p.getInterfaceName(), p, r, 0, ADD, toDefaultTable);
    }

    private boolean removeRoute(LinkProperties p, RouteInfo r) {
        return modifyRoute(p.getInterfaceName(), p, r, 0, false);
    private boolean removeRoute(LinkProperties p, RouteInfo r, boolean toDefaultTable) {
        return modifyRoute(p.getInterfaceName(), p, r, 0, REMOVE, toDefaultTable);
    }

    private boolean addRouteToAddress(LinkProperties lp, InetAddress addr) {
        return modifyRouteToAddress(lp, addr, true);
        return modifyRouteToAddress(lp, addr, ADD, TO_DEFAULT_TABLE);
    }

    private boolean removeRouteToAddress(LinkProperties lp, InetAddress addr) {
        return modifyRouteToAddress(lp, addr, false);
        return modifyRouteToAddress(lp, addr, REMOVE, TO_DEFAULT_TABLE);
    }

    private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd) {
    private boolean modifyRouteToAddress(LinkProperties lp, InetAddress addr, boolean doAdd,
            boolean toDefaultTable) {
        RouteInfo bestRoute = RouteInfo.selectBestRoute(lp.getRoutes(), addr);
        if (bestRoute == null) {
            bestRoute = RouteInfo.makeHostRoute(addr);
@@ -1176,15 +1183,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                bestRoute = RouteInfo.makeHostRoute(addr, bestRoute.getGateway());
            }
        }
        return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd);
        return modifyRoute(lp.getInterfaceName(), lp, bestRoute, 0, doAdd, toDefaultTable);
    }

    private boolean modifyRoute(String ifaceName, LinkProperties lp, RouteInfo r, int cycleCount,
            boolean doAdd) {
            boolean doAdd, boolean toDefaultTable) {
        if ((ifaceName == null) || (lp == null) || (r == null)) return false;

        if (cycleCount > MAX_HOSTROUTE_CYCLE_COUNT) {
            loge("Error adding route - too much recursion");
            loge("Error modifying route - too much recursion");
            return false;
        }

@@ -1199,14 +1206,18 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                    // route to it's gateway
                    bestRoute = RouteInfo.makeHostRoute(r.getGateway(), bestRoute.getGateway());
                }
                modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd);
                modifyRoute(ifaceName, lp, bestRoute, cycleCount+1, doAdd, toDefaultTable);
            }
        }
        if (doAdd) {
            if (VDBG) log("Adding " + r + " for interface " + ifaceName);
            mAddedRoutes.add(r);
            try {
                if (toDefaultTable) {
                    mAddedRoutes.add(r);  // only track default table - only one apps can effect
                    mNetd.addRoute(ifaceName, r);
                } else {
                    mNetd.addSecondaryRoute(ifaceName, r);
                }
            } catch (Exception e) {
                // never crash - catch them all
                if (VDBG) loge("Exception trying to add a route: " + e);
@@ -1215,6 +1226,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        } else {
            // if we remove this one and there are no more like it, then refcount==0 and
            // we can remove it from the table
            if (toDefaultTable) {
                mAddedRoutes.remove(r);
                if (mAddedRoutes.contains(r) == false) {
                    if (VDBG) log("Removing " + r + " for interface " + ifaceName);
@@ -1228,6 +1240,16 @@ public class ConnectivityService extends IConnectivityManager.Stub {
                } else {
                    if (VDBG) log("not removing " + r + " as it's still in use");
                }
            } else {
                if (VDBG) log("Removing " + r + " for interface " + ifaceName);
                try {
                    mNetd.removeSecondaryRoute(ifaceName, r);
                } catch (Exception e) {
                    // never crash - catch them all
                    if (VDBG) loge("Exception trying to remove a route: " + e);
                    return false;
                }
            }
        }
        return true;
    }
@@ -1862,14 +1884,21 @@ public class ConnectivityService extends IConnectivityManager.Stub {

        for (RouteInfo r : routeDiff.removed) {
            if (isLinkDefault || ! r.isDefaultRoute()) {
                removeRoute(curLp, r);
                removeRoute(curLp, r, TO_DEFAULT_TABLE);
            }
            if (isLinkDefault == false) {
                // remove from a secondary route table
                removeRoute(curLp, r, TO_SECONDARY_TABLE);
            }
        }

        for (RouteInfo r :  routeDiff.added) {
            if (isLinkDefault || ! r.isDefaultRoute()) {
                addRoute(newLp, r);
                addRoute(newLp, r, TO_DEFAULT_TABLE);
            } else {
                // add to a secondary route table
                addRoute(newLp, r, TO_SECONDARY_TABLE);

                // many radios add a default route even when we don't want one.
                // remove the default route unless somebody else has asked for it
                String ifaceName = newLp.getInterfaceName();
@@ -2450,12 +2479,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
        int defaultVal = (SystemProperties.get("ro.tether.denied").equals("true") ? 0 : 1);
        boolean tetherEnabledInSettings = (Settings.Secure.getInt(mContext.getContentResolver(),
                Settings.Secure.TETHER_SUPPORTED, defaultVal) != 0);
        // Short term disabling of Tethering if DUN is required.
        // TODO - fix multi-connection tethering using policy-base routing
        int[] upstreamConnTypes = mTethering.getUpstreamIfaceTypes();
        for (int i : upstreamConnTypes) {
            if (i == ConnectivityManager.TYPE_MOBILE_DUN) return false;
        }
        return tetherEnabledInSettings && mTetheringConfigValid;
    }

+48 −11
Original line number Diff line number Diff line
@@ -59,7 +59,11 @@ import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.InterfaceAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
@@ -77,6 +81,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
    private static final int ADD = 1;
    private static final int REMOVE = 2;

    private static final String DEFAULT = "default";
    private static final String SECONDARY = "secondary";

    /**
     * Name representing {@link #setGlobalAlert(long)} limit when delivered to
     * {@link INetworkManagementEventObserver#limitReached(String, String)}.
@@ -500,15 +507,25 @@ public class NetworkManagementService extends INetworkManagementService.Stub

    public void addRoute(String interfaceName, RouteInfo route) {
        mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
        modifyRoute(interfaceName, ADD, route);
        modifyRoute(interfaceName, ADD, route, DEFAULT);
    }

    public void removeRoute(String interfaceName, RouteInfo route) {
        mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
        modifyRoute(interfaceName, REMOVE, route);
        modifyRoute(interfaceName, REMOVE, route, DEFAULT);
    }

    private void modifyRoute(String interfaceName, int action, RouteInfo route) {
    public void addSecondaryRoute(String interfaceName, RouteInfo route) {
        mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
        modifyRoute(interfaceName, ADD, route, SECONDARY);
    }

    public void removeSecondaryRoute(String interfaceName, RouteInfo route) {
        mContext.enforceCallingOrSelfPermission(CHANGE_NETWORK_STATE, TAG);
        modifyRoute(interfaceName, REMOVE, route, SECONDARY);
    }

    private void modifyRoute(String interfaceName, int action, RouteInfo route, String type) {
        ArrayList<String> rsp;

        StringBuilder cmd;
@@ -516,12 +533,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub
        switch (action) {
            case ADD:
            {
                cmd = new StringBuilder("interface route add " + interfaceName);
                cmd = new StringBuilder("interface route add " + interfaceName + " " + type);
                break;
            }
            case REMOVE:
            {
                cmd = new StringBuilder("interface route remove " + interfaceName);
                cmd = new StringBuilder("interface route remove " + interfaceName + " " + type);
                break;
            }
            default:
@@ -828,14 +845,33 @@ public class NetworkManagementService extends INetworkManagementService.Stub
        }
    }

    private void modifyNat(String cmd, String internalInterface, String externalInterface)
            throws SocketException {
        cmd = String.format("nat %s %s %s", cmd, internalInterface, externalInterface);

        NetworkInterface internalNetworkInterface =
                NetworkInterface.getByName(internalInterface);
        Collection<InterfaceAddress>interfaceAddresses =
                internalNetworkInterface.getInterfaceAddresses();
        cmd += " " + interfaceAddresses.size();
        for (InterfaceAddress ia : interfaceAddresses) {
            InetAddress addr = NetworkUtils.getNetworkPart(ia.getAddress(),
                    ia.getNetworkPrefixLength());
            cmd = cmd + " " + addr.getHostAddress() + "/" + ia.getNetworkPrefixLength();
        }

        mConnector.doCommand(cmd);
    }

    public void enableNat(String internalInterface, String externalInterface)
            throws IllegalStateException {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
        if (DBG) Log.d(TAG, "enableNat(" + internalInterface + ", " + externalInterface + ")");
        try {
            mConnector.doCommand(
                    String.format("nat enable %s %s", internalInterface, externalInterface));
        } catch (NativeDaemonConnectorException e) {
            modifyNat("enable", internalInterface, externalInterface);
        } catch (Exception e) {
            Log.e(TAG, "enableNat got Exception " + e.toString());
            throw new IllegalStateException(
                    "Unable to communicate to native daemon for enabling NAT interface");
        }
@@ -845,10 +881,11 @@ public class NetworkManagementService extends INetworkManagementService.Stub
            throws IllegalStateException {
        mContext.enforceCallingOrSelfPermission(
                android.Manifest.permission.CHANGE_NETWORK_STATE, "NetworkManagementService");
        if (DBG) Log.d(TAG, "disableNat(" + internalInterface + ", " + externalInterface + ")");
        try {
            mConnector.doCommand(
                    String.format("nat disable %s %s", internalInterface, externalInterface));
        } catch (NativeDaemonConnectorException e) {
            modifyNat("disable", internalInterface, externalInterface);
        } catch (Exception e) {
            Log.e(TAG, "disableNat got Exception " + e.toString());
            throw new IllegalStateException(
                    "Unable to communicate to native daemon for disabling NAT interface");
        }
+10 −14
Original line number Diff line number Diff line
@@ -91,6 +91,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {

    private final INetworkManagementService mNMService;
    private final INetworkStatsService mStatsService;
    private final IConnectivityManager mConnService;
    private Looper mLooper;
    private HandlerThread mThread;

@@ -127,10 +128,11 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
                                         // when RNDIS is enabled

    public Tethering(Context context, INetworkManagementService nmService,
            INetworkStatsService statsService, Looper looper) {
            INetworkStatsService statsService, IConnectivityManager connService, Looper looper) {
        mContext = context;
        mNMService = nmService;
        mStatsService = statsService;
        mConnService = connService;
        mLooper = looper;

        mIfaces = new HashMap<String, TetherInterfaceSM>();
@@ -347,10 +349,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
    }

    private void sendTetherStateChangedBroadcast() {
        IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
        IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
        try {
            if (!cm.isTetheringSupported()) return;
            if (!mConnService.isTetheringSupported()) return;
        } catch (RemoteException e) {
            return;
        }
@@ -910,6 +910,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
                try {
                    mNMService.tetherInterface(mIfaceName);
                } catch (Exception e) {
                    Log.e(TAG, "Error Tethering: " + e.toString());
                    setLastError(ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR);

                    transitionTo(mInitialState);
@@ -987,6 +988,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
                            try {
                                mNMService.enableNat(mIfaceName, newUpstreamIfaceName);
                            } catch (Exception e) {
                                Log.e(TAG, "Exception enabling Nat: " + e.toString());
                                try {
                                    mNMService.untetherInterface(mIfaceName);
                                } catch (Exception ee) {}
@@ -1150,13 +1152,11 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
                boolean retValue = true;
                if (apnType == ConnectivityManager.TYPE_NONE) return false;
                if (apnType != mMobileApnReserved) turnOffUpstreamMobileConnection();
                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
                int result = Phone.APN_REQUEST_FAILED;
                String enableString = enableString(apnType);
                if (enableString == null) return false;
                try {
                    result = cm.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
                    result = mConnService.startUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
                            enableString, new Binder());
                } catch (Exception e) {
                }
@@ -1178,10 +1178,8 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
            }
            protected boolean turnOffUpstreamMobileConnection() {
                if (mMobileApnReserved != ConnectivityManager.TYPE_NONE) {
                    IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                    IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
                    try {
                        cm.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
                        mConnService.stopUsingNetworkFeature(ConnectivityManager.TYPE_MOBILE,
                                enableString(mMobileApnReserved));
                    } catch (Exception e) {
                        return false;
@@ -1234,8 +1232,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
            }

            protected void chooseUpstreamType(boolean tryCell) {
                IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                IConnectivityManager cm = IConnectivityManager.Stub.asInterface(b);
                int upType = ConnectivityManager.TYPE_NONE;
                String iface = null;

@@ -1251,7 +1247,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
                for (Integer netType : mUpstreamIfaceTypes) {
                    NetworkInfo info = null;
                    try {
                        info = cm.getNetworkInfo(netType.intValue());
                        info = mConnService.getNetworkInfo(netType.intValue());
                    } catch (RemoteException e) { }
                    if ((info != null) && info.isConnected()) {
                        upType = netType.intValue();
@@ -1283,7 +1279,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
                } else {
                    LinkProperties linkProperties = null;
                    try {
                        linkProperties = cm.getLinkProperties(upType);
                        linkProperties = mConnService.getLinkProperties(upType);
                    } catch (RemoteException e) { }
                    if (linkProperties != null) iface = linkProperties.getInterfaceName();
                }