Loading services/core/java/com/android/server/connectivity/Tethering.java +10 −0 Original line number Original line Diff line number Diff line Loading @@ -1392,6 +1392,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering for (Integer netType : mUpstreamIfaceTypes) { for (Integer netType : mUpstreamIfaceTypes) { NetworkInfo info = cm.getNetworkInfo(netType.intValue()); NetworkInfo info = cm.getNetworkInfo(netType.intValue()); // TODO: if the network is suspended we should consider // that to be the same as connected here. if ((info != null) && info.isConnected()) { if ((info != null) && info.isConnected()) { upType = netType.intValue(); upType = netType.intValue(); break; break; Loading Loading @@ -1465,6 +1467,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering // it immediately, because there likely will be no second // it immediately, because there likely will be no second // EVENT_ON_AVAILABLE (it was already received). // EVENT_ON_AVAILABLE (it was already received). handleNewUpstreamNetworkState(ns); handleNewUpstreamNetworkState(ns); } else if (mCurrentUpstreamIface == null) { // There are no available upstream networks, or none that // have an IPv4 default route (current metric for success). handleNewUpstreamNetworkState(null); } } } } Loading Loading @@ -1639,6 +1645,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering chooseUpstreamType(mTryCell); chooseUpstreamType(mTryCell); mTryCell = !mTryCell; mTryCell = !mTryCell; } } @Override @Override public void exit() { public void exit() { // TODO: examine if we should check the return value. // TODO: examine if we should check the return value. Loading @@ -1646,7 +1653,9 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering mUpstreamNetworkMonitor.stop(); mUpstreamNetworkMonitor.stop(); stopListeningForSimChanges(); stopListeningForSimChanges(); notifyTetheredOfNewUpstreamIface(null); notifyTetheredOfNewUpstreamIface(null); handleNewUpstreamNetworkState(null); } } @Override @Override public boolean processMessage(Message message) { public boolean processMessage(Message message) { maybeLogMessage(this, message.what); maybeLogMessage(this, message.what); Loading Loading @@ -1734,6 +1743,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering // reevaluation is triggered via received CONNECTIVITY_ACTION // reevaluation is triggered via received CONNECTIVITY_ACTION // broadcasts that result in being passed a // broadcasts that result in being passed a // TetherMasterSM.CMD_UPSTREAM_CHANGED. // TetherMasterSM.CMD_UPSTREAM_CHANGED. handleNewUpstreamNetworkState(null); break; break; default: default: break; break; Loading services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java +9 −9 Original line number Original line Diff line number Diff line Loading @@ -55,7 +55,7 @@ public class IPv6TetheringCoordinator { if (VDBG) { if (VDBG) { Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns)); Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns)); } } if (ns == null || ns.network == null) { if (!canTetherIPv6(ns)) { stopIPv6TetheringOnAllInterfaces(); stopIPv6TetheringOnAllInterfaces(); setUpstreamNetworkState(null); setUpstreamNetworkState(null); return; return; Loading @@ -65,8 +65,9 @@ public class IPv6TetheringCoordinator { !ns.network.equals(mUpstreamNetworkState.network)) { !ns.network.equals(mUpstreamNetworkState.network)) { stopIPv6TetheringOnAllInterfaces(); stopIPv6TetheringOnAllInterfaces(); } } setUpstreamNetworkState(ns); setUpstreamNetworkState(ns); maybeUpdateIPv6TetheringInterfaces(); updateIPv6TetheringInterfaces(); } } private void stopIPv6TetheringOnAllInterfaces() { private void stopIPv6TetheringOnAllInterfaces() { Loading @@ -77,9 +78,10 @@ public class IPv6TetheringCoordinator { } } private void setUpstreamNetworkState(NetworkState ns) { private void setUpstreamNetworkState(NetworkState ns) { if (!canTetherIPv6(ns)) { if (ns == null) { mUpstreamNetworkState = null; mUpstreamNetworkState = null; } else { } else { // Make a deep copy of the parts we need. mUpstreamNetworkState = new NetworkState( mUpstreamNetworkState = new NetworkState( null, null, new LinkProperties(ns.linkProperties), new LinkProperties(ns.linkProperties), Loading @@ -94,19 +96,17 @@ public class IPv6TetheringCoordinator { } } } } private void maybeUpdateIPv6TetheringInterfaces() { private void updateIPv6TetheringInterfaces() { if (mUpstreamNetworkState == null) return; for (TetherInterfaceStateMachine sm : mNotifyList) { for (TetherInterfaceStateMachine sm : mNotifyList) { final LinkProperties lp = getInterfaceIPv6LinkProperties(sm.interfaceType()); final LinkProperties lp = getInterfaceIPv6LinkProperties(sm.interfaceType()); if (lp != null) { sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp); sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp); } break; break; } } } } private LinkProperties getInterfaceIPv6LinkProperties(int interfaceType) { private LinkProperties getInterfaceIPv6LinkProperties(int interfaceType) { if (mUpstreamNetworkState == null) return null; // NOTE: Here, in future, we would have policies to decide how to divvy // NOTE: Here, in future, we would have policies to decide how to divvy // up the available dedicated prefixes among downstream interfaces. // up the available dedicated prefixes among downstream interfaces. // At this time we have no such mechanism--we only support tethering // At this time we have no such mechanism--we only support tethering Loading services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java +148 −60 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.connectivity.tethering; package com.android.server.connectivity.tethering; import android.net.INetd; import android.net.IpPrefix; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.LinkProperties; Loading @@ -27,13 +28,16 @@ import android.net.ip.RouterAdvertisementDaemon.RaParams; import android.os.INetworkManagementService; import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.RemoteException; import android.util.Log; import android.util.Log; import android.util.Slog; import java.net.Inet6Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.NetworkInterface; import java.net.SocketException; import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.ArrayList; import java.util.HashSet; import java.util.HashSet; import java.util.Objects; /** /** Loading @@ -41,13 +45,15 @@ import java.util.HashSet; */ */ class IPv6TetheringInterfaceServices { class IPv6TetheringInterfaceServices { private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName(); private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName(); private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64"); private static final int RFC7421_IP_PREFIX_LENGTH = 64; private final String mIfName; private final String mIfName; private final INetworkManagementService mNMService; private final INetworkManagementService mNMService; private NetworkInterface mNetworkInterface; private NetworkInterface mNetworkInterface; private byte[] mHwAddr; private byte[] mHwAddr; private ArrayList<RouteInfo> mLastLocalRoutes; private LinkProperties mLastIPv6LinkProperties; private RouterAdvertisementDaemon mRaDaemon; private RouterAdvertisementDaemon mRaDaemon; private RaParams mLastRaParams; private RaParams mLastRaParams; Loading Loading @@ -86,8 +92,7 @@ class IPv6TetheringInterfaceServices { public void stop() { public void stop() { mNetworkInterface = null; mNetworkInterface = null; mHwAddr = null; mHwAddr = null; updateLocalRoutes(null); setRaParams(null); updateRaParams(null); if (mRaDaemon != null) { if (mRaDaemon != null) { mRaDaemon.stop(); mRaDaemon.stop(); Loading @@ -104,95 +109,178 @@ class IPv6TetheringInterfaceServices { public void updateUpstreamIPv6LinkProperties(LinkProperties v6only) { public void updateUpstreamIPv6LinkProperties(LinkProperties v6only) { if (mRaDaemon == null) return; if (mRaDaemon == null) return; if (v6only == null) { // Avoid unnecessary work on spurious updates. updateLocalRoutes(null); if (Objects.equals(mLastIPv6LinkProperties, v6only)) { updateRaParams(null); return; return; } } RaParams params = new RaParams(); RaParams params = null; if (v6only != null) { params = new RaParams(); params.mtu = v6only.getMtu(); params.mtu = v6only.getMtu(); params.hasDefaultRoute = v6only.hasIPv6DefaultRoute(); params.hasDefaultRoute = v6only.hasIPv6DefaultRoute(); ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>(); for (LinkAddress linkAddr : v6only.getLinkAddresses()) { for (LinkAddress linkAddr : v6only.getLinkAddresses()) { final IpPrefix prefix = new IpPrefix(linkAddr.getAddress(), if (linkAddr.getPrefixLength() != RFC7421_IP_PREFIX_LENGTH) continue; linkAddr.getPrefixLength()); // Accumulate routes representing "prefixes to be assigned to the // local interface", for subsequent addition to the local network // in the routing rules. localRoutes.add(new RouteInfo(prefix, null, mIfName)); final IpPrefix prefix = new IpPrefix( linkAddr.getAddress(), linkAddr.getPrefixLength()); params.prefixes.add(prefix); params.prefixes.add(prefix); final Inet6Address dnsServer = getLocalDnsIpFor(prefix); if (dnsServer != null) { params.dnses.add(dnsServer); } } } // If v6only is null, we pass in null to setRaParams(), which handles // deprecation of any existing RA data. setRaParams(params); mLastIPv6LinkProperties = v6only; } } // We need to be able to send unicast RAs, and clients might like to // ping the default router's link-local address, so add that as well. localRoutes.add(new RouteInfo(new IpPrefix("fe80::/64"), null, mIfName)); // TODO: Add a local interface address, update dnsmasq to listen on the private void configureLocalRoutes( // new address, and use only that address as a DNS server. HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) { for (InetAddress dnsServer : v6only.getDnsServers()) { // [1] Remove the routes that are deprecated. if (dnsServer instanceof Inet6Address) { if (!deprecatedPrefixes.isEmpty()) { params.dnses.add((Inet6Address) dnsServer); final ArrayList<RouteInfo> toBeRemoved = getLocalRoutesFor(deprecatedPrefixes); try { final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved); if (removalFailures > 0) { Log.e(TAG, String.format("Failed to remove %d IPv6 routes from local table.", removalFailures)); } } catch (RemoteException e) { Log.e(TAG, "Failed to remove IPv6 routes from local table: ", e); } } } } updateLocalRoutes(localRoutes); // [2] Add only the routes that have not previously been added. updateRaParams(params); if (newPrefixes != null && !newPrefixes.isEmpty()) { HashSet<IpPrefix> addedPrefixes = (HashSet) newPrefixes.clone(); if (mLastRaParams != null) { addedPrefixes.removeAll(mLastRaParams.prefixes); } } private void updateLocalRoutes(ArrayList<RouteInfo> localRoutes) { if (mLastRaParams == null || mLastRaParams.prefixes.isEmpty()) { if (localRoutes != null) { // We need to be able to send unicast RAs, and clients might // TODO: Compare with mLastLocalRoutes and take appropriate // like to ping the default router's link-local address. Note // appropriate action on the difference between the two. // that we never remove the link-local route from the network // until Tethering disables tethering on the interface. addedPrefixes.add(LINK_LOCAL_PREFIX); } if (!localRoutes.isEmpty()) { if (!addedPrefixes.isEmpty()) { final ArrayList<RouteInfo> toBeAdded = getLocalRoutesFor(addedPrefixes); try { try { mNMService.addInterfaceToLocalNetwork(mIfName, localRoutes); // It's safe to call addInterfaceToLocalNetwork() even if // the interface is already in the local_network. mNMService.addInterfaceToLocalNetwork(mIfName, toBeAdded); } catch (RemoteException e) { } catch (RemoteException e) { Log.e(TAG, "Failed to add IPv6 routes to local table: ", e); Log.e(TAG, "Failed to add IPv6 routes to local table: ", e); } } } } } else { } if (mLastLocalRoutes != null && !mLastLocalRoutes.isEmpty()) { } private void configureLocalDns( HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) { INetd netd = getNetdServiceOrNull(); if (netd == null) { if (newDnses != null) newDnses.clear(); Log.e(TAG, "No netd service instance available; not setting local IPv6 addresses"); return; } // [1] Remove deprecated local DNS IP addresses. if (!deprecatedDnses.isEmpty()) { for (Inet6Address dns : deprecatedDnses) { final String dnsString = dns.getHostAddress(); try { try { final int removalFailures = netd.interfaceDelAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH); mNMService.removeRoutesFromLocalNetwork(mLastLocalRoutes); } catch (RemoteException e) { if (removalFailures > 0) { Log.e(TAG, "Failed to remove local dns IP: " + dnsString, e); Log.e(TAG, } String.format("Failed to remove %d IPv6 routes from local table.", } removalFailures)); } // [2] Add only the local DNS IP addresses that have not previously been added. if (newDnses != null && !newDnses.isEmpty()) { final HashSet<Inet6Address> addedDnses = (HashSet) newDnses.clone(); if (mLastRaParams != null) { addedDnses.removeAll(mLastRaParams.dnses); } } for (Inet6Address dns : addedDnses) { final String dnsString = dns.getHostAddress(); try { netd.interfaceAddAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH); } catch (RemoteException e) { } catch (RemoteException e) { Log.e(TAG, "Failed to remove IPv6 routes from local table: ", e); Log.e(TAG, "Failed to add local dns IP: " + dnsString, e); newDnses.remove(dns); } } } } } } mLastLocalRoutes = localRoutes; try { netd.tetherApplyDnsInterfaces(); } catch (RemoteException e) { Log.e(TAG, "Failed to update local DNS caching server"); if (newDnses != null) newDnses.clear(); } } } private void updateRaParams(RaParams params) { private void setRaParams(RaParams newParams) { if (mRaDaemon != null) { if (mRaDaemon != null) { HashSet<IpPrefix> deprecated = null; final RaParams deprecatedParams = RaParams.getDeprecatedRaParams(mLastRaParams, newParams); if (mLastRaParams != null) { configureLocalRoutes(deprecatedParams.prefixes, deprecated = new HashSet<>(); (newParams != null) ? newParams.prefixes : null); configureLocalDns(deprecatedParams.dnses, (newParams != null) ? newParams.dnses : null); for (IpPrefix ipp : mLastRaParams.prefixes) { mRaDaemon.buildNewRa(deprecatedParams, newParams); if (params == null || !params.prefixes.contains(ipp)) { deprecated.add(ipp); } } mLastRaParams = newParams; } // Accumulate routes representing "prefixes to be assigned to the local // interface", for subsequent modification of local_network routing. private ArrayList<RouteInfo> getLocalRoutesFor(HashSet<IpPrefix> prefixes) { final ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>(); for (IpPrefix ipp : prefixes) { localRoutes.add(new RouteInfo(ipp, null, mIfName)); } } return localRoutes; } } // Currently, we send spurious RAs (5) whenever there's any update. private INetd getNetdServiceOrNull() { // TODO: Compare params with mLastParams to avoid spurious updates. if (mNMService != null) { mRaDaemon.buildNewRa(params, deprecated); try { return mNMService.getNetdService(); } catch (RemoteException ignored) { // This blocks until netd can be reached, but it can return // null during a netd crash. } } return null; } } mLastRaParams = params; // Given a prefix like 2001:db8::/64 return 2001:db8::1. private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) { final byte[] dnsBytes = localPrefix.getRawAddress(); dnsBytes[dnsBytes.length - 1] = 0x1; try { return Inet6Address.getByAddress(null, dnsBytes, 0); } catch (UnknownHostException e) { Slog.wtf(TAG, "Failed to construct Inet6Address from: " + localPrefix); return null; } } } } } services/net/java/android/net/ip/RouterAdvertisementDaemon.java +153 −81 File changed.Preview size limit exceeded, changes collapsed. Show changes Loading
services/core/java/com/android/server/connectivity/Tethering.java +10 −0 Original line number Original line Diff line number Diff line Loading @@ -1392,6 +1392,8 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering for (Integer netType : mUpstreamIfaceTypes) { for (Integer netType : mUpstreamIfaceTypes) { NetworkInfo info = cm.getNetworkInfo(netType.intValue()); NetworkInfo info = cm.getNetworkInfo(netType.intValue()); // TODO: if the network is suspended we should consider // that to be the same as connected here. if ((info != null) && info.isConnected()) { if ((info != null) && info.isConnected()) { upType = netType.intValue(); upType = netType.intValue(); break; break; Loading Loading @@ -1465,6 +1467,10 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering // it immediately, because there likely will be no second // it immediately, because there likely will be no second // EVENT_ON_AVAILABLE (it was already received). // EVENT_ON_AVAILABLE (it was already received). handleNewUpstreamNetworkState(ns); handleNewUpstreamNetworkState(ns); } else if (mCurrentUpstreamIface == null) { // There are no available upstream networks, or none that // have an IPv4 default route (current metric for success). handleNewUpstreamNetworkState(null); } } } } Loading Loading @@ -1639,6 +1645,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering chooseUpstreamType(mTryCell); chooseUpstreamType(mTryCell); mTryCell = !mTryCell; mTryCell = !mTryCell; } } @Override @Override public void exit() { public void exit() { // TODO: examine if we should check the return value. // TODO: examine if we should check the return value. Loading @@ -1646,7 +1653,9 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering mUpstreamNetworkMonitor.stop(); mUpstreamNetworkMonitor.stop(); stopListeningForSimChanges(); stopListeningForSimChanges(); notifyTetheredOfNewUpstreamIface(null); notifyTetheredOfNewUpstreamIface(null); handleNewUpstreamNetworkState(null); } } @Override @Override public boolean processMessage(Message message) { public boolean processMessage(Message message) { maybeLogMessage(this, message.what); maybeLogMessage(this, message.what); Loading Loading @@ -1734,6 +1743,7 @@ public class Tethering extends BaseNetworkObserver implements IControlsTethering // reevaluation is triggered via received CONNECTIVITY_ACTION // reevaluation is triggered via received CONNECTIVITY_ACTION // broadcasts that result in being passed a // broadcasts that result in being passed a // TetherMasterSM.CMD_UPSTREAM_CHANGED. // TetherMasterSM.CMD_UPSTREAM_CHANGED. handleNewUpstreamNetworkState(null); break; break; default: default: break; break; Loading
services/core/java/com/android/server/connectivity/tethering/IPv6TetheringCoordinator.java +9 −9 Original line number Original line Diff line number Diff line Loading @@ -55,7 +55,7 @@ public class IPv6TetheringCoordinator { if (VDBG) { if (VDBG) { Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns)); Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns)); } } if (ns == null || ns.network == null) { if (!canTetherIPv6(ns)) { stopIPv6TetheringOnAllInterfaces(); stopIPv6TetheringOnAllInterfaces(); setUpstreamNetworkState(null); setUpstreamNetworkState(null); return; return; Loading @@ -65,8 +65,9 @@ public class IPv6TetheringCoordinator { !ns.network.equals(mUpstreamNetworkState.network)) { !ns.network.equals(mUpstreamNetworkState.network)) { stopIPv6TetheringOnAllInterfaces(); stopIPv6TetheringOnAllInterfaces(); } } setUpstreamNetworkState(ns); setUpstreamNetworkState(ns); maybeUpdateIPv6TetheringInterfaces(); updateIPv6TetheringInterfaces(); } } private void stopIPv6TetheringOnAllInterfaces() { private void stopIPv6TetheringOnAllInterfaces() { Loading @@ -77,9 +78,10 @@ public class IPv6TetheringCoordinator { } } private void setUpstreamNetworkState(NetworkState ns) { private void setUpstreamNetworkState(NetworkState ns) { if (!canTetherIPv6(ns)) { if (ns == null) { mUpstreamNetworkState = null; mUpstreamNetworkState = null; } else { } else { // Make a deep copy of the parts we need. mUpstreamNetworkState = new NetworkState( mUpstreamNetworkState = new NetworkState( null, null, new LinkProperties(ns.linkProperties), new LinkProperties(ns.linkProperties), Loading @@ -94,19 +96,17 @@ public class IPv6TetheringCoordinator { } } } } private void maybeUpdateIPv6TetheringInterfaces() { private void updateIPv6TetheringInterfaces() { if (mUpstreamNetworkState == null) return; for (TetherInterfaceStateMachine sm : mNotifyList) { for (TetherInterfaceStateMachine sm : mNotifyList) { final LinkProperties lp = getInterfaceIPv6LinkProperties(sm.interfaceType()); final LinkProperties lp = getInterfaceIPv6LinkProperties(sm.interfaceType()); if (lp != null) { sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp); sm.sendMessage(TetherInterfaceStateMachine.CMD_IPV6_TETHER_UPDATE, 0, 0, lp); } break; break; } } } } private LinkProperties getInterfaceIPv6LinkProperties(int interfaceType) { private LinkProperties getInterfaceIPv6LinkProperties(int interfaceType) { if (mUpstreamNetworkState == null) return null; // NOTE: Here, in future, we would have policies to decide how to divvy // NOTE: Here, in future, we would have policies to decide how to divvy // up the available dedicated prefixes among downstream interfaces. // up the available dedicated prefixes among downstream interfaces. // At this time we have no such mechanism--we only support tethering // At this time we have no such mechanism--we only support tethering Loading
services/core/java/com/android/server/connectivity/tethering/IPv6TetheringInterfaceServices.java +148 −60 Original line number Original line Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.connectivity.tethering; package com.android.server.connectivity.tethering; import android.net.INetd; import android.net.IpPrefix; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.LinkProperties; Loading @@ -27,13 +28,16 @@ import android.net.ip.RouterAdvertisementDaemon.RaParams; import android.os.INetworkManagementService; import android.os.INetworkManagementService; import android.os.RemoteException; import android.os.RemoteException; import android.util.Log; import android.util.Log; import android.util.Slog; import java.net.Inet6Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.NetworkInterface; import java.net.SocketException; import java.net.SocketException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.ArrayList; import java.util.HashSet; import java.util.HashSet; import java.util.Objects; /** /** Loading @@ -41,13 +45,15 @@ import java.util.HashSet; */ */ class IPv6TetheringInterfaceServices { class IPv6TetheringInterfaceServices { private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName(); private static final String TAG = IPv6TetheringInterfaceServices.class.getSimpleName(); private static final IpPrefix LINK_LOCAL_PREFIX = new IpPrefix("fe80::/64"); private static final int RFC7421_IP_PREFIX_LENGTH = 64; private final String mIfName; private final String mIfName; private final INetworkManagementService mNMService; private final INetworkManagementService mNMService; private NetworkInterface mNetworkInterface; private NetworkInterface mNetworkInterface; private byte[] mHwAddr; private byte[] mHwAddr; private ArrayList<RouteInfo> mLastLocalRoutes; private LinkProperties mLastIPv6LinkProperties; private RouterAdvertisementDaemon mRaDaemon; private RouterAdvertisementDaemon mRaDaemon; private RaParams mLastRaParams; private RaParams mLastRaParams; Loading Loading @@ -86,8 +92,7 @@ class IPv6TetheringInterfaceServices { public void stop() { public void stop() { mNetworkInterface = null; mNetworkInterface = null; mHwAddr = null; mHwAddr = null; updateLocalRoutes(null); setRaParams(null); updateRaParams(null); if (mRaDaemon != null) { if (mRaDaemon != null) { mRaDaemon.stop(); mRaDaemon.stop(); Loading @@ -104,95 +109,178 @@ class IPv6TetheringInterfaceServices { public void updateUpstreamIPv6LinkProperties(LinkProperties v6only) { public void updateUpstreamIPv6LinkProperties(LinkProperties v6only) { if (mRaDaemon == null) return; if (mRaDaemon == null) return; if (v6only == null) { // Avoid unnecessary work on spurious updates. updateLocalRoutes(null); if (Objects.equals(mLastIPv6LinkProperties, v6only)) { updateRaParams(null); return; return; } } RaParams params = new RaParams(); RaParams params = null; if (v6only != null) { params = new RaParams(); params.mtu = v6only.getMtu(); params.mtu = v6only.getMtu(); params.hasDefaultRoute = v6only.hasIPv6DefaultRoute(); params.hasDefaultRoute = v6only.hasIPv6DefaultRoute(); ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>(); for (LinkAddress linkAddr : v6only.getLinkAddresses()) { for (LinkAddress linkAddr : v6only.getLinkAddresses()) { final IpPrefix prefix = new IpPrefix(linkAddr.getAddress(), if (linkAddr.getPrefixLength() != RFC7421_IP_PREFIX_LENGTH) continue; linkAddr.getPrefixLength()); // Accumulate routes representing "prefixes to be assigned to the // local interface", for subsequent addition to the local network // in the routing rules. localRoutes.add(new RouteInfo(prefix, null, mIfName)); final IpPrefix prefix = new IpPrefix( linkAddr.getAddress(), linkAddr.getPrefixLength()); params.prefixes.add(prefix); params.prefixes.add(prefix); final Inet6Address dnsServer = getLocalDnsIpFor(prefix); if (dnsServer != null) { params.dnses.add(dnsServer); } } } // If v6only is null, we pass in null to setRaParams(), which handles // deprecation of any existing RA data. setRaParams(params); mLastIPv6LinkProperties = v6only; } } // We need to be able to send unicast RAs, and clients might like to // ping the default router's link-local address, so add that as well. localRoutes.add(new RouteInfo(new IpPrefix("fe80::/64"), null, mIfName)); // TODO: Add a local interface address, update dnsmasq to listen on the private void configureLocalRoutes( // new address, and use only that address as a DNS server. HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) { for (InetAddress dnsServer : v6only.getDnsServers()) { // [1] Remove the routes that are deprecated. if (dnsServer instanceof Inet6Address) { if (!deprecatedPrefixes.isEmpty()) { params.dnses.add((Inet6Address) dnsServer); final ArrayList<RouteInfo> toBeRemoved = getLocalRoutesFor(deprecatedPrefixes); try { final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved); if (removalFailures > 0) { Log.e(TAG, String.format("Failed to remove %d IPv6 routes from local table.", removalFailures)); } } catch (RemoteException e) { Log.e(TAG, "Failed to remove IPv6 routes from local table: ", e); } } } } updateLocalRoutes(localRoutes); // [2] Add only the routes that have not previously been added. updateRaParams(params); if (newPrefixes != null && !newPrefixes.isEmpty()) { HashSet<IpPrefix> addedPrefixes = (HashSet) newPrefixes.clone(); if (mLastRaParams != null) { addedPrefixes.removeAll(mLastRaParams.prefixes); } } private void updateLocalRoutes(ArrayList<RouteInfo> localRoutes) { if (mLastRaParams == null || mLastRaParams.prefixes.isEmpty()) { if (localRoutes != null) { // We need to be able to send unicast RAs, and clients might // TODO: Compare with mLastLocalRoutes and take appropriate // like to ping the default router's link-local address. Note // appropriate action on the difference between the two. // that we never remove the link-local route from the network // until Tethering disables tethering on the interface. addedPrefixes.add(LINK_LOCAL_PREFIX); } if (!localRoutes.isEmpty()) { if (!addedPrefixes.isEmpty()) { final ArrayList<RouteInfo> toBeAdded = getLocalRoutesFor(addedPrefixes); try { try { mNMService.addInterfaceToLocalNetwork(mIfName, localRoutes); // It's safe to call addInterfaceToLocalNetwork() even if // the interface is already in the local_network. mNMService.addInterfaceToLocalNetwork(mIfName, toBeAdded); } catch (RemoteException e) { } catch (RemoteException e) { Log.e(TAG, "Failed to add IPv6 routes to local table: ", e); Log.e(TAG, "Failed to add IPv6 routes to local table: ", e); } } } } } else { } if (mLastLocalRoutes != null && !mLastLocalRoutes.isEmpty()) { } private void configureLocalDns( HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) { INetd netd = getNetdServiceOrNull(); if (netd == null) { if (newDnses != null) newDnses.clear(); Log.e(TAG, "No netd service instance available; not setting local IPv6 addresses"); return; } // [1] Remove deprecated local DNS IP addresses. if (!deprecatedDnses.isEmpty()) { for (Inet6Address dns : deprecatedDnses) { final String dnsString = dns.getHostAddress(); try { try { final int removalFailures = netd.interfaceDelAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH); mNMService.removeRoutesFromLocalNetwork(mLastLocalRoutes); } catch (RemoteException e) { if (removalFailures > 0) { Log.e(TAG, "Failed to remove local dns IP: " + dnsString, e); Log.e(TAG, } String.format("Failed to remove %d IPv6 routes from local table.", } removalFailures)); } // [2] Add only the local DNS IP addresses that have not previously been added. if (newDnses != null && !newDnses.isEmpty()) { final HashSet<Inet6Address> addedDnses = (HashSet) newDnses.clone(); if (mLastRaParams != null) { addedDnses.removeAll(mLastRaParams.dnses); } } for (Inet6Address dns : addedDnses) { final String dnsString = dns.getHostAddress(); try { netd.interfaceAddAddress(mIfName, dnsString, RFC7421_IP_PREFIX_LENGTH); } catch (RemoteException e) { } catch (RemoteException e) { Log.e(TAG, "Failed to remove IPv6 routes from local table: ", e); Log.e(TAG, "Failed to add local dns IP: " + dnsString, e); newDnses.remove(dns); } } } } } } mLastLocalRoutes = localRoutes; try { netd.tetherApplyDnsInterfaces(); } catch (RemoteException e) { Log.e(TAG, "Failed to update local DNS caching server"); if (newDnses != null) newDnses.clear(); } } } private void updateRaParams(RaParams params) { private void setRaParams(RaParams newParams) { if (mRaDaemon != null) { if (mRaDaemon != null) { HashSet<IpPrefix> deprecated = null; final RaParams deprecatedParams = RaParams.getDeprecatedRaParams(mLastRaParams, newParams); if (mLastRaParams != null) { configureLocalRoutes(deprecatedParams.prefixes, deprecated = new HashSet<>(); (newParams != null) ? newParams.prefixes : null); configureLocalDns(deprecatedParams.dnses, (newParams != null) ? newParams.dnses : null); for (IpPrefix ipp : mLastRaParams.prefixes) { mRaDaemon.buildNewRa(deprecatedParams, newParams); if (params == null || !params.prefixes.contains(ipp)) { deprecated.add(ipp); } } mLastRaParams = newParams; } // Accumulate routes representing "prefixes to be assigned to the local // interface", for subsequent modification of local_network routing. private ArrayList<RouteInfo> getLocalRoutesFor(HashSet<IpPrefix> prefixes) { final ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>(); for (IpPrefix ipp : prefixes) { localRoutes.add(new RouteInfo(ipp, null, mIfName)); } } return localRoutes; } } // Currently, we send spurious RAs (5) whenever there's any update. private INetd getNetdServiceOrNull() { // TODO: Compare params with mLastParams to avoid spurious updates. if (mNMService != null) { mRaDaemon.buildNewRa(params, deprecated); try { return mNMService.getNetdService(); } catch (RemoteException ignored) { // This blocks until netd can be reached, but it can return // null during a netd crash. } } return null; } } mLastRaParams = params; // Given a prefix like 2001:db8::/64 return 2001:db8::1. private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) { final byte[] dnsBytes = localPrefix.getRawAddress(); dnsBytes[dnsBytes.length - 1] = 0x1; try { return Inet6Address.getByAddress(null, dnsBytes, 0); } catch (UnknownHostException e) { Slog.wtf(TAG, "Failed to construct Inet6Address from: " + localPrefix); return null; } } } } }
services/net/java/android/net/ip/RouterAdvertisementDaemon.java +153 −81 File changed.Preview size limit exceeded, changes collapsed. Show changes