Android 16.0.0 release 4
-----BEGIN PGP SIGNATURE----- iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCaS5huQAKCRDorT+BmrEO eIsnAJ9kJ9OjiHpwigt9XwjTrGcbD1hQ0QCfSw2VHyS9TLyzt7DZsQ3AYU+WVVA= =/SH/ -----END PGP SIGNATURE----- gpgsig -----BEGIN SSH SIGNATURE----- U1NIU0lHAAAAAQAAADMAAAALc3NoLWVkMjU1MTkAAAAgPpdpjxPACTIhnlvYz0GM4BR7FJ +rYv3jMbfxNKD3JvcAAAADZ2l0AAAAAAAAAAZzaGE1MTIAAABTAAAAC3NzaC1lZDI1NTE5 AAAAQHUBff/oLA1TO7KbbZDsBJZmFVcXgFmG+2K3aaKq9F0tiaT1kiNeHdjXpaLI07p344 TExz9CBvFVft81pJyRBwY= -----END SSH SIGNATURE----- Merge tag 'android-16.0.0_r4' into staging/lineage-23.2_merge-android-16.0.0_r4 Android 16.0.0 release 4 # -----BEGIN PGP SIGNATURE----- # # iF0EABECAB0WIQRDQNE1cO+UXoOBCWTorT+BmrEOeAUCaS5huQAKCRDorT+BmrEO # eIsnAJ9kJ9OjiHpwigt9XwjTrGcbD1hQ0QCfSw2VHyS9TLyzt7DZsQ3AYU+WVVA= # =/SH/ # -----END PGP SIGNATURE----- # gpg: Signature made Tue Dec 2 05:49:13 2025 EET # gpg: using DSA key 4340D13570EF945E83810964E8AD3F819AB10E78 # gpg: Good signature from "The Android Open Source Project <initial-contribution@android.com>" [ultimate] # By Yan Yan (203) and others # Via Automerger Merge Worker (1173) and others * tag 'android-16.0.0_r4': (1057 commits) Use string for CREATE_APP_SPECIFIC_NETWORK permission bpf: move MSS calculation under CE check to avoid overhead BpfNetworkStats: use `atomic` for ifindex cache when possible NetBpfLoad: remove pointless 0 write. bpf: remove obsolete isAtLeastR/Sv2/25Q3 NetBpfLoad: use global `api_level_full` directly in NetBpfLoad Log validated underlying network count that's available for VCN underlying network selection BpfUtils: fix sdk level detection logic for 25Q3+ Add RTMGRP_IPV6_IFINFO bpf: remove BPFLOADER_MAINLINE_U_QPR3_VERSION bpf: move BPFLOADER_MAINLINE_S_VERSION into bpf_map_def.h Reduce log level for BluetoothSocket errors Bump the min sdk of Tethering BpfNetworkStats: apparently RiscV isn't actually a 64-bit architecture. KernelUtils.h: isAtLeastKernelVersion(x,y,z) - default 'z' to 0 bpf_existence_test - update for tcp acc ecn bpf: tcpAccECN: eliminate header file and move more fully into netd BpfMap: shorten error strings to enable SSO (on 64-bit) BpfNetworkStats: enforce that IfaceValue access is lock-free NetBpfLoad: use libbpf based on mainline beta flag, part 2 ... Conflicts: bpf/headers/include/bpf/KernelUtils.h bpf/progs/netd.h Change-Id: I76a7aadc1405c6621e17f3d1b6b87640d84f5794
This commit is contained in:
commit
42374b293f
554 changed files with 53416 additions and 6658 deletions
|
|
@ -11,4 +11,4 @@ xiaom@google.com
|
|||
yuyanghuang@google.com
|
||||
|
||||
martinwu@google.com #{LAST_RESORT_SUGGESTION}
|
||||
satk@google.com #{LAST_RESORT_SUGGESTION}
|
||||
larsberg@google.com #{LAST_RESORT_SUGGESTION}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
lorenzo@google.com
|
||||
satk@google.com #{LAST_RESORT_SUGGESTION}
|
||||
larsberg@google.com #{LAST_RESORT_SUGGESTION}
|
||||
|
||||
# For cherry-picks of CLs that are already merged in aosp/master, flaky test
|
||||
# fixes, or no-op refactors.
|
||||
|
|
|
|||
|
|
@ -15,6 +15,3 @@ ktlint_hook = ${REPO_ROOT}/prebuilts/ktlint/ktlint.py --disabled-rules comment-w
|
|||
hidden_api_txt_checksorted_hook = ${REPO_ROOT}/tools/platform-compat/hiddenapi/checksorted_sha.sh ${PREUPLOAD_COMMIT} ${REPO_ROOT}
|
||||
|
||||
python_hook = ${REPO_ROOT}/packages/modules/Connectivity/preupload_hook_script.py ${PREUPLOAD_FILES}
|
||||
|
||||
# go/alint for details
|
||||
alint_hook = ${REPO_ROOT}/vendor/google/tools/alint
|
||||
|
|
|
|||
44
TEST_MAPPING
44
TEST_MAPPING
|
|
@ -83,6 +83,14 @@
|
|||
"exclude-annotation": "com.android.testutils.NetworkStackModuleTest"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CtsHostsideNetworkTests",
|
||||
"options": [
|
||||
{
|
||||
"exclude-annotation": "androidx.test.filters.RequiresDevice"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"captiveportal-networkstack-mainline-presubmit": [
|
||||
|
|
@ -319,14 +327,6 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CtsHostsideNetworkTests[CaptivePortalLoginGoogle.apk+NetworkStackGoogle.apk+com.google.android.resolv.apex+com.google.android.tethering.apex]",
|
||||
"options": [
|
||||
{
|
||||
"exclude-annotation": "androidx.test.filters.RequiresDevice"
|
||||
}
|
||||
]
|
||||
},
|
||||
// Test with APK modules only, in cases where APEX is not supported, or the other modules
|
||||
// were simply not updated
|
||||
{
|
||||
|
|
@ -435,12 +435,23 @@
|
|||
"name": "CtsNetTestCasesUpdateStatsPermission"
|
||||
}
|
||||
],
|
||||
"tv-presubmit": [
|
||||
"hsum-presubmit": [
|
||||
{
|
||||
"name": "CtsNetTestCases"
|
||||
},
|
||||
{
|
||||
"name": "CtsNativeNetTestCases"
|
||||
"name": "CtsNativeNetDnsTestCases"
|
||||
},
|
||||
{
|
||||
"name": "CtsNetTestCasesInternetPermission"
|
||||
},
|
||||
{
|
||||
"name": "CtsNetTestCasesUpdateStatsPermission"
|
||||
}
|
||||
],
|
||||
"tv-presubmit": [
|
||||
{
|
||||
"name": "CtsNetTestCases"
|
||||
},
|
||||
{
|
||||
"name": "CtsNativeNetDnsTestCases"
|
||||
|
|
@ -471,5 +482,18 @@
|
|||
{
|
||||
"path": "vendor/xts/gts-tests/hostsidetests/networkstack"
|
||||
}
|
||||
],
|
||||
"wear-cts-presubmit": [
|
||||
{
|
||||
"name": "CtsNetTestCases",
|
||||
"options": [
|
||||
{
|
||||
"exclude-filter": "android.net.cts.NetworkValidationTest#testCapportApiCallbacks"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CtsNetTestCasesUpdateStatsPermission"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,7 +22,10 @@ package {
|
|||
java_defaults {
|
||||
name: "TetheringApiLevel",
|
||||
sdk_version: "module_current",
|
||||
min_sdk_version: "30",
|
||||
min_sdk_version: select(release_flag("RELEASE_DEPRECATE_MAINLINE_R_SUPPORT"), {
|
||||
true: "31",
|
||||
default: "30",
|
||||
}),
|
||||
}
|
||||
|
||||
java_defaults {
|
||||
|
|
@ -65,6 +68,8 @@ java_defaults {
|
|||
"androidx.annotation_annotation",
|
||||
"connectivity-net-module-utils-bpf",
|
||||
"com.android.net.flags-aconfig-java",
|
||||
"com.android.tethering.beta.test.flags-aconfig-java",
|
||||
"com.android.tethering.mainline.beta.flags-aconfig-java",
|
||||
"modules-utils-build",
|
||||
"modules-utils-statemachine",
|
||||
"networkstack-client",
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ apex {
|
|||
"libservice-connectivity",
|
||||
"libservice-thread-jni",
|
||||
"libandroid_net_connectivity_com_android_net_module_util_jni",
|
||||
"libandroid_net_connectivity_com_android_net_module_util_jni_CommonConnectivityJni",
|
||||
],
|
||||
native_shared_libs: [
|
||||
"libcom.android.tethering.dns_helper",
|
||||
|
|
|
|||
|
|
@ -33,20 +33,17 @@ import androidx.annotation.Nullable;
|
|||
import com.android.net.module.util.IBpfMap;
|
||||
import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
|
||||
import com.android.net.module.util.SharedLog;
|
||||
import com.android.net.module.util.Struct.S32;
|
||||
import com.android.net.module.util.Struct.S64;
|
||||
import com.android.net.module.util.bpf.Tether4Key;
|
||||
import com.android.net.module.util.bpf.Tether4Value;
|
||||
import com.android.net.module.util.bpf.TetherStatsKey;
|
||||
import com.android.net.module.util.bpf.TetherStatsValue;
|
||||
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
|
||||
import com.android.networkstack.tethering.BpfCoordinator.Ipv6DownstreamRule;
|
||||
import com.android.networkstack.tethering.BpfCoordinator.Ipv6UpstreamRule;
|
||||
import com.android.networkstack.tethering.BpfUtils;
|
||||
import com.android.networkstack.tethering.Tether6Value;
|
||||
import com.android.networkstack.tethering.TetherDevKey;
|
||||
import com.android.networkstack.tethering.TetherDevValue;
|
||||
import com.android.networkstack.tethering.TetherDownstream6Key;
|
||||
import com.android.networkstack.tethering.TetherLimitKey;
|
||||
import com.android.networkstack.tethering.TetherLimitValue;
|
||||
import com.android.networkstack.tethering.TetherUpstream6Key;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
|
|
@ -85,15 +82,15 @@ public class BpfCoordinatorShimImpl
|
|||
|
||||
// BPF map of tethering statistics of the upstream interface since tethering startup.
|
||||
@Nullable
|
||||
private final IBpfMap<TetherStatsKey, TetherStatsValue> mBpfStatsMap;
|
||||
private final IBpfMap<S32, TetherStatsValue> mBpfStatsMap;
|
||||
|
||||
// BPF map of per-interface quota for tethering offload.
|
||||
@Nullable
|
||||
private final IBpfMap<TetherLimitKey, TetherLimitValue> mBpfLimitMap;
|
||||
private final IBpfMap<S32, S64> mBpfLimitMap;
|
||||
|
||||
// BPF map of interface index mapping for XDP.
|
||||
@Nullable
|
||||
private final IBpfMap<TetherDevKey, TetherDevValue> mBpfDevMap;
|
||||
private final IBpfMap<S32, S32> mBpfDevMap;
|
||||
|
||||
// Tracking IPv4 rule count while any rule is using the given upstream interfaces. Used for
|
||||
// reducing the BPF map iteration query. The count is increased or decreased when the rule is
|
||||
|
|
@ -252,7 +249,7 @@ public class BpfCoordinatorShimImpl
|
|||
try {
|
||||
// The reported tether stats are total data usage for all currently-active upstream
|
||||
// interfaces since tethering start.
|
||||
mBpfStatsMap.forEach((key, value) -> tetherStatsList.put((int) key.ifindex, value));
|
||||
mBpfStatsMap.forEach((key, value) -> tetherStatsList.put((int) key.val, value));
|
||||
} catch (ErrnoException e) {
|
||||
mLog.e("Fail to fetch tethering stats from BPF map: ", e);
|
||||
return null;
|
||||
|
|
@ -269,7 +266,7 @@ public class BpfCoordinatorShimImpl
|
|||
TetherStatsValue statsValue = null;
|
||||
|
||||
try {
|
||||
statsValue = mBpfStatsMap.getValue(new TetherStatsKey(ifIndex));
|
||||
statsValue = mBpfStatsMap.getValue(new S32(ifIndex));
|
||||
} catch (ErrnoException e) {
|
||||
// The BpfMap#getValue doesn't throw an errno ENOENT exception. Catch other error
|
||||
// while trying to get stats entry.
|
||||
|
|
@ -287,7 +284,7 @@ public class BpfCoordinatorShimImpl
|
|||
// This function is the *only* thing that can create entries.
|
||||
// BpfMap#insertEntry use BPF_NOEXIST to create the entry. The entry is created
|
||||
// if and only if it doesn't exist.
|
||||
mBpfStatsMap.insertEntry(new TetherStatsKey(ifIndex), new TetherStatsValue(
|
||||
mBpfStatsMap.insertEntry(new S32(ifIndex), new TetherStatsValue(
|
||||
0 /* rxPackets */, 0 /* rxBytes */, 0 /* rxErrors */, 0 /* txPackets */,
|
||||
0 /* txBytes */, 0 /* txErrors */));
|
||||
} catch (ErrnoException | IllegalArgumentException e) {
|
||||
|
|
@ -305,7 +302,7 @@ public class BpfCoordinatorShimImpl
|
|||
if (newLimit < rxBytes + txBytes) newLimit = QUOTA_UNLIMITED;
|
||||
|
||||
try {
|
||||
mBpfLimitMap.updateEntry(new TetherLimitKey(ifIndex), new TetherLimitValue(newLimit));
|
||||
mBpfLimitMap.updateEntry(new S32(ifIndex), new S64(newLimit));
|
||||
} catch (ErrnoException e) {
|
||||
mLog.e("Fail to set quota " + quotaBytes + " for interface index " + ifIndex + ": ", e);
|
||||
return false;
|
||||
|
|
@ -331,7 +328,7 @@ public class BpfCoordinatorShimImpl
|
|||
|
||||
TetherStatsValue statsValue = null;
|
||||
try {
|
||||
statsValue = mBpfStatsMap.getValue(new TetherStatsKey(ifIndex));
|
||||
statsValue = mBpfStatsMap.getValue(new S32(ifIndex));
|
||||
} catch (ErrnoException e) {
|
||||
mLog.e("Could not get stats entry for interface index " + ifIndex + ": ", e);
|
||||
return null;
|
||||
|
|
@ -343,14 +340,14 @@ public class BpfCoordinatorShimImpl
|
|||
}
|
||||
|
||||
try {
|
||||
mBpfStatsMap.deleteEntry(new TetherStatsKey(ifIndex));
|
||||
mBpfStatsMap.deleteEntry(new S32(ifIndex));
|
||||
} catch (ErrnoException e) {
|
||||
mLog.e("Could not delete stats entry for interface index " + ifIndex + ": ", e);
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
mBpfLimitMap.deleteEntry(new TetherLimitKey(ifIndex));
|
||||
mBpfLimitMap.deleteEntry(new S32(ifIndex));
|
||||
} catch (ErrnoException e) {
|
||||
mLog.e("Could not delete limit for interface index " + ifIndex + ": ", e);
|
||||
return null;
|
||||
|
|
@ -470,7 +467,7 @@ public class BpfCoordinatorShimImpl
|
|||
@Override
|
||||
public boolean addDevMap(int ifIndex) {
|
||||
try {
|
||||
mBpfDevMap.updateEntry(new TetherDevKey(ifIndex), new TetherDevValue(ifIndex));
|
||||
mBpfDevMap.updateEntry(new S32(ifIndex), new S32(ifIndex));
|
||||
} catch (ErrnoException e) {
|
||||
mLog.e("Could not add interface " + ifIndex + ": " + e);
|
||||
return false;
|
||||
|
|
@ -481,7 +478,7 @@ public class BpfCoordinatorShimImpl
|
|||
@Override
|
||||
public boolean removeDevMap(int ifIndex) {
|
||||
try {
|
||||
mBpfDevMap.deleteEntry(new TetherDevKey(ifIndex));
|
||||
mBpfDevMap.deleteEntry(new S32(ifIndex));
|
||||
} catch (ErrnoException e) {
|
||||
mLog.e("Could not delete interface " + ifIndex + ": " + e);
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -34,8 +34,9 @@ java_sdk_library {
|
|||
// Using for test only
|
||||
"//cts/tests/netlegacy22.api",
|
||||
|
||||
// TODO: b/374174952 Remove it when VCN CTS is moved to Connectivity/
|
||||
// TODO: b/374174952 Clean up VCN paths when the code location is finalized
|
||||
"//cts/tests/tests/vcn",
|
||||
"//packages/modules/Connectivity/Vcn/tests:__subpackages__",
|
||||
|
||||
"//external/sl4a:__subpackages__",
|
||||
"//frameworks/base/core/tests/bandwidthtests",
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ package android.net;
|
|||
|
||||
/**
|
||||
* Listener interface allowing objects to listen to various module event.
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
oneway interface IIntResultListener {
|
||||
void onResult(int resultCode);
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import android.net.TetheringInterface;
|
|||
|
||||
/**
|
||||
* Status details for tethering downstream interfaces.
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
parcelable TetherStatesParcel {
|
||||
TetheringInterface[] availableList;
|
||||
|
|
|
|||
|
|
@ -381,7 +381,7 @@ public class TetheringManager {
|
|||
* @param context Context for the manager.
|
||||
* @param connectorSupplier Supplier for the manager connector; may return null while the
|
||||
* service is not connected.
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
public TetheringManager(@NonNull final Context context,
|
||||
|
|
@ -574,7 +574,7 @@ public class TetheringManager {
|
|||
* already released.
|
||||
* 2. This is not synchronous, so it's not useful to use try-with-resources.
|
||||
*
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
@SuppressLint("NotCloseable")
|
||||
|
|
@ -588,7 +588,7 @@ public class TetheringManager {
|
|||
/**
|
||||
* Callback for requestTetheredInterface.
|
||||
*
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
public interface TetheredInterfaceCallback {
|
||||
|
|
@ -694,7 +694,7 @@ public class TetheringManager {
|
|||
* @param iface the interface name to tether.
|
||||
* @return error a {@code TETHER_ERROR} value indicating success or failure type
|
||||
*
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
|
|
@ -729,7 +729,7 @@ public class TetheringManager {
|
|||
* On SDK versions after {@link Build.VERSION_CODES.VANILLA_ICE_CREAM}, this will
|
||||
* throw an UnsupportedOperationException.
|
||||
*
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
|
|
@ -758,7 +758,7 @@ public class TetheringManager {
|
|||
* used and an entitlement check is needed, downstream USB tethering will be enabled but will
|
||||
* not have any upstream.
|
||||
*
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
@Deprecated
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
|
|
@ -1553,7 +1553,7 @@ public class TetheringManager {
|
|||
* Helper function of #requestLatestTetheringEntitlementResult to remain backwards compatible
|
||||
* with ConnectivityManager#getLatestTetheringEntitlementResult
|
||||
*
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
// TODO: improve the usage of ResultReceiver, b/145096122
|
||||
@SystemApi(client = MODULE_LIBRARIES)
|
||||
|
|
|
|||
37
Tethering/jni/commonconnectivity/onload.cpp
Normal file
37
Tethering/jni/commonconnectivity/onload.cpp
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#define LOG_TAG "com_android_networkstack_tethering_util_CommonConnectivityJni"
|
||||
|
||||
#include <android/log.h>
|
||||
#include <nativehelper/JNIHelp.h>
|
||||
|
||||
namespace android {
|
||||
int register_CommonConnectivityJni(JNIEnv *env, char const *class_name);
|
||||
|
||||
extern "C" jint JNI_OnLoad(JavaVM *vm, void *) {
|
||||
JNIEnv *env;
|
||||
if (vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6) !=
|
||||
JNI_OK) {
|
||||
__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed");
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
if (register_CommonConnectivityJni(env,
|
||||
"com/android/networkstack/tethering/util/CommonConnectivityJni") < 0) return JNI_ERR;
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
}; // namespace android
|
||||
|
|
@ -23,6 +23,7 @@
|
|||
namespace android {
|
||||
|
||||
int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name);
|
||||
int register_com_android_net_module_util_BpfBitmap(JNIEnv* env, char const* class_name);
|
||||
int register_com_android_net_module_util_TcUtils(JNIEnv* env, char const* class_name);
|
||||
int register_com_android_networkstack_tethering_BpfCoordinator(JNIEnv* env);
|
||||
int register_com_android_networkstack_tethering_util_TetheringUtils(JNIEnv* env);
|
||||
|
|
@ -39,6 +40,9 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
|
|||
if (register_com_android_net_module_util_BpfMap(env,
|
||||
"com/android/networkstack/tethering/util/BpfMap") < 0) return JNI_ERR;
|
||||
|
||||
if (register_com_android_net_module_util_BpfBitmap(env,
|
||||
"com/android/networkstack/tethering/util/BpfBitmap") < 0) return JNI_ERR;
|
||||
|
||||
if (register_com_android_net_module_util_TcUtils(env,
|
||||
"com/android/networkstack/tethering/util/TcUtils") < 0) return JNI_ERR;
|
||||
|
||||
|
|
|
|||
|
|
@ -39,11 +39,11 @@ import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
|
|||
import static android.net.util.NetworkConstants.asByte;
|
||||
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
||||
|
||||
import static com.android.net.module.util.ConnectivityCommonFlags.USE_ROUTE_PARCEL_IPCS;
|
||||
import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
|
||||
import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
|
||||
import static com.android.networkstack.tethering.TetheringConfiguration.USE_SYNC_SM;
|
||||
import static com.android.networkstack.tethering.TetheringFeatureFlags.TETHERING_LOCAL_NETWORK_AGENT;
|
||||
import static com.android.networkstack.tethering.TetheringFeatureFlags.WIFIP2PGO_LOCAL_NETWORK_AGENT;
|
||||
import static com.android.networkstack.tethering.TetheringFeatureFlags.TETHERING_AND_P2P_GO_LOCAL_AGENT;
|
||||
import static com.android.networkstack.tethering.util.PrefixUtils.asIpPrefix;
|
||||
import static com.android.networkstack.tethering.util.TetheringMessageBase.BASE_IPSERVER;
|
||||
import static com.android.networkstack.tethering.util.TetheringUtils.getTransportTypeForTetherableType;
|
||||
|
|
@ -91,6 +91,7 @@ import com.android.net.module.util.IIpv4PrefixRequest;
|
|||
import com.android.net.module.util.InterfaceParams;
|
||||
import com.android.net.module.util.NetdUtils;
|
||||
import com.android.net.module.util.RoutingCoordinatorManager;
|
||||
import com.android.net.module.util.SdkUtil;
|
||||
import com.android.net.module.util.SharedLog;
|
||||
import com.android.net.module.util.SyncStateMachine.StateInfo;
|
||||
import com.android.net.module.util.ip.InterfaceController;
|
||||
|
|
@ -100,6 +101,7 @@ import com.android.networkstack.tethering.metrics.TetheringMetrics;
|
|||
import com.android.networkstack.tethering.util.InterfaceSet;
|
||||
import com.android.networkstack.tethering.util.PrefixUtils;
|
||||
import com.android.networkstack.tethering.util.StateMachineShim;
|
||||
import com.android.tethering.mainline.beta.Flags;
|
||||
|
||||
import java.net.Inet4Address;
|
||||
import java.net.Inet6Address;
|
||||
|
|
@ -218,10 +220,24 @@ public class IpServer extends StateMachineShim {
|
|||
DhcpServerCallbacks cb);
|
||||
|
||||
/**
|
||||
* @see DeviceConfigUtils#isTetheringFeatureEnabled
|
||||
* Get whether a tethering feature flag is enabled via chickened out.
|
||||
* @param name the name of the feature.
|
||||
*/
|
||||
public boolean isFeatureEnabled(Context context, String name) {
|
||||
return DeviceConfigUtils.isTetheringFeatureEnabled(context, name);
|
||||
public boolean isTetheringFeatureNotChickenedOut(@NonNull Context context,
|
||||
@NonNull String name) {
|
||||
return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(context, name);
|
||||
}
|
||||
|
||||
/** Get whether tethering and P2P GO local agent flag is enabled via beta flags. */
|
||||
public boolean isTetheringAndP2pGoLocalAgentBetaFlagEnabled() {
|
||||
return Flags.tetheringAndP2pGoLocalAgent();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DeviceConfigUtils#isTetheringFeatureNotChickenedOut
|
||||
*/
|
||||
public boolean isFeatureNotChickenedOut(Context context, String name) {
|
||||
return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(context, name);
|
||||
}
|
||||
|
||||
/** Create a NetworkAgent instance to be used by IpServer. */
|
||||
|
|
@ -288,6 +304,7 @@ public class IpServer extends StateMachineShim {
|
|||
private final boolean mUsingLegacyDhcp;
|
||||
private final int mP2pLeasesSubnetPrefixLength;
|
||||
private final boolean mIsWifiP2pDedicatedIpEnabled;
|
||||
private final boolean mUseRouteParcel;
|
||||
|
||||
private final Dependencies mDeps;
|
||||
|
||||
|
|
@ -335,8 +352,8 @@ public class IpServer extends StateMachineShim {
|
|||
private final Handler mHandler;
|
||||
private final Context mContext;
|
||||
|
||||
private final boolean mSupportTetheringLocalAgent;
|
||||
private final boolean mSupportWifiP2pGroupOwnerLocalAgent;
|
||||
// Whether to enable tethering and Wi-Fi P2p Group Owner mode local network agent.
|
||||
private final boolean mSupportTetheringAndP2pGoLocalAgent;
|
||||
|
||||
// This will be null if the TetheredState is not entered or feature not supported.
|
||||
// This will be only accessed from the IpServer handler thread.
|
||||
|
|
@ -381,11 +398,21 @@ public class IpServer extends StateMachineShim {
|
|||
mLastError = TETHER_ERROR_NO_ERROR;
|
||||
mServingMode = STATE_AVAILABLE;
|
||||
|
||||
// Tethering network agent is supported on V+, and will be rolled out gradually.
|
||||
mSupportTetheringLocalAgent = SdkLevel.isAtLeastV()
|
||||
&& mDeps.isFeatureEnabled(mContext, TETHERING_LOCAL_NETWORK_AGENT);
|
||||
mSupportWifiP2pGroupOwnerLocalAgent = mSupportTetheringLocalAgent
|
||||
&& mDeps.isFeatureEnabled(mContext, WIFIP2PGO_LOCAL_NETWORK_AGENT);
|
||||
// Determines support for the Tethering/P2P GO local network agent. This feature is
|
||||
// gated on Android V+ because it requires NET_CAPABILITY_LOCAL_NETWORK.
|
||||
// For 25Q4+, it is enabled by default with a kill switch to prevent impacting
|
||||
// existing devices if issues arise. For older V+ devices, rollout is controlled
|
||||
// by a mainline beta flag.
|
||||
mSupportTetheringAndP2pGoLocalAgent = SdkLevel.isAtLeastV()
|
||||
&& (SdkUtil.isAtLeast25Q4()
|
||||
? mDeps.isTetheringFeatureNotChickenedOut(mContext,
|
||||
TETHERING_AND_P2P_GO_LOCAL_AGENT)
|
||||
: mDeps.isTetheringAndP2pGoLocalAgentBetaFlagEnabled());
|
||||
|
||||
// For post 25Q2 releases always use *RouteParcel methods. For 25Q2 or lower, decide based
|
||||
// on kill-switch
|
||||
mUseRouteParcel = SdkUtil.isAtLeast25Q4()
|
||||
|| mDeps.isFeatureNotChickenedOut(mContext, USE_ROUTE_PARCEL_IPCS);
|
||||
|
||||
mInitialState = new InitialState();
|
||||
mLocalHotspotState = new LocalHotspotState();
|
||||
|
|
@ -848,6 +875,7 @@ public class IpServer extends StateMachineShim {
|
|||
String upstreamIface = null;
|
||||
InterfaceParams upstreamIfaceParams = null;
|
||||
int upstreamIfIndex = NO_UPSTREAM;
|
||||
int pmtu6 = 1400; // default 'safe-ish' value
|
||||
|
||||
if (v6only != null) {
|
||||
upstreamIface = v6only.getInterfaceName();
|
||||
|
|
@ -856,7 +884,14 @@ public class IpServer extends StateMachineShim {
|
|||
upstreamIfIndex = upstreamIfaceParams.index;
|
||||
}
|
||||
params = new RaParams();
|
||||
params.mtu = v6only.getMtu();
|
||||
pmtu6 = v6only.getMtu();
|
||||
if (pmtu6 < 1280) pmtu6 = 1400; // we simply don't know what it is, 1400 is safe-ish
|
||||
for (RouteInfo route : v6only.getRoutes()) {
|
||||
if (route.getMtu() >= 1280) pmtu6 = Math.min(pmtu6, route.getMtu());
|
||||
}
|
||||
// Clamp v6 MTU to 1280-1500 range.
|
||||
if (pmtu6 > 1500) pmtu6 = 1500;
|
||||
params.mtu = pmtu6;
|
||||
params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
|
||||
|
||||
if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface, ttlAdjustment);
|
||||
|
|
@ -874,6 +909,8 @@ public class IpServer extends StateMachineShim {
|
|||
// CMD_TETHER_CONNECTION_CHANGED. Adding the mapping update here to the avoid potential
|
||||
// timing issue. It prevents that the IPv6 capability is updated later than
|
||||
// CMD_TETHER_CONNECTION_CHANGED.
|
||||
//
|
||||
// TODO: I believe we need to push v6mtu into this call.
|
||||
mBpfCoordinator.maybeAddUpstreamToLookupTable(upstreamIfIndex, upstreamIface);
|
||||
|
||||
// If v6only is null, we pass in null to setRaParams(), which handles
|
||||
|
|
@ -886,7 +923,7 @@ public class IpServer extends StateMachineShim {
|
|||
// mLastIPv6UpstreamIfindex and mLastIPv6UpstreamPrefixes because BpfCoordinator will call
|
||||
// IpServer#getIpv6UpstreamIfindex and IpServer#getIpv6UpstreamPrefixes to retrieve current
|
||||
// upstream interface index and prefixes when handling upstream changes.
|
||||
mBpfCoordinator.updateIpv6UpstreamInterface(this, upstreamIfIndex, upstreamPrefixes);
|
||||
mBpfCoordinator.updateIpv6UpstreamInterface(this, upstreamIfIndex, upstreamPrefixes, pmtu6);
|
||||
mLastIPv6LinkProperties = v6only;
|
||||
mLastIPv6UpstreamIfindex = upstreamIfIndex;
|
||||
mLastIPv6UpstreamPrefixes = upstreamPrefixes;
|
||||
|
|
@ -896,7 +933,8 @@ public class IpServer extends StateMachineShim {
|
|||
}
|
||||
|
||||
private void removeRoutesFromNetwork(int netId, @NonNull final List<RouteInfo> toBeRemoved) {
|
||||
final int removalFailures = NetdUtils.removeRoutesFromNetwork(mNetd, netId, toBeRemoved);
|
||||
final int removalFailures = NetdUtils.removeRoutesFromNetwork(mNetd, netId, toBeRemoved,
|
||||
mUseRouteParcel);
|
||||
if (removalFailures > 0) {
|
||||
mLog.e("Failed to remove " + removalFailures
|
||||
+ " IPv6 routes from network " + netId + ".");
|
||||
|
|
@ -927,15 +965,14 @@ public class IpServer extends StateMachineShim {
|
|||
}
|
||||
}
|
||||
|
||||
private void addRoutesToNetwork(int netId,
|
||||
@NonNull final List<RouteInfo> toBeAdded) {
|
||||
private void addRoutesToNetwork(int netId, @NonNull final List<RouteInfo> toBeAdded) {
|
||||
// It's safe to call addInterfaceToNetwork() even if
|
||||
// the interface is already in the network.
|
||||
addInterfaceToNetwork(netId, mIfaceName);
|
||||
try {
|
||||
// Add routes from local network. Note that adding routes that
|
||||
// already exist does not cause an error (EEXIST is silently ignored).
|
||||
NetdUtils.addRoutesToNetwork(mNetd, netId, mIfaceName, toBeAdded);
|
||||
NetdUtils.addRoutesToNetwork(mNetd, netId, mIfaceName, toBeAdded, mUseRouteParcel);
|
||||
} catch (IllegalStateException e) {
|
||||
mLog.e("Failed to add IPv4/v6 routes to local table: " + e);
|
||||
return;
|
||||
|
|
@ -949,6 +986,7 @@ public class IpServer extends StateMachineShim {
|
|||
final List<RouteInfo> routesToBeRemoved =
|
||||
getLocalRoutesFor(mIfaceName, deprecatedPrefixes);
|
||||
if (mTetheringAgent == null) {
|
||||
// Routes for local network are not considered local routes.
|
||||
removeRoutesFromNetwork(LOCAL_NET_ID, routesToBeRemoved);
|
||||
}
|
||||
for (RouteInfo route : routesToBeRemoved) mLinkProperties.removeRoute(route);
|
||||
|
|
@ -1166,8 +1204,7 @@ public class IpServer extends StateMachineShim {
|
|||
|
||||
@SuppressLint("NewApi")
|
||||
private void startServingInterface() {
|
||||
if (mSupportTetheringLocalAgent && (mSupportWifiP2pGroupOwnerLocalAgent
|
||||
|| getScope() != CONNECTIVITY_SCOPE_LOCAL)) {
|
||||
if (mSupportTetheringAndP2pGoLocalAgent) {
|
||||
try {
|
||||
mTetheringAgent = mDeps.makeNetworkAgent(mContext, Looper.myLooper(), TAG,
|
||||
mInterfaceType, mLinkProperties);
|
||||
|
|
@ -1197,10 +1234,11 @@ public class IpServer extends StateMachineShim {
|
|||
20 /* maxAttempts */, 50 /* pollingIntervalMs */);
|
||||
// Activate a route to dest and IPv6 link local.
|
||||
NetdUtils.modifyRoute(mNetd, NetdUtils.ModifyOperation.ADD, LOCAL_NET_ID,
|
||||
new RouteInfo(asIpPrefix(mIpv4Address), null, mIfaceName, RTN_UNICAST));
|
||||
new RouteInfo(asIpPrefix(mIpv4Address), null, mIfaceName,
|
||||
RTN_UNICAST), mUseRouteParcel);
|
||||
NetdUtils.modifyRoute(mNetd, NetdUtils.ModifyOperation.ADD, LOCAL_NET_ID,
|
||||
new RouteInfo(new IpPrefix("fe80::/64"), null, mIfaceName,
|
||||
RTN_UNICAST));
|
||||
RTN_UNICAST), mUseRouteParcel);
|
||||
}
|
||||
} catch (RemoteException | ServiceSpecificException | IllegalStateException e) {
|
||||
mLog.e("Error Tethering", e);
|
||||
|
|
@ -1330,6 +1368,7 @@ public class IpServer extends StateMachineShim {
|
|||
final List<RouteInfo> routesToBeRemoved =
|
||||
List.of(getDirectConnectedRoute(deprecatedLinkAddress));
|
||||
if (mTetheringAgent == null) {
|
||||
// Routes for local network are not considered local routes.
|
||||
removeRoutesFromNetwork(LOCAL_NET_ID, routesToBeRemoved);
|
||||
}
|
||||
for (RouteInfo route : routesToBeRemoved) mLinkProperties.removeRoute(route);
|
||||
|
|
@ -1440,7 +1479,7 @@ public class IpServer extends StateMachineShim {
|
|||
for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
|
||||
mUpstreamIfaceSet = null;
|
||||
mBpfCoordinator.updateIpv6UpstreamInterface(IpServer.this, NO_UPSTREAM,
|
||||
Collections.emptySet());
|
||||
Collections.emptySet(), 1400);
|
||||
}
|
||||
|
||||
private void cleanupUpstreamInterface(String upstreamIface) {
|
||||
|
|
|
|||
|
|
@ -74,9 +74,9 @@ import com.android.net.module.util.InterfaceParams;
|
|||
import com.android.net.module.util.NetworkStackConstants;
|
||||
import com.android.net.module.util.SharedLog;
|
||||
import com.android.net.module.util.Struct.S32;
|
||||
import com.android.net.module.util.Struct.S64;
|
||||
import com.android.net.module.util.bpf.Tether4Key;
|
||||
import com.android.net.module.util.bpf.Tether4Value;
|
||||
import com.android.net.module.util.bpf.TetherStatsKey;
|
||||
import com.android.net.module.util.bpf.TetherStatsValue;
|
||||
import com.android.net.module.util.ip.ConntrackMonitor;
|
||||
import com.android.net.module.util.ip.ConntrackMonitor.ConntrackEventConsumer;
|
||||
|
|
@ -448,11 +448,11 @@ public class BpfCoordinator {
|
|||
}
|
||||
|
||||
/** Get stats BPF map. */
|
||||
@Nullable public IBpfMap<TetherStatsKey, TetherStatsValue> getBpfStatsMap() {
|
||||
@Nullable public IBpfMap<S32, TetherStatsValue> getBpfStatsMap() {
|
||||
if (!isAtLeastS()) return null;
|
||||
try {
|
||||
return new BpfMap<>(TETHER_STATS_MAP_PATH,
|
||||
TetherStatsKey.class, TetherStatsValue.class);
|
||||
S32.class, TetherStatsValue.class);
|
||||
} catch (ErrnoException e) {
|
||||
Log.e(TAG, "Cannot create stats map: " + e);
|
||||
return null;
|
||||
|
|
@ -460,11 +460,11 @@ public class BpfCoordinator {
|
|||
}
|
||||
|
||||
/** Get limit BPF map. */
|
||||
@Nullable public IBpfMap<TetherLimitKey, TetherLimitValue> getBpfLimitMap() {
|
||||
@Nullable public IBpfMap<S32, S64> getBpfLimitMap() {
|
||||
if (!isAtLeastS()) return null;
|
||||
try {
|
||||
return new BpfMap<>(TETHER_LIMIT_MAP_PATH,
|
||||
TetherLimitKey.class, TetherLimitValue.class);
|
||||
S32.class, S64.class);
|
||||
} catch (ErrnoException e) {
|
||||
Log.e(TAG, "Cannot create limit map: " + e);
|
||||
return null;
|
||||
|
|
@ -472,11 +472,11 @@ public class BpfCoordinator {
|
|||
}
|
||||
|
||||
/** Get dev BPF map. */
|
||||
@Nullable public IBpfMap<TetherDevKey, TetherDevValue> getBpfDevMap() {
|
||||
@Nullable public IBpfMap<S32, S32> getBpfDevMap() {
|
||||
if (!isAtLeastS()) return null;
|
||||
try {
|
||||
return new BpfMap<>(TETHER_DEV_MAP_PATH,
|
||||
TetherDevKey.class, TetherDevValue.class);
|
||||
S32.class, S32.class);
|
||||
} catch (ErrnoException e) {
|
||||
Log.e(TAG, "Cannot create dev map: " + e);
|
||||
return null;
|
||||
|
|
@ -501,6 +501,12 @@ public class BpfCoordinator {
|
|||
lastMaxSessionCount);
|
||||
}
|
||||
|
||||
/** Send a BpfCoordinatorShimInitError event. */
|
||||
public void sendBpfCoordinatorShimInitError() {
|
||||
ConnectivityStatsLog.write(ConnectivityStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED,
|
||||
ConnectivityStatsLog.CORE_NETWORKING_TERRIBLE_ERROR_OCCURRED__ERROR_TYPE__TYPE_BPF_COORDINATOR_SHIM_INIT_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DeviceConfigUtils#isTetheringFeatureEnabled
|
||||
*/
|
||||
|
|
@ -542,6 +548,7 @@ public class BpfCoordinator {
|
|||
mBpfCoordinatorShim = BpfCoordinatorShim.getBpfCoordinatorShim(deps);
|
||||
if (!mBpfCoordinatorShim.isInitialized()) {
|
||||
mLog.e("Bpf shim not initialized");
|
||||
mDeps.sendBpfCoordinatorShimInitError();
|
||||
}
|
||||
|
||||
// BPF IPv4 forwarding only supports on S+.
|
||||
|
|
@ -790,7 +797,7 @@ public class BpfCoordinator {
|
|||
*/
|
||||
private void updateAllIpv6Rules(@NonNull final IpServer ipServer,
|
||||
final InterfaceParams interfaceParams, int newUpstreamIfindex,
|
||||
@NonNull final Set<IpPrefix> newUpstreamPrefixes) {
|
||||
@NonNull final Set<IpPrefix> newUpstreamPrefixes, int pmtu) {
|
||||
if (!isUsingBpf()) return;
|
||||
|
||||
// Remove IPv6 downstream rules. Remove the old ones before adding the new rules, otherwise
|
||||
|
|
@ -816,7 +823,7 @@ public class BpfCoordinator {
|
|||
for (final IpPrefix ipPrefix : newUpstreamPrefixes) {
|
||||
addIpv6UpstreamRule(ipServer, new Ipv6UpstreamRule(
|
||||
newUpstreamIfindex, interfaceParams.index, ipPrefix,
|
||||
interfaceParams.macAddr, NULL_MAC_ADDRESS, NULL_MAC_ADDRESS));
|
||||
interfaceParams.macAddr, NULL_MAC_ADDRESS, NULL_MAC_ADDRESS, pmtu));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -958,7 +965,7 @@ public class BpfCoordinator {
|
|||
* Note that this can be only called on handler thread.
|
||||
*/
|
||||
public void updateIpv6UpstreamInterface(@NonNull final IpServer ipServer, int upstreamIfindex,
|
||||
@NonNull Set<IpPrefix> upstreamPrefixes) {
|
||||
@NonNull Set<IpPrefix> upstreamPrefixes, int pmtu) {
|
||||
if (!isUsingBpf()) return;
|
||||
|
||||
// If the upstream interface has changed, remove all rules and re-add them with the new
|
||||
|
|
@ -971,7 +978,7 @@ public class BpfCoordinator {
|
|||
final boolean upstreamSupportsBpf = checkUpstreamSupportsBpf(upstreamIfindex);
|
||||
updateAllIpv6Rules(ipServer, interfaceParams,
|
||||
getInterfaceIndexForRule(upstreamIfindex, upstreamSupportsBpf),
|
||||
upstreamPrefixes);
|
||||
upstreamPrefixes, pmtu);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1059,12 +1066,12 @@ public class BpfCoordinator {
|
|||
|
||||
// Find the rules which are related with the given client.
|
||||
mBpfCoordinatorShim.tetherOffloadRuleForEach(UPSTREAM, (k, v) -> {
|
||||
if (Arrays.equals(k.src4, clientAddr.getAddress())) {
|
||||
if (Objects.equals(k.src4, clientAddr)) {
|
||||
deleteUpstreamRuleKeys.add(k);
|
||||
}
|
||||
});
|
||||
mBpfCoordinatorShim.tetherOffloadRuleForEach(DOWNSTREAM, (k, v) -> {
|
||||
if (Arrays.equals(v.dst46, toIpv4MappedAddressBytes(clientAddr))) {
|
||||
if (Objects.equals(v.dst46, clientAddr)) {
|
||||
deleteDownstreamRuleKeys.add(k);
|
||||
upstreamIndiceSet.add((int) k.iif);
|
||||
}
|
||||
|
|
@ -1370,7 +1377,7 @@ public class BpfCoordinator {
|
|||
}
|
||||
}
|
||||
private void dumpBpfStats(@NonNull IndentingPrintWriter pw) {
|
||||
try (IBpfMap<TetherStatsKey, TetherStatsValue> map = mDeps.getBpfStatsMap()) {
|
||||
try (IBpfMap<S32, TetherStatsValue> map = mDeps.getBpfStatsMap()) {
|
||||
if (map == null) {
|
||||
pw.println("No BPF stats map");
|
||||
return;
|
||||
|
|
@ -1439,9 +1446,10 @@ public class BpfCoordinator {
|
|||
}
|
||||
|
||||
private String ipv6UpstreamRuleToString(TetherUpstream6Key key, Tether6Value value) {
|
||||
return String.format("%d(%s) [%s] [%s] -> %d(%s) %04x [%s] [%s]",
|
||||
return String.format("%d(%s) [%s] [%s] -> %d(%s) %04x [%s] [%s] %d",
|
||||
key.iif, getIfName(key.iif), key.dstMac, bytesToPrefix(key.src64), value.oif,
|
||||
getIfName(value.oif), value.ethProto, value.ethSrcMac, value.ethDstMac);
|
||||
getIfName(value.oif), value.ethProto, value.ethSrcMac, value.ethDstMac,
|
||||
value.pmtu);
|
||||
}
|
||||
|
||||
private void dumpIpv6UpstreamRules(IndentingPrintWriter pw) {
|
||||
|
|
@ -1467,9 +1475,9 @@ public class BpfCoordinator {
|
|||
} catch (UnknownHostException impossible) {
|
||||
throw new AssertionError("IP address array not valid IPv6 address!");
|
||||
}
|
||||
return String.format("%d(%s) [%s] %s -> %d(%s) %04x [%s] [%s]",
|
||||
return String.format("%d(%s) [%s] %s -> %d(%s) %04x [%s] [%s] %d",
|
||||
key.iif, getIfName(key.iif), key.dstMac, neigh6, value.oif, getIfName(value.oif),
|
||||
value.ethProto, value.ethSrcMac, value.ethDstMac);
|
||||
value.ethProto, value.ethSrcMac, value.ethDstMac, value.pmtu);
|
||||
}
|
||||
|
||||
private void dumpIpv6DownstreamRules(IndentingPrintWriter pw) {
|
||||
|
|
@ -1492,13 +1500,13 @@ public class BpfCoordinator {
|
|||
// duplicate bpf map dump code.
|
||||
private void dumpBpfForwardingRulesIpv6(IndentingPrintWriter pw) {
|
||||
pw.println("IPv6 Upstream: iif(iface) [inDstMac] [sourcePrefix] -> oif(iface) etherType "
|
||||
+ "[outSrcMac] [outDstMac]");
|
||||
+ "[outSrcMac] [outDstMac] pmtu");
|
||||
pw.increaseIndent();
|
||||
dumpIpv6UpstreamRules(pw);
|
||||
pw.decreaseIndent();
|
||||
|
||||
pw.println("IPv6 Downstream: iif(iface) [inDstMac] neigh6 -> oif(iface) etherType "
|
||||
+ "[outSrcMac] [outDstMac]");
|
||||
+ "[outSrcMac] [outDstMac] pmtu");
|
||||
pw.increaseIndent();
|
||||
dumpIpv6DownstreamRules(pw);
|
||||
pw.decreaseIndent();
|
||||
|
|
@ -1522,7 +1530,7 @@ public class BpfCoordinator {
|
|||
// expected argument order.
|
||||
// TODO: dump downstream4 map.
|
||||
if (CollectionUtils.contains(args, DUMPSYS_RAWMAP_ARG_STATS)) {
|
||||
try (IBpfMap<TetherStatsKey, TetherStatsValue> statsMap = mDeps.getBpfStatsMap()) {
|
||||
try (IBpfMap<S32, TetherStatsValue> statsMap = mDeps.getBpfStatsMap()) {
|
||||
BpfDump.dumpRawMap(statsMap, pw);
|
||||
} catch (IOException e) {
|
||||
pw.println("Error dumping stats map: " + e);
|
||||
|
|
@ -1552,20 +1560,15 @@ public class BpfCoordinator {
|
|||
Tether4Key key, Tether4Value value) {
|
||||
final String src4, public4, dst4;
|
||||
final int publicPort;
|
||||
try {
|
||||
src4 = InetAddress.getByAddress(key.src4).getHostAddress();
|
||||
if (downstream) {
|
||||
public4 = InetAddress.getByAddress(key.dst4).getHostAddress();
|
||||
publicPort = key.dstPort;
|
||||
} else {
|
||||
public4 = InetAddress.getByAddress(value.src46).getHostAddress();
|
||||
publicPort = value.srcPort;
|
||||
}
|
||||
dst4 = InetAddress.getByAddress(value.dst46).getHostAddress();
|
||||
} catch (UnknownHostException impossible) {
|
||||
throw new AssertionError("IP address array not valid IPv4 address!");
|
||||
src4 = key.src4.getHostAddress();
|
||||
if (downstream) {
|
||||
public4 = key.dst4.getHostAddress();
|
||||
publicPort = key.dstPort;
|
||||
} else {
|
||||
public4 = value.src46.getHostAddress();
|
||||
publicPort = value.srcPort;
|
||||
}
|
||||
|
||||
dst4 = value.dst46.getHostAddress();
|
||||
final String ageStr = (value.lastUsed == 0) ? "-"
|
||||
: String.format("%dms", (now - value.lastUsed) / 1_000_000);
|
||||
return String.format("%s [%s] %d(%s) %s:%d -> %d(%s) %s:%d -> %s:%d [%s] %d %s",
|
||||
|
|
@ -1636,7 +1639,7 @@ public class BpfCoordinator {
|
|||
}
|
||||
|
||||
private void dumpDevmap(@NonNull IndentingPrintWriter pw) {
|
||||
try (IBpfMap<TetherDevKey, TetherDevValue> map = mDeps.getBpfDevMap()) {
|
||||
try (IBpfMap<S32, S32> map = mDeps.getBpfDevMap()) {
|
||||
if (map == null) {
|
||||
pw.println("No devmap support");
|
||||
return;
|
||||
|
|
@ -1651,8 +1654,8 @@ public class BpfCoordinator {
|
|||
// Only get upstream interface name. Just do the best to make the index readable.
|
||||
// TODO: get downstream interface name because the index is either upstream or
|
||||
// downstream interface in dev map.
|
||||
pw.println(String.format("%d (%s) -> %d (%s)", k.ifIndex, getIfName(k.ifIndex),
|
||||
v.ifIndex, getIfName(v.ifIndex)));
|
||||
pw.println(String.format("%d (%s) -> %d (%s)", k.val, getIfName(k.val),
|
||||
v.val, getIfName(v.val)));
|
||||
});
|
||||
} catch (ErrnoException | IOException e) {
|
||||
pw.println("Error dumping dev map: " + e);
|
||||
|
|
@ -1692,7 +1695,7 @@ public class BpfCoordinator {
|
|||
// |field |oif |ethDst|ethSrc|ethPro|pmtu |
|
||||
// | | |mac |mac |to | |
|
||||
// +------+------+------+------+------+------+
|
||||
// |value |upstre|-- |-- |ETH_P_|1500 |
|
||||
// |value |upstre|-- |-- |ETH_P_|pmtu |
|
||||
// | |am | | |IP | |
|
||||
// +------+------+------+------+------+------+
|
||||
//
|
||||
|
|
@ -1706,16 +1709,19 @@ public class BpfCoordinator {
|
|||
public final MacAddress outSrcMac;
|
||||
@NonNull
|
||||
public final MacAddress outDstMac;
|
||||
public final int pmtu;
|
||||
|
||||
public Ipv6UpstreamRule(int upstreamIfindex, int downstreamIfindex,
|
||||
@NonNull IpPrefix sourcePrefix, @NonNull MacAddress inDstMac,
|
||||
@NonNull MacAddress outSrcMac, @NonNull MacAddress outDstMac) {
|
||||
@NonNull MacAddress outSrcMac, @NonNull MacAddress outDstMac,
|
||||
int pmtu) {
|
||||
this.upstreamIfindex = upstreamIfindex;
|
||||
this.downstreamIfindex = downstreamIfindex;
|
||||
this.sourcePrefix = sourcePrefix;
|
||||
this.inDstMac = inDstMac;
|
||||
this.outSrcMac = outSrcMac;
|
||||
this.outDstMac = outDstMac;
|
||||
this.pmtu = pmtu;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1732,8 +1738,7 @@ public class BpfCoordinator {
|
|||
*/
|
||||
@NonNull
|
||||
public Tether6Value makeTether6Value() {
|
||||
return new Tether6Value(upstreamIfindex, outDstMac, outSrcMac, ETH_P_IPV6,
|
||||
NetworkStackConstants.ETHER_MTU);
|
||||
return new Tether6Value(upstreamIfindex, outDstMac, outSrcMac, ETH_P_IPV6, pmtu);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -2032,20 +2037,6 @@ public class BpfCoordinator {
|
|||
return null;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@VisibleForTesting
|
||||
static byte[] toIpv4MappedAddressBytes(Inet4Address ia4) {
|
||||
final byte[] addr4 = ia4.getAddress();
|
||||
final byte[] addr6 = new byte[16];
|
||||
addr6[10] = (byte) 0xff;
|
||||
addr6[11] = (byte) 0xff;
|
||||
addr6[12] = addr4[0];
|
||||
addr6[13] = addr4[1];
|
||||
addr6[14] = addr4[2];
|
||||
addr6[15] = addr4[3];
|
||||
return addr6;
|
||||
}
|
||||
|
||||
// TODO: parse CTA_PROTOINFO of conntrack event in ConntrackMonitor. For TCP, only add rules
|
||||
// while TCP status is established.
|
||||
@VisibleForTesting
|
||||
|
|
@ -2111,16 +2102,16 @@ public class BpfCoordinator {
|
|||
private Tether4Key makeTetherUpstream4Key(
|
||||
@NonNull ConntrackEvent e, @NonNull ClientInfo c) {
|
||||
return new Tether4Key(c.downstreamIfindex, c.downstreamMac,
|
||||
e.tupleOrig.protoNum, e.tupleOrig.srcIp.getAddress(),
|
||||
e.tupleOrig.dstIp.getAddress(), e.tupleOrig.srcPort, e.tupleOrig.dstPort);
|
||||
e.tupleOrig.protoNum, e.tupleOrig.srcIp, e.tupleOrig.dstIp,
|
||||
e.tupleOrig.srcPort, e.tupleOrig.dstPort);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private Tether4Key makeTetherDownstream4Key(
|
||||
@NonNull ConntrackEvent e, @NonNull ClientInfo c, int upstreamIndex) {
|
||||
return new Tether4Key(upstreamIndex, NULL_MAC_ADDRESS /* dstMac (rawip) */,
|
||||
e.tupleReply.protoNum, e.tupleReply.srcIp.getAddress(),
|
||||
e.tupleReply.dstIp.getAddress(), e.tupleReply.srcPort, e.tupleReply.dstPort);
|
||||
e.tupleReply.protoNum, e.tupleReply.srcIp, e.tupleReply.dstIp,
|
||||
e.tupleReply.srcPort, e.tupleReply.dstPort);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
|
|
@ -2129,8 +2120,7 @@ public class BpfCoordinator {
|
|||
return new Tether4Value(upstreamInfo.ifIndex,
|
||||
NULL_MAC_ADDRESS /* ethDstMac (rawip) */,
|
||||
NULL_MAC_ADDRESS /* ethSrcMac (rawip) */, ETH_P_IP,
|
||||
upstreamInfo.mtu, toIpv4MappedAddressBytes(e.tupleReply.dstIp),
|
||||
toIpv4MappedAddressBytes(e.tupleReply.srcIp), e.tupleReply.dstPort,
|
||||
upstreamInfo.mtu, e.tupleReply.dstIp, e.tupleReply.srcIp, e.tupleReply.dstPort,
|
||||
e.tupleReply.srcPort, 0 /* lastUsed, filled by bpf prog only */);
|
||||
}
|
||||
|
||||
|
|
@ -2139,8 +2129,7 @@ public class BpfCoordinator {
|
|||
@NonNull ClientInfo c, @NonNull UpstreamInfo upstreamInfo) {
|
||||
return new Tether4Value(c.downstreamIfindex,
|
||||
c.clientMac, c.downstreamMac, ETH_P_IP, upstreamInfo.mtu,
|
||||
toIpv4MappedAddressBytes(e.tupleOrig.dstIp),
|
||||
toIpv4MappedAddressBytes(e.tupleOrig.srcIp),
|
||||
e.tupleOrig.dstIp, e.tupleOrig.srcIp,
|
||||
e.tupleOrig.dstPort, e.tupleOrig.srcPort,
|
||||
0 /* lastUsed, filled by bpf prog only */);
|
||||
}
|
||||
|
|
@ -2465,17 +2454,6 @@ public class BpfCoordinator {
|
|||
return Math.max(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS, configInterval);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private Inet4Address parseIPv4Address(byte[] addrBytes) {
|
||||
try {
|
||||
final InetAddress ia = Inet4Address.getByAddress(addrBytes);
|
||||
if (ia instanceof Inet4Address) return (Inet4Address) ia;
|
||||
} catch (UnknownHostException e) {
|
||||
mLog.e("Failed to parse IPv4 address: " + e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Update CTA_TUPLE_ORIG timeout for a given conntrack entry. Note that there will also be
|
||||
// coming a conntrack event to notify updated timeout.
|
||||
private void updateConntrackTimeout(byte proto, Inet4Address src4, short srcPort,
|
||||
|
|
@ -2532,9 +2510,8 @@ public class BpfCoordinator {
|
|||
// both directions for TCP.
|
||||
mBpfCoordinatorShim.tetherOffloadRuleForEach(UPSTREAM, (k, v) -> {
|
||||
if ((now - v.lastUsed) / 1_000_000 < CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS) {
|
||||
updateConntrackTimeout((byte) k.l4proto,
|
||||
parseIPv4Address(k.src4), (short) k.srcPort,
|
||||
parseIPv4Address(k.dst4), (short) k.dstPort);
|
||||
updateConntrackTimeout((byte) k.l4proto, k.src4, (short) k.srcPort, k.dst4,
|
||||
(short) k.dstPort);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -2543,9 +2520,8 @@ public class BpfCoordinator {
|
|||
// which is opposite direction for downstream map value.
|
||||
mBpfCoordinatorShim.tetherOffloadRuleForEach(DOWNSTREAM, (k, v) -> {
|
||||
if ((now - v.lastUsed) / 1_000_000 < CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS) {
|
||||
updateConntrackTimeout((byte) k.l4proto,
|
||||
parseIPv4Address(v.dst46), (short) v.dstPort,
|
||||
parseIPv4Address(v.src46), (short) v.srcPort);
|
||||
updateConntrackTimeout((byte) k.l4proto, (Inet4Address) v.dst46, (short) v.dstPort,
|
||||
(Inet4Address) v.src46, (short) v.srcPort);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ import java.io.IOException;
|
|||
/**
|
||||
* The classes and the methods for BPF utilization.
|
||||
*
|
||||
* {@hide}
|
||||
* @hide
|
||||
*/
|
||||
public class BpfUtils {
|
||||
static {
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import static android.net.TetheringManager.TETHERING_WIFI;
|
|||
import static android.net.TetheringManager.TETHER_ERROR_ENTITLEMENT_UNKNOWN;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
|
||||
import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED;
|
||||
import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
|
||||
|
||||
import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
|
||||
import static com.android.networkstack.apishim.ConstantsShim.ACTION_TETHER_UNSUPPORTED_CARRIER_UI;
|
||||
|
|
@ -448,7 +449,8 @@ public class EntitlementManager {
|
|||
return TETHERING_PROVISIONING_CARRIER_UNSUPPORT;
|
||||
}
|
||||
|
||||
if (!config.isCarrierConfigAffirmsEntitlementCheckRequired) {
|
||||
if (!config.isCarrierConfigAffirmsEntitlementCheckRequired
|
||||
|| INVALID_SUBSCRIPTION_ID == config.activeDataSubId) {
|
||||
return TETHERING_PROVISIONING_NOT_REQUIRED;
|
||||
}
|
||||
return (config.provisioningApp.length == 2)
|
||||
|
|
|
|||
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2020 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.networkstack.tethering;
|
||||
|
||||
import com.android.net.module.util.Struct;
|
||||
import com.android.net.module.util.Struct.Field;
|
||||
import com.android.net.module.util.Struct.Type;
|
||||
|
||||
/** The value of BpfMap which is used for tethering per-interface limit. */
|
||||
public class TetherLimitValue extends Struct {
|
||||
// Use the signed long variable to store the int64 limit on limit BPF map.
|
||||
// S64 is enough for each interface limit even at 5Gbps for ~468 years.
|
||||
// 2^63 / (5 * 1000 * 1000 * 1000) * 8 / 86400 / 365 = 468.
|
||||
// Note that QUOTA_UNLIMITED (-1) indicates there is no limit.
|
||||
@Field(order = 0, type = Type.S64)
|
||||
public final long limit;
|
||||
|
||||
public TetherLimitValue(final long limit) {
|
||||
this.limit = limit;
|
||||
}
|
||||
}
|
||||
|
|
@ -138,9 +138,8 @@ public abstract class TetheringDependencies {
|
|||
IBinder binder;
|
||||
if (!SdkLevel.isAtLeastS()) {
|
||||
final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
|
||||
binder =
|
||||
new RoutingCoordinatorService(
|
||||
getINetd(context, log), cm::getAllNetworks, context);
|
||||
binder = new RoutingCoordinatorService(getINetd(context, log), cm::getAllNetworks,
|
||||
context, false /* bluetoothTetheringUseRandomAddress */);
|
||||
} else {
|
||||
binder = ConnectivityInternalApiUtil.getRoutingCoordinator(context);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,15 +61,8 @@ public class TetheringFeatureFlags {
|
|||
public static final String TETHER_ACTIVE_SESSIONS_METRICS = "tether_active_sessions_metrics";
|
||||
|
||||
/**
|
||||
* A feature flag to control whether the tethering local network agent should be enabled.
|
||||
* Disabled by default.
|
||||
* A kill switch to control whether the TETHERING_AND_P2P_GO_LOCAL_AGENT is enabled.
|
||||
*/
|
||||
public static final String TETHERING_LOCAL_NETWORK_AGENT = "tethering_local_network_agent";
|
||||
|
||||
/**
|
||||
* A feature flag to control whether the Wifi P2P Group Owner local network agent
|
||||
* should be enabled. Disabled by default. This depends on TETHERING_LOCAL_AGENT
|
||||
* and will not be enabled if that flag is off.
|
||||
*/
|
||||
public static final String WIFIP2PGO_LOCAL_NETWORK_AGENT = "wifip2pgo_local_network_agent";
|
||||
public static final String TETHERING_AND_P2P_GO_LOCAL_AGENT =
|
||||
"tethering_and_p2p_go_local_agent";
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue