Allow callers of startTethering to choose local-only mode.
This is useful for OEMs that want to use RNDIS or NCM as a
local-only link that is directly connected to some other host.
This can be used to implement USB tethering using NCM, which
currently only supports local-only mode.
Bug: 175090447
Test: TetheringIntegrationTests:EthernetTetheringTest#testLocalOnlyTethering
Change-Id: I0ffaa46e4640e5b235340a15d25909106ceb0c07
diff --git a/Tethering/src/android/net/ip/IpServer.java b/Tethering/src/android/net/ip/IpServer.java
index da15fa8..c45ce83 100644
--- a/Tethering/src/android/net/ip/IpServer.java
+++ b/Tethering/src/android/net/ip/IpServer.java
@@ -1426,7 +1426,7 @@
break;
case CMD_INTERFACE_DOWN:
transitionTo(mUnavailableState);
- mLog.i("Untethered (interface down) and restarting" + mIfaceName);
+ mLog.i("Untethered (interface down) and restarting " + mIfaceName);
mCallback.requestEnableTethering(mInterfaceType, true /* enabled */);
break;
default:
diff --git a/Tethering/src/android/net/util/TetheringUtils.java b/Tethering/src/android/net/util/TetheringUtils.java
index 9e7cc2f..29900d9 100644
--- a/Tethering/src/android/net/util/TetheringUtils.java
+++ b/Tethering/src/android/net/util/TetheringUtils.java
@@ -162,7 +162,8 @@
&& Objects.equals(request.localIPv4Address, otherRequest.localIPv4Address)
&& Objects.equals(request.staticClientAddress, otherRequest.staticClientAddress)
&& request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck
- && request.showProvisioningUi == otherRequest.showProvisioningUi;
+ && request.showProvisioningUi == otherRequest.showProvisioningUi
+ && request.connectivityScope == otherRequest.connectivityScope;
}
/** Get inet6 address for all nodes given scope ID. */
diff --git a/Tethering/src/com/android/networkstack/tethering/Tethering.java b/Tethering/src/com/android/networkstack/tethering/Tethering.java
index 1815ff3..acbfa8c 100644
--- a/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ b/Tethering/src/com/android/networkstack/tethering/Tethering.java
@@ -29,6 +29,7 @@
import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
+import static android.net.TetheringManager.CONNECTIVITY_SCOPE_LOCAL;
import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
@@ -90,6 +91,7 @@
import android.net.TetheredClient;
import android.net.TetheringCallbackStartedParcel;
import android.net.TetheringConfigurationParcel;
+import android.net.TetheringManager.TetheringRequest;
import android.net.TetheringRequestParcel;
import android.net.ip.IpServer;
import android.net.shared.NetdUtils;
@@ -731,7 +733,7 @@
return;
}
maybeTrackNewInterfaceLocked(iface, TETHERING_ETHERNET);
- changeInterfaceState(iface, IpServer.STATE_TETHERED);
+ changeInterfaceState(iface, getRequestedState(TETHERING_ETHERNET));
mConfiguredEthernetIface = iface;
}
}
@@ -748,10 +750,10 @@
}
}
- void tether(String iface, final IIntResultListener listener) {
+ void tether(String iface, int requestedState, final IIntResultListener listener) {
mHandler.post(() -> {
try {
- listener.onResult(tether(iface, IpServer.STATE_TETHERED));
+ listener.onResult(tether(iface, requestedState));
} catch (RemoteException e) { }
});
}
@@ -855,6 +857,22 @@
return true;
}
+ private int getRequestedState(int type) {
+ final TetheringRequestParcel request = mActiveTetheringRequests.get(type);
+
+ // The request could have been deleted before we had a chance to complete it.
+ // If so, assume that the scope is the default scope for this tethering type.
+ // This likely doesn't matter - if the request has been deleted, then tethering is
+ // likely going to be stopped soon anyway.
+ final int connectivityScope = (request != null)
+ ? request.connectivityScope
+ : TetheringRequest.getDefaultConnectivityScope(type);
+
+ return connectivityScope == CONNECTIVITY_SCOPE_LOCAL
+ ? IpServer.STATE_LOCAL_ONLY
+ : IpServer.STATE_TETHERED;
+ }
+
// TODO: Figure out how to update for local hotspot mode interfaces.
private void sendTetherStateChangedBroadcast() {
if (!isTetheringSupported()) return;
@@ -994,9 +1012,11 @@
mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_USB);
} else if (usbConfigured && rndisEnabled) {
// Tether if rndis is enabled and usb is configured.
- tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
+ final int state = getRequestedState(TETHERING_USB);
+ tetherMatchingInterfaces(state, TETHERING_USB);
} else if (usbConnected && ncmEnabled) {
- tetherMatchingInterfaces(IpServer.STATE_LOCAL_ONLY, TETHERING_NCM);
+ final int state = getRequestedState(TETHERING_NCM);
+ tetherMatchingInterfaces(state, TETHERING_NCM);
}
mRndisEnabled = usbConfigured && rndisEnabled;
}
diff --git a/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
index 1906ca7..e36df7f 100644
--- a/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ b/Tethering/src/com/android/networkstack/tethering/TetheringService.java
@@ -105,7 +105,7 @@
IIntResultListener listener) {
if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
- mTethering.tether(iface, listener);
+ mTethering.tether(iface, IpServer.STATE_TETHERED, listener);
}
@Override