Loading services/core/java/com/android/server/connectivity/Tethering.java +46 −24 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,7 @@ import android.net.NetworkRequest; import android.net.NetworkState; import android.net.NetworkState; import android.net.NetworkUtils; import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.RouteInfo; import android.net.util.PrefixUtils; import android.net.util.SharedLog; import android.net.util.SharedLog; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Binder; Loading Loading @@ -219,7 +220,7 @@ public class Tethering extends BaseNetworkObserver { mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mForwardedDownstreams = new HashSet<>(); mForwardedDownstreams = new HashSet<>(); mSimChange = new SimChangeListener( mSimChange = new SimChangeListener( mContext, mTetherMasterSM.getHandler(), () -> reevaluateSimCardProvisioning()); mContext, smHandler, () -> reevaluateSimCardProvisioning()); mStateReceiver = new StateReceiver(); mStateReceiver = new StateReceiver(); IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter(); Loading @@ -227,13 +228,13 @@ public class Tethering extends BaseNetworkObserver { filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler()); mContext.registerReceiver(mStateReceiver, filter, null, smHandler); filter = new IntentFilter(); filter = new IntentFilter(); filter.addAction(Intent.ACTION_MEDIA_SHARED); filter.addAction(Intent.ACTION_MEDIA_SHARED); filter.addAction(Intent.ACTION_MEDIA_UNSHARED); filter.addAction(Intent.ACTION_MEDIA_UNSHARED); filter.addDataScheme("file"); filter.addDataScheme("file"); mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler()); mContext.registerReceiver(mStateReceiver, filter, null, smHandler); // load device config info // load device config info updateConfiguration(); updateConfiguration(); Loading Loading @@ -1142,12 +1143,6 @@ public class Tethering extends BaseNetworkObserver { } } } } private void startOffloadController() { mOffloadController.start(); mOffloadController.updateExemptPrefixes( mUpstreamNetworkMonitor.getOffloadExemptPrefixes()); } class TetherMasterSM extends StateMachine { class TetherMasterSM extends StateMachine { private static final int BASE_MASTER = Protocol.BASE_TETHERING; private static final int BASE_MASTER = Protocol.BASE_TETHERING; // an interface SM has requested Tethering/Local Hotspot // an interface SM has requested Tethering/Local Hotspot Loading @@ -1165,14 +1160,14 @@ public class Tethering extends BaseNetworkObserver { static final int CMD_CLEAR_ERROR = BASE_MASTER + 6; static final int CMD_CLEAR_ERROR = BASE_MASTER + 6; static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7; static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7; private State mInitialState; private final State mInitialState; private State mTetherModeAliveState; private final State mTetherModeAliveState; private State mSetIpForwardingEnabledErrorState; private final State mSetIpForwardingEnabledErrorState; private State mSetIpForwardingDisabledErrorState; private final State mSetIpForwardingDisabledErrorState; private State mStartTetheringErrorState; private final State mStartTetheringErrorState; private State mStopTetheringErrorState; private final State mStopTetheringErrorState; private State mSetDnsForwardersErrorState; private final State mSetDnsForwardersErrorState; // This list is a little subtle. It contains all the interfaces that currently are // This list is a little subtle. It contains all the interfaces that currently are // requesting tethering, regardless of whether these interfaces are still members of // requesting tethering, regardless of whether these interfaces are still members of Loading Loading @@ -1212,9 +1207,33 @@ public class Tethering extends BaseNetworkObserver { mNotifyList = new ArrayList<>(); mNotifyList = new ArrayList<>(); mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog); mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog); setInitialState(mInitialState); setInitialState(mInitialState); } } private void startOffloadController() { mOffloadController.start(); sendOffloadExemptPrefixes(); } private void sendOffloadExemptPrefixes() { sendOffloadExemptPrefixes(mUpstreamNetworkMonitor.getLocalPrefixes()); } private void sendOffloadExemptPrefixes(Set<IpPrefix> localPrefixes) { // Add in well-known minimum set. PrefixUtils.addNonForwardablePrefixes(localPrefixes); // Add tragically hardcoded prefixes. localPrefixes.add(PrefixUtils.DEFAULT_WIFI_P2P_PREFIX); // Add prefixes for all downstreams, regardless of IP serving mode. for (TetherInterfaceStateMachine tism : mNotifyList) { localPrefixes.addAll(PrefixUtils.localPrefixesFrom(tism.linkProperties())); } mOffloadController.setLocalPrefixes(localPrefixes); } class InitialState extends State { class InitialState extends State { @Override @Override public boolean processMessage(Message message) { public boolean processMessage(Message message) { Loading Loading @@ -1422,8 +1441,8 @@ public class Tethering extends BaseNetworkObserver { } } private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) { private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) { if (arg1 == UpstreamNetworkMonitor.NOTIFY_EXEMPT_PREFIXES) { if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) { mOffloadController.updateExemptPrefixes((Set<IpPrefix>) o); sendOffloadExemptPrefixes((Set<IpPrefix>) o); return; return; } } Loading Loading @@ -1573,6 +1592,9 @@ public class Tethering extends BaseNetworkObserver { mOffloadController.notifyDownstreamLinkProperties(newLp); mOffloadController.notifyDownstreamLinkProperties(newLp); } else { } else { mOffloadController.removeDownstreamInterface(newLp.getInterfaceName()); mOffloadController.removeDownstreamInterface(newLp.getInterfaceName()); // Another interface might be in local-only hotspot mode; // resend all local prefixes to the OffloadController. sendOffloadExemptPrefixes(); } } break; break; } } Loading services/core/java/com/android/server/connectivity/tethering/OffloadController.java +55 −8 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; import android.content.ContentResolver; import android.content.ContentResolver; import android.net.IpPrefix; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.LinkProperties; import android.net.RouteInfo; import android.net.RouteInfo; import android.net.util.SharedLog; import android.net.util.SharedLog; Loading @@ -27,8 +28,11 @@ import android.os.Handler; import android.provider.Settings; import android.provider.Settings; import java.net.Inet4Address; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetAddress; import java.util.ArrayList; import java.util.ArrayList; import java.util.HashSet; import java.util.Objects; import java.util.Set; import java.util.Set; /** /** Loading @@ -47,7 +51,13 @@ public class OffloadController { private boolean mConfigInitialized; private boolean mConfigInitialized; private boolean mControlInitialized; private boolean mControlInitialized; private LinkProperties mUpstreamLinkProperties; private LinkProperties mUpstreamLinkProperties; // The complete set of offload-exempt prefixes passed in via Tethering from // all upstream and downstream sources. private Set<IpPrefix> mExemptPrefixes; private Set<IpPrefix> mExemptPrefixes; // A strictly "smaller" set of prefixes, wherein offload-approved prefixes // (e.g. downstream on-link prefixes) have been removed and replaced with // prefixes representing only the locally-assigned IP addresses. private Set<String> mLastLocalPrefixStrs; public OffloadController(Handler h, OffloadHardwareInterface hwi, public OffloadController(Handler h, OffloadHardwareInterface hwi, ContentResolver contentResolver, SharedLog log) { ContentResolver contentResolver, SharedLog log) { Loading @@ -55,6 +65,8 @@ public class OffloadController { mHwInterface = hwi; mHwInterface = hwi; mContentResolver = contentResolver; mContentResolver = contentResolver; mLog = log.forSubComponent(TAG); mLog = log.forSubComponent(TAG); mExemptPrefixes = new HashSet<>(); mLastLocalPrefixStrs = new HashSet<>(); } } public void start() { public void start() { Loading Loading @@ -134,25 +146,22 @@ public class OffloadController { } } public void setUpstreamLinkProperties(LinkProperties lp) { public void setUpstreamLinkProperties(LinkProperties lp) { if (!started()) return; if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return; mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null; mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null; // TODO: examine return code and decide what to do if programming // TODO: examine return code and decide what to do if programming // upstream parameters fails (probably just wait for a subsequent // upstream parameters fails (probably just wait for a subsequent // onOffloadEvent() callback to tell us offload is available again and // onOffloadEvent() callback to tell us offload is available again and // then reapply all state). // then reapply all state). computeAndPushLocalPrefixes(); pushUpstreamParameters(); pushUpstreamParameters(); } } public void updateExemptPrefixes(Set<IpPrefix> exemptPrefixes) { public void setLocalPrefixes(Set<IpPrefix> localPrefixes) { if (!started()) return; if (!started()) return; mExemptPrefixes = exemptPrefixes; mExemptPrefixes = localPrefixes; // TODO: computeAndPushLocalPrefixes(); // - add IP addresses from all downstream link properties // - add routes from all non-tethering downstream link properties // - remove any 64share prefixes // - push this to the HAL } } public void notifyDownstreamLinkProperties(LinkProperties lp) { public void notifyDownstreamLinkProperties(LinkProperties lp) { Loading Loading @@ -215,4 +224,42 @@ public class OffloadController { return mHwInterface.setUpstreamParameters( return mHwInterface.setUpstreamParameters( iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways)); iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways)); } } private boolean computeAndPushLocalPrefixes() { final Set<String> localPrefixStrs = computeLocalPrefixStrings( mExemptPrefixes, mUpstreamLinkProperties); if (mLastLocalPrefixStrs.equals(localPrefixStrs)) return true; mLastLocalPrefixStrs = localPrefixStrs; return mHwInterface.setLocalPrefixes(new ArrayList<>(localPrefixStrs)); } // TODO: Factor in downstream LinkProperties once that information is available. private static Set<String> computeLocalPrefixStrings( Set<IpPrefix> localPrefixes, LinkProperties upstreamLinkProperties) { // Create an editable copy. final Set<IpPrefix> prefixSet = new HashSet<>(localPrefixes); // TODO: If a downstream interface (not currently passed in) is reusing // the /64 of the upstream (64share) then: // // [a] remove that /64 from the local prefixes // [b] add in /128s for IP addresses on the downstream interface // [c] add in /128s for IP addresses on the upstream interface // // Until downstream information is available here, simply add /128s from // the upstream network; they'll just be redundant with their /64. if (upstreamLinkProperties != null) { for (LinkAddress linkAddr : upstreamLinkProperties.getLinkAddresses()) { if (!linkAddr.isGlobalPreferred()) continue; final InetAddress ip = linkAddr.getAddress(); if (!(ip instanceof Inet6Address)) continue; prefixSet.add(new IpPrefix(ip, 128)); } } final HashSet<String> localPrefixStrs = new HashSet<>(); for (IpPrefix pfx : prefixSet) localPrefixStrs.add(pfx.toString()); return localPrefixStrs; } } } services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java +20 −0 Original line number Original line Diff line number Diff line Loading @@ -168,6 +168,26 @@ public class OffloadHardwareInterface { return stats; return stats; } } public boolean setLocalPrefixes(ArrayList<String> localPrefixes) { final String logmsg = String.format("setLocalPrefixes([%s])", String.join(",", localPrefixes)); final CbResults results = new CbResults(); try { mOffloadControl.setLocalPrefixes(localPrefixes, (boolean success, String errMsg) -> { results.success = success; results.errMsg = errMsg; }); } catch (RemoteException e) { record(logmsg, e); return false; } record(logmsg, results); return results.success; } public boolean setUpstreamParameters( public boolean setUpstreamParameters( String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) { String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) { iface = (iface != null) ? iface : NO_INTERFACE_NAME; iface = (iface != null) ? iface : NO_INTERFACE_NAME; Loading services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +2 −0 Original line number Original line Diff line number Diff line Loading @@ -161,6 +161,8 @@ public class TetherInterfaceStateMachine extends StateMachine { public int lastError() { return mLastError; } public int lastError() { return mLastError; } public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); } public void stop() { sendMessage(CMD_INTERFACE_DOWN); } public void stop() { sendMessage(CMD_INTERFACE_DOWN); } public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); } public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); } Loading services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +17 −41 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.NetworkRequest; import android.net.NetworkState; import android.net.NetworkState; import android.net.util.NetworkConstants; import android.net.util.NetworkConstants; import android.net.util.PrefixUtils; import android.net.util.SharedLog; import android.net.util.SharedLog; import android.util.Log; import android.util.Log; Loading Loading @@ -72,16 +73,11 @@ public class UpstreamNetworkMonitor { private static final boolean DBG = false; private static final boolean DBG = false; private static final boolean VDBG = false; private static final boolean VDBG = false; private static final IpPrefix[] MINIMUM_LOCAL_PREFIXES_SET = { prefix("127.0.0.0/8"), prefix("169.254.0.0/16"), prefix("::/3"), prefix("fe80::/64"), prefix("fc00::/7"), prefix("ff00::/8"), }; public static final int EVENT_ON_AVAILABLE = 1; public static final int EVENT_ON_AVAILABLE = 1; public static final int EVENT_ON_CAPABILITIES = 2; public static final int EVENT_ON_CAPABILITIES = 2; public static final int EVENT_ON_LINKPROPERTIES = 3; public static final int EVENT_ON_LINKPROPERTIES = 3; public static final int EVENT_ON_LOST = 4; public static final int EVENT_ON_LOST = 4; public static final int NOTIFY_EXEMPT_PREFIXES = 10; public static final int NOTIFY_LOCAL_PREFIXES = 10; private static final int CALLBACK_LISTEN_ALL = 1; private static final int CALLBACK_LISTEN_ALL = 1; private static final int CALLBACK_TRACK_DEFAULT = 2; private static final int CALLBACK_TRACK_DEFAULT = 2; Loading @@ -93,7 +89,7 @@ public class UpstreamNetworkMonitor { private final Handler mHandler; private final Handler mHandler; private final int mWhat; private final int mWhat; private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>(); private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>(); private HashSet<IpPrefix> mOffloadExemptPrefixes; private HashSet<IpPrefix> mLocalPrefixes; private ConnectivityManager mCM; private ConnectivityManager mCM; private NetworkCallback mListenAllCallback; private NetworkCallback mListenAllCallback; private NetworkCallback mDefaultNetworkCallback; private NetworkCallback mDefaultNetworkCallback; Loading @@ -107,7 +103,7 @@ public class UpstreamNetworkMonitor { mHandler = mTarget.getHandler(); mHandler = mTarget.getHandler(); mLog = log.forSubComponent(TAG); mLog = log.forSubComponent(TAG); mWhat = what; mWhat = what; mOffloadExemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values()); mLocalPrefixes = new HashSet<>(); } } @VisibleForTesting @VisibleForTesting Loading Loading @@ -223,8 +219,8 @@ public class UpstreamNetworkMonitor { return typeStatePair.ns; return typeStatePair.ns; } } public Set<IpPrefix> getOffloadExemptPrefixes() { public Set<IpPrefix> getLocalPrefixes() { return (Set<IpPrefix>) mOffloadExemptPrefixes.clone(); return (Set<IpPrefix>) mLocalPrefixes.clone(); } } private void handleAvailable(int callbackType, Network network) { private void handleAvailable(int callbackType, Network network) { Loading Loading @@ -360,11 +356,11 @@ public class UpstreamNetworkMonitor { notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network)); notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network)); } } private void recomputeOffloadExemptPrefixes() { private void recomputeLocalPrefixes() { final HashSet<IpPrefix> exemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values()); final HashSet<IpPrefix> localPrefixes = allLocalPrefixes(mNetworkMap.values()); if (!mOffloadExemptPrefixes.equals(exemptPrefixes)) { if (!mLocalPrefixes.equals(localPrefixes)) { mOffloadExemptPrefixes = exemptPrefixes; mLocalPrefixes = localPrefixes; notifyTarget(NOTIFY_EXEMPT_PREFIXES, exemptPrefixes.clone()); notifyTarget(NOTIFY_LOCAL_PREFIXES, localPrefixes.clone()); } } } } Loading Loading @@ -402,7 +398,7 @@ public class UpstreamNetworkMonitor { @Override @Override public void onLinkPropertiesChanged(Network network, LinkProperties newLp) { public void onLinkPropertiesChanged(Network network, LinkProperties newLp) { handleLinkProp(network, newLp); handleLinkProp(network, newLp); recomputeOffloadExemptPrefixes(); recomputeLocalPrefixes(); } } // TODO: Handle onNetworkSuspended(); // TODO: Handle onNetworkSuspended(); Loading @@ -411,7 +407,7 @@ public class UpstreamNetworkMonitor { @Override @Override public void onLost(Network network) { public void onLost(Network network) { handleLost(mCallbackType, network); handleLost(mCallbackType, network); recomputeOffloadExemptPrefixes(); recomputeLocalPrefixes(); } } } } Loading Loading @@ -460,35 +456,15 @@ public class UpstreamNetworkMonitor { return result; return result; } } private static HashSet<IpPrefix> allOffloadExemptPrefixes(Iterable<NetworkState> netStates) { private static HashSet<IpPrefix> allLocalPrefixes(Iterable<NetworkState> netStates) { final HashSet<IpPrefix> prefixSet = new HashSet<>(); final HashSet<IpPrefix> prefixSet = new HashSet<>(); addDefaultLocalPrefixes(prefixSet); for (NetworkState ns : netStates) { for (NetworkState ns : netStates) { addOffloadExemptPrefixes(prefixSet, ns.linkProperties); final LinkProperties lp = ns.linkProperties; if (lp == null) continue; prefixSet.addAll(PrefixUtils.localPrefixesFrom(lp)); } } return prefixSet; return prefixSet; } } private static void addDefaultLocalPrefixes(Set<IpPrefix> prefixSet) { Collections.addAll(prefixSet, MINIMUM_LOCAL_PREFIXES_SET); } private static void addOffloadExemptPrefixes(Set<IpPrefix> prefixSet, LinkProperties lp) { if (lp == null) return; for (LinkAddress linkAddr : lp.getAllLinkAddresses()) { prefixSet.add(new IpPrefix(linkAddr.getAddress(), linkAddr.getPrefixLength())); } // TODO: Consider adding other non-default routes associated with this // network. Traffic to these destinations should perhaps not go through // the Internet (upstream). } private static IpPrefix prefix(String prefixStr) { return new IpPrefix(prefixStr); } } } Loading
services/core/java/com/android/server/connectivity/Tethering.java +46 −24 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,7 @@ import android.net.NetworkRequest; import android.net.NetworkState; import android.net.NetworkState; import android.net.NetworkUtils; import android.net.NetworkUtils; import android.net.RouteInfo; import android.net.RouteInfo; import android.net.util.PrefixUtils; import android.net.util.SharedLog; import android.net.util.SharedLog; import android.net.wifi.WifiManager; import android.net.wifi.WifiManager; import android.os.Binder; import android.os.Binder; Loading Loading @@ -219,7 +220,7 @@ public class Tethering extends BaseNetworkObserver { mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mForwardedDownstreams = new HashSet<>(); mForwardedDownstreams = new HashSet<>(); mSimChange = new SimChangeListener( mSimChange = new SimChangeListener( mContext, mTetherMasterSM.getHandler(), () -> reevaluateSimCardProvisioning()); mContext, smHandler, () -> reevaluateSimCardProvisioning()); mStateReceiver = new StateReceiver(); mStateReceiver = new StateReceiver(); IntentFilter filter = new IntentFilter(); IntentFilter filter = new IntentFilter(); Loading @@ -227,13 +228,13 @@ public class Tethering extends BaseNetworkObserver { filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION); filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED); mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler()); mContext.registerReceiver(mStateReceiver, filter, null, smHandler); filter = new IntentFilter(); filter = new IntentFilter(); filter.addAction(Intent.ACTION_MEDIA_SHARED); filter.addAction(Intent.ACTION_MEDIA_SHARED); filter.addAction(Intent.ACTION_MEDIA_UNSHARED); filter.addAction(Intent.ACTION_MEDIA_UNSHARED); filter.addDataScheme("file"); filter.addDataScheme("file"); mContext.registerReceiver(mStateReceiver, filter, null, mTetherMasterSM.getHandler()); mContext.registerReceiver(mStateReceiver, filter, null, smHandler); // load device config info // load device config info updateConfiguration(); updateConfiguration(); Loading Loading @@ -1142,12 +1143,6 @@ public class Tethering extends BaseNetworkObserver { } } } } private void startOffloadController() { mOffloadController.start(); mOffloadController.updateExemptPrefixes( mUpstreamNetworkMonitor.getOffloadExemptPrefixes()); } class TetherMasterSM extends StateMachine { class TetherMasterSM extends StateMachine { private static final int BASE_MASTER = Protocol.BASE_TETHERING; private static final int BASE_MASTER = Protocol.BASE_TETHERING; // an interface SM has requested Tethering/Local Hotspot // an interface SM has requested Tethering/Local Hotspot Loading @@ -1165,14 +1160,14 @@ public class Tethering extends BaseNetworkObserver { static final int CMD_CLEAR_ERROR = BASE_MASTER + 6; static final int CMD_CLEAR_ERROR = BASE_MASTER + 6; static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7; static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MASTER + 7; private State mInitialState; private final State mInitialState; private State mTetherModeAliveState; private final State mTetherModeAliveState; private State mSetIpForwardingEnabledErrorState; private final State mSetIpForwardingEnabledErrorState; private State mSetIpForwardingDisabledErrorState; private final State mSetIpForwardingDisabledErrorState; private State mStartTetheringErrorState; private final State mStartTetheringErrorState; private State mStopTetheringErrorState; private final State mStopTetheringErrorState; private State mSetDnsForwardersErrorState; private final State mSetDnsForwardersErrorState; // This list is a little subtle. It contains all the interfaces that currently are // This list is a little subtle. It contains all the interfaces that currently are // requesting tethering, regardless of whether these interfaces are still members of // requesting tethering, regardless of whether these interfaces are still members of Loading Loading @@ -1212,9 +1207,33 @@ public class Tethering extends BaseNetworkObserver { mNotifyList = new ArrayList<>(); mNotifyList = new ArrayList<>(); mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog); mIPv6TetheringCoordinator = new IPv6TetheringCoordinator(mNotifyList, mLog); setInitialState(mInitialState); setInitialState(mInitialState); } } private void startOffloadController() { mOffloadController.start(); sendOffloadExemptPrefixes(); } private void sendOffloadExemptPrefixes() { sendOffloadExemptPrefixes(mUpstreamNetworkMonitor.getLocalPrefixes()); } private void sendOffloadExemptPrefixes(Set<IpPrefix> localPrefixes) { // Add in well-known minimum set. PrefixUtils.addNonForwardablePrefixes(localPrefixes); // Add tragically hardcoded prefixes. localPrefixes.add(PrefixUtils.DEFAULT_WIFI_P2P_PREFIX); // Add prefixes for all downstreams, regardless of IP serving mode. for (TetherInterfaceStateMachine tism : mNotifyList) { localPrefixes.addAll(PrefixUtils.localPrefixesFrom(tism.linkProperties())); } mOffloadController.setLocalPrefixes(localPrefixes); } class InitialState extends State { class InitialState extends State { @Override @Override public boolean processMessage(Message message) { public boolean processMessage(Message message) { Loading Loading @@ -1422,8 +1441,8 @@ public class Tethering extends BaseNetworkObserver { } } private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) { private void handleUpstreamNetworkMonitorCallback(int arg1, Object o) { if (arg1 == UpstreamNetworkMonitor.NOTIFY_EXEMPT_PREFIXES) { if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) { mOffloadController.updateExemptPrefixes((Set<IpPrefix>) o); sendOffloadExemptPrefixes((Set<IpPrefix>) o); return; return; } } Loading Loading @@ -1573,6 +1592,9 @@ public class Tethering extends BaseNetworkObserver { mOffloadController.notifyDownstreamLinkProperties(newLp); mOffloadController.notifyDownstreamLinkProperties(newLp); } else { } else { mOffloadController.removeDownstreamInterface(newLp.getInterfaceName()); mOffloadController.removeDownstreamInterface(newLp.getInterfaceName()); // Another interface might be in local-only hotspot mode; // resend all local prefixes to the OffloadController. sendOffloadExemptPrefixes(); } } break; break; } } Loading
services/core/java/com/android/server/connectivity/tethering/OffloadController.java +55 −8 Original line number Original line Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED; import android.content.ContentResolver; import android.content.ContentResolver; import android.net.IpPrefix; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.LinkProperties; import android.net.RouteInfo; import android.net.RouteInfo; import android.net.util.SharedLog; import android.net.util.SharedLog; Loading @@ -27,8 +28,11 @@ import android.os.Handler; import android.provider.Settings; import android.provider.Settings; import java.net.Inet4Address; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetAddress; import java.util.ArrayList; import java.util.ArrayList; import java.util.HashSet; import java.util.Objects; import java.util.Set; import java.util.Set; /** /** Loading @@ -47,7 +51,13 @@ public class OffloadController { private boolean mConfigInitialized; private boolean mConfigInitialized; private boolean mControlInitialized; private boolean mControlInitialized; private LinkProperties mUpstreamLinkProperties; private LinkProperties mUpstreamLinkProperties; // The complete set of offload-exempt prefixes passed in via Tethering from // all upstream and downstream sources. private Set<IpPrefix> mExemptPrefixes; private Set<IpPrefix> mExemptPrefixes; // A strictly "smaller" set of prefixes, wherein offload-approved prefixes // (e.g. downstream on-link prefixes) have been removed and replaced with // prefixes representing only the locally-assigned IP addresses. private Set<String> mLastLocalPrefixStrs; public OffloadController(Handler h, OffloadHardwareInterface hwi, public OffloadController(Handler h, OffloadHardwareInterface hwi, ContentResolver contentResolver, SharedLog log) { ContentResolver contentResolver, SharedLog log) { Loading @@ -55,6 +65,8 @@ public class OffloadController { mHwInterface = hwi; mHwInterface = hwi; mContentResolver = contentResolver; mContentResolver = contentResolver; mLog = log.forSubComponent(TAG); mLog = log.forSubComponent(TAG); mExemptPrefixes = new HashSet<>(); mLastLocalPrefixStrs = new HashSet<>(); } } public void start() { public void start() { Loading Loading @@ -134,25 +146,22 @@ public class OffloadController { } } public void setUpstreamLinkProperties(LinkProperties lp) { public void setUpstreamLinkProperties(LinkProperties lp) { if (!started()) return; if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return; mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null; mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null; // TODO: examine return code and decide what to do if programming // TODO: examine return code and decide what to do if programming // upstream parameters fails (probably just wait for a subsequent // upstream parameters fails (probably just wait for a subsequent // onOffloadEvent() callback to tell us offload is available again and // onOffloadEvent() callback to tell us offload is available again and // then reapply all state). // then reapply all state). computeAndPushLocalPrefixes(); pushUpstreamParameters(); pushUpstreamParameters(); } } public void updateExemptPrefixes(Set<IpPrefix> exemptPrefixes) { public void setLocalPrefixes(Set<IpPrefix> localPrefixes) { if (!started()) return; if (!started()) return; mExemptPrefixes = exemptPrefixes; mExemptPrefixes = localPrefixes; // TODO: computeAndPushLocalPrefixes(); // - add IP addresses from all downstream link properties // - add routes from all non-tethering downstream link properties // - remove any 64share prefixes // - push this to the HAL } } public void notifyDownstreamLinkProperties(LinkProperties lp) { public void notifyDownstreamLinkProperties(LinkProperties lp) { Loading Loading @@ -215,4 +224,42 @@ public class OffloadController { return mHwInterface.setUpstreamParameters( return mHwInterface.setUpstreamParameters( iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways)); iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways)); } } private boolean computeAndPushLocalPrefixes() { final Set<String> localPrefixStrs = computeLocalPrefixStrings( mExemptPrefixes, mUpstreamLinkProperties); if (mLastLocalPrefixStrs.equals(localPrefixStrs)) return true; mLastLocalPrefixStrs = localPrefixStrs; return mHwInterface.setLocalPrefixes(new ArrayList<>(localPrefixStrs)); } // TODO: Factor in downstream LinkProperties once that information is available. private static Set<String> computeLocalPrefixStrings( Set<IpPrefix> localPrefixes, LinkProperties upstreamLinkProperties) { // Create an editable copy. final Set<IpPrefix> prefixSet = new HashSet<>(localPrefixes); // TODO: If a downstream interface (not currently passed in) is reusing // the /64 of the upstream (64share) then: // // [a] remove that /64 from the local prefixes // [b] add in /128s for IP addresses on the downstream interface // [c] add in /128s for IP addresses on the upstream interface // // Until downstream information is available here, simply add /128s from // the upstream network; they'll just be redundant with their /64. if (upstreamLinkProperties != null) { for (LinkAddress linkAddr : upstreamLinkProperties.getLinkAddresses()) { if (!linkAddr.isGlobalPreferred()) continue; final InetAddress ip = linkAddr.getAddress(); if (!(ip instanceof Inet6Address)) continue; prefixSet.add(new IpPrefix(ip, 128)); } } final HashSet<String> localPrefixStrs = new HashSet<>(); for (IpPrefix pfx : prefixSet) localPrefixStrs.add(pfx.toString()); return localPrefixStrs; } } }
services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java +20 −0 Original line number Original line Diff line number Diff line Loading @@ -168,6 +168,26 @@ public class OffloadHardwareInterface { return stats; return stats; } } public boolean setLocalPrefixes(ArrayList<String> localPrefixes) { final String logmsg = String.format("setLocalPrefixes([%s])", String.join(",", localPrefixes)); final CbResults results = new CbResults(); try { mOffloadControl.setLocalPrefixes(localPrefixes, (boolean success, String errMsg) -> { results.success = success; results.errMsg = errMsg; }); } catch (RemoteException e) { record(logmsg, e); return false; } record(logmsg, results); return results.success; } public boolean setUpstreamParameters( public boolean setUpstreamParameters( String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) { String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) { iface = (iface != null) ? iface : NO_INTERFACE_NAME; iface = (iface != null) ? iface : NO_INTERFACE_NAME; Loading
services/core/java/com/android/server/connectivity/tethering/TetherInterfaceStateMachine.java +2 −0 Original line number Original line Diff line number Diff line Loading @@ -161,6 +161,8 @@ public class TetherInterfaceStateMachine extends StateMachine { public int lastError() { return mLastError; } public int lastError() { return mLastError; } public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); } public void stop() { sendMessage(CMD_INTERFACE_DOWN); } public void stop() { sendMessage(CMD_INTERFACE_DOWN); } public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); } public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); } Loading
services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java +17 −41 Original line number Original line Diff line number Diff line Loading @@ -34,6 +34,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkRequest; import android.net.NetworkRequest; import android.net.NetworkState; import android.net.NetworkState; import android.net.util.NetworkConstants; import android.net.util.NetworkConstants; import android.net.util.PrefixUtils; import android.net.util.SharedLog; import android.net.util.SharedLog; import android.util.Log; import android.util.Log; Loading Loading @@ -72,16 +73,11 @@ public class UpstreamNetworkMonitor { private static final boolean DBG = false; private static final boolean DBG = false; private static final boolean VDBG = false; private static final boolean VDBG = false; private static final IpPrefix[] MINIMUM_LOCAL_PREFIXES_SET = { prefix("127.0.0.0/8"), prefix("169.254.0.0/16"), prefix("::/3"), prefix("fe80::/64"), prefix("fc00::/7"), prefix("ff00::/8"), }; public static final int EVENT_ON_AVAILABLE = 1; public static final int EVENT_ON_AVAILABLE = 1; public static final int EVENT_ON_CAPABILITIES = 2; public static final int EVENT_ON_CAPABILITIES = 2; public static final int EVENT_ON_LINKPROPERTIES = 3; public static final int EVENT_ON_LINKPROPERTIES = 3; public static final int EVENT_ON_LOST = 4; public static final int EVENT_ON_LOST = 4; public static final int NOTIFY_EXEMPT_PREFIXES = 10; public static final int NOTIFY_LOCAL_PREFIXES = 10; private static final int CALLBACK_LISTEN_ALL = 1; private static final int CALLBACK_LISTEN_ALL = 1; private static final int CALLBACK_TRACK_DEFAULT = 2; private static final int CALLBACK_TRACK_DEFAULT = 2; Loading @@ -93,7 +89,7 @@ public class UpstreamNetworkMonitor { private final Handler mHandler; private final Handler mHandler; private final int mWhat; private final int mWhat; private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>(); private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>(); private HashSet<IpPrefix> mOffloadExemptPrefixes; private HashSet<IpPrefix> mLocalPrefixes; private ConnectivityManager mCM; private ConnectivityManager mCM; private NetworkCallback mListenAllCallback; private NetworkCallback mListenAllCallback; private NetworkCallback mDefaultNetworkCallback; private NetworkCallback mDefaultNetworkCallback; Loading @@ -107,7 +103,7 @@ public class UpstreamNetworkMonitor { mHandler = mTarget.getHandler(); mHandler = mTarget.getHandler(); mLog = log.forSubComponent(TAG); mLog = log.forSubComponent(TAG); mWhat = what; mWhat = what; mOffloadExemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values()); mLocalPrefixes = new HashSet<>(); } } @VisibleForTesting @VisibleForTesting Loading Loading @@ -223,8 +219,8 @@ public class UpstreamNetworkMonitor { return typeStatePair.ns; return typeStatePair.ns; } } public Set<IpPrefix> getOffloadExemptPrefixes() { public Set<IpPrefix> getLocalPrefixes() { return (Set<IpPrefix>) mOffloadExemptPrefixes.clone(); return (Set<IpPrefix>) mLocalPrefixes.clone(); } } private void handleAvailable(int callbackType, Network network) { private void handleAvailable(int callbackType, Network network) { Loading Loading @@ -360,11 +356,11 @@ public class UpstreamNetworkMonitor { notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network)); notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network)); } } private void recomputeOffloadExemptPrefixes() { private void recomputeLocalPrefixes() { final HashSet<IpPrefix> exemptPrefixes = allOffloadExemptPrefixes(mNetworkMap.values()); final HashSet<IpPrefix> localPrefixes = allLocalPrefixes(mNetworkMap.values()); if (!mOffloadExemptPrefixes.equals(exemptPrefixes)) { if (!mLocalPrefixes.equals(localPrefixes)) { mOffloadExemptPrefixes = exemptPrefixes; mLocalPrefixes = localPrefixes; notifyTarget(NOTIFY_EXEMPT_PREFIXES, exemptPrefixes.clone()); notifyTarget(NOTIFY_LOCAL_PREFIXES, localPrefixes.clone()); } } } } Loading Loading @@ -402,7 +398,7 @@ public class UpstreamNetworkMonitor { @Override @Override public void onLinkPropertiesChanged(Network network, LinkProperties newLp) { public void onLinkPropertiesChanged(Network network, LinkProperties newLp) { handleLinkProp(network, newLp); handleLinkProp(network, newLp); recomputeOffloadExemptPrefixes(); recomputeLocalPrefixes(); } } // TODO: Handle onNetworkSuspended(); // TODO: Handle onNetworkSuspended(); Loading @@ -411,7 +407,7 @@ public class UpstreamNetworkMonitor { @Override @Override public void onLost(Network network) { public void onLost(Network network) { handleLost(mCallbackType, network); handleLost(mCallbackType, network); recomputeOffloadExemptPrefixes(); recomputeLocalPrefixes(); } } } } Loading Loading @@ -460,35 +456,15 @@ public class UpstreamNetworkMonitor { return result; return result; } } private static HashSet<IpPrefix> allOffloadExemptPrefixes(Iterable<NetworkState> netStates) { private static HashSet<IpPrefix> allLocalPrefixes(Iterable<NetworkState> netStates) { final HashSet<IpPrefix> prefixSet = new HashSet<>(); final HashSet<IpPrefix> prefixSet = new HashSet<>(); addDefaultLocalPrefixes(prefixSet); for (NetworkState ns : netStates) { for (NetworkState ns : netStates) { addOffloadExemptPrefixes(prefixSet, ns.linkProperties); final LinkProperties lp = ns.linkProperties; if (lp == null) continue; prefixSet.addAll(PrefixUtils.localPrefixesFrom(lp)); } } return prefixSet; return prefixSet; } } private static void addDefaultLocalPrefixes(Set<IpPrefix> prefixSet) { Collections.addAll(prefixSet, MINIMUM_LOCAL_PREFIXES_SET); } private static void addOffloadExemptPrefixes(Set<IpPrefix> prefixSet, LinkProperties lp) { if (lp == null) return; for (LinkAddress linkAddr : lp.getAllLinkAddresses()) { prefixSet.add(new IpPrefix(linkAddr.getAddress(), linkAddr.getPrefixLength())); } // TODO: Consider adding other non-default routes associated with this // network. Traffic to these destinations should perhaps not go through // the Internet (upstream). } private static IpPrefix prefix(String prefixStr) { return new IpPrefix(prefixStr); } } }