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
|
yuyanghuang@google.com
|
||||||
|
|
||||||
martinwu@google.com #{LAST_RESORT_SUGGESTION}
|
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
|
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
|
# For cherry-picks of CLs that are already merged in aosp/master, flaky test
|
||||||
# fixes, or no-op refactors.
|
# 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}
|
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}
|
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"
|
"exclude-annotation": "com.android.testutils.NetworkStackModuleTest"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CtsHostsideNetworkTests",
|
||||||
|
"options": [
|
||||||
|
{
|
||||||
|
"exclude-annotation": "androidx.test.filters.RequiresDevice"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"captiveportal-networkstack-mainline-presubmit": [
|
"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
|
// Test with APK modules only, in cases where APEX is not supported, or the other modules
|
||||||
// were simply not updated
|
// were simply not updated
|
||||||
{
|
{
|
||||||
|
|
@ -435,12 +435,23 @@
|
||||||
"name": "CtsNetTestCasesUpdateStatsPermission"
|
"name": "CtsNetTestCasesUpdateStatsPermission"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"tv-presubmit": [
|
"hsum-presubmit": [
|
||||||
{
|
{
|
||||||
"name": "CtsNetTestCases"
|
"name": "CtsNetTestCases"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "CtsNativeNetTestCases"
|
"name": "CtsNativeNetDnsTestCases"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CtsNetTestCasesInternetPermission"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "CtsNetTestCasesUpdateStatsPermission"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"tv-presubmit": [
|
||||||
|
{
|
||||||
|
"name": "CtsNetTestCases"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "CtsNativeNetDnsTestCases"
|
"name": "CtsNativeNetDnsTestCases"
|
||||||
|
|
@ -471,5 +482,18 @@
|
||||||
{
|
{
|
||||||
"path": "vendor/xts/gts-tests/hostsidetests/networkstack"
|
"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 {
|
java_defaults {
|
||||||
name: "TetheringApiLevel",
|
name: "TetheringApiLevel",
|
||||||
sdk_version: "module_current",
|
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 {
|
java_defaults {
|
||||||
|
|
@ -65,6 +68,8 @@ java_defaults {
|
||||||
"androidx.annotation_annotation",
|
"androidx.annotation_annotation",
|
||||||
"connectivity-net-module-utils-bpf",
|
"connectivity-net-module-utils-bpf",
|
||||||
"com.android.net.flags-aconfig-java",
|
"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-build",
|
||||||
"modules-utils-statemachine",
|
"modules-utils-statemachine",
|
||||||
"networkstack-client",
|
"networkstack-client",
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,7 @@ apex {
|
||||||
"libservice-connectivity",
|
"libservice-connectivity",
|
||||||
"libservice-thread-jni",
|
"libservice-thread-jni",
|
||||||
"libandroid_net_connectivity_com_android_net_module_util_jni",
|
"libandroid_net_connectivity_com_android_net_module_util_jni",
|
||||||
|
"libandroid_net_connectivity_com_android_net_module_util_jni_CommonConnectivityJni",
|
||||||
],
|
],
|
||||||
native_shared_libs: [
|
native_shared_libs: [
|
||||||
"libcom.android.tethering.dns_helper",
|
"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;
|
||||||
import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
|
import com.android.net.module.util.IBpfMap.ThrowingBiConsumer;
|
||||||
import com.android.net.module.util.SharedLog;
|
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.Tether4Key;
|
||||||
import com.android.net.module.util.bpf.Tether4Value;
|
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.bpf.TetherStatsValue;
|
||||||
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
|
import com.android.networkstack.tethering.BpfCoordinator.Dependencies;
|
||||||
import com.android.networkstack.tethering.BpfCoordinator.Ipv6DownstreamRule;
|
import com.android.networkstack.tethering.BpfCoordinator.Ipv6DownstreamRule;
|
||||||
import com.android.networkstack.tethering.BpfCoordinator.Ipv6UpstreamRule;
|
import com.android.networkstack.tethering.BpfCoordinator.Ipv6UpstreamRule;
|
||||||
import com.android.networkstack.tethering.BpfUtils;
|
import com.android.networkstack.tethering.BpfUtils;
|
||||||
import com.android.networkstack.tethering.Tether6Value;
|
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.TetherDownstream6Key;
|
||||||
import com.android.networkstack.tethering.TetherLimitKey;
|
|
||||||
import com.android.networkstack.tethering.TetherLimitValue;
|
|
||||||
import com.android.networkstack.tethering.TetherUpstream6Key;
|
import com.android.networkstack.tethering.TetherUpstream6Key;
|
||||||
|
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
|
|
@ -85,15 +82,15 @@ public class BpfCoordinatorShimImpl
|
||||||
|
|
||||||
// BPF map of tethering statistics of the upstream interface since tethering startup.
|
// BPF map of tethering statistics of the upstream interface since tethering startup.
|
||||||
@Nullable
|
@Nullable
|
||||||
private final IBpfMap<TetherStatsKey, TetherStatsValue> mBpfStatsMap;
|
private final IBpfMap<S32, TetherStatsValue> mBpfStatsMap;
|
||||||
|
|
||||||
// BPF map of per-interface quota for tethering offload.
|
// BPF map of per-interface quota for tethering offload.
|
||||||
@Nullable
|
@Nullable
|
||||||
private final IBpfMap<TetherLimitKey, TetherLimitValue> mBpfLimitMap;
|
private final IBpfMap<S32, S64> mBpfLimitMap;
|
||||||
|
|
||||||
// BPF map of interface index mapping for XDP.
|
// BPF map of interface index mapping for XDP.
|
||||||
@Nullable
|
@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
|
// 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
|
// reducing the BPF map iteration query. The count is increased or decreased when the rule is
|
||||||
|
|
@ -252,7 +249,7 @@ public class BpfCoordinatorShimImpl
|
||||||
try {
|
try {
|
||||||
// The reported tether stats are total data usage for all currently-active upstream
|
// The reported tether stats are total data usage for all currently-active upstream
|
||||||
// interfaces since tethering start.
|
// 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) {
|
} catch (ErrnoException e) {
|
||||||
mLog.e("Fail to fetch tethering stats from BPF map: ", e);
|
mLog.e("Fail to fetch tethering stats from BPF map: ", e);
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -269,7 +266,7 @@ public class BpfCoordinatorShimImpl
|
||||||
TetherStatsValue statsValue = null;
|
TetherStatsValue statsValue = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
statsValue = mBpfStatsMap.getValue(new TetherStatsKey(ifIndex));
|
statsValue = mBpfStatsMap.getValue(new S32(ifIndex));
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
// The BpfMap#getValue doesn't throw an errno ENOENT exception. Catch other error
|
// The BpfMap#getValue doesn't throw an errno ENOENT exception. Catch other error
|
||||||
// while trying to get stats entry.
|
// while trying to get stats entry.
|
||||||
|
|
@ -287,7 +284,7 @@ public class BpfCoordinatorShimImpl
|
||||||
// This function is the *only* thing that can create entries.
|
// This function is the *only* thing that can create entries.
|
||||||
// BpfMap#insertEntry use BPF_NOEXIST to create the entry. The entry is created
|
// BpfMap#insertEntry use BPF_NOEXIST to create the entry. The entry is created
|
||||||
// if and only if it doesn't exist.
|
// 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 /* rxPackets */, 0 /* rxBytes */, 0 /* rxErrors */, 0 /* txPackets */,
|
||||||
0 /* txBytes */, 0 /* txErrors */));
|
0 /* txBytes */, 0 /* txErrors */));
|
||||||
} catch (ErrnoException | IllegalArgumentException e) {
|
} catch (ErrnoException | IllegalArgumentException e) {
|
||||||
|
|
@ -305,7 +302,7 @@ public class BpfCoordinatorShimImpl
|
||||||
if (newLimit < rxBytes + txBytes) newLimit = QUOTA_UNLIMITED;
|
if (newLimit < rxBytes + txBytes) newLimit = QUOTA_UNLIMITED;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mBpfLimitMap.updateEntry(new TetherLimitKey(ifIndex), new TetherLimitValue(newLimit));
|
mBpfLimitMap.updateEntry(new S32(ifIndex), new S64(newLimit));
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
mLog.e("Fail to set quota " + quotaBytes + " for interface index " + ifIndex + ": ", e);
|
mLog.e("Fail to set quota " + quotaBytes + " for interface index " + ifIndex + ": ", e);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -331,7 +328,7 @@ public class BpfCoordinatorShimImpl
|
||||||
|
|
||||||
TetherStatsValue statsValue = null;
|
TetherStatsValue statsValue = null;
|
||||||
try {
|
try {
|
||||||
statsValue = mBpfStatsMap.getValue(new TetherStatsKey(ifIndex));
|
statsValue = mBpfStatsMap.getValue(new S32(ifIndex));
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
mLog.e("Could not get stats entry for interface index " + ifIndex + ": ", e);
|
mLog.e("Could not get stats entry for interface index " + ifIndex + ": ", e);
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -343,14 +340,14 @@ public class BpfCoordinatorShimImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mBpfStatsMap.deleteEntry(new TetherStatsKey(ifIndex));
|
mBpfStatsMap.deleteEntry(new S32(ifIndex));
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
mLog.e("Could not delete stats entry for interface index " + ifIndex + ": ", e);
|
mLog.e("Could not delete stats entry for interface index " + ifIndex + ": ", e);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
mBpfLimitMap.deleteEntry(new TetherLimitKey(ifIndex));
|
mBpfLimitMap.deleteEntry(new S32(ifIndex));
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
mLog.e("Could not delete limit for interface index " + ifIndex + ": ", e);
|
mLog.e("Could not delete limit for interface index " + ifIndex + ": ", e);
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -470,7 +467,7 @@ public class BpfCoordinatorShimImpl
|
||||||
@Override
|
@Override
|
||||||
public boolean addDevMap(int ifIndex) {
|
public boolean addDevMap(int ifIndex) {
|
||||||
try {
|
try {
|
||||||
mBpfDevMap.updateEntry(new TetherDevKey(ifIndex), new TetherDevValue(ifIndex));
|
mBpfDevMap.updateEntry(new S32(ifIndex), new S32(ifIndex));
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
mLog.e("Could not add interface " + ifIndex + ": " + e);
|
mLog.e("Could not add interface " + ifIndex + ": " + e);
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -481,7 +478,7 @@ public class BpfCoordinatorShimImpl
|
||||||
@Override
|
@Override
|
||||||
public boolean removeDevMap(int ifIndex) {
|
public boolean removeDevMap(int ifIndex) {
|
||||||
try {
|
try {
|
||||||
mBpfDevMap.deleteEntry(new TetherDevKey(ifIndex));
|
mBpfDevMap.deleteEntry(new S32(ifIndex));
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
mLog.e("Could not delete interface " + ifIndex + ": " + e);
|
mLog.e("Could not delete interface " + ifIndex + ": " + e);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,9 @@ java_sdk_library {
|
||||||
// Using for test only
|
// Using for test only
|
||||||
"//cts/tests/netlegacy22.api",
|
"//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",
|
"//cts/tests/tests/vcn",
|
||||||
|
"//packages/modules/Connectivity/Vcn/tests:__subpackages__",
|
||||||
|
|
||||||
"//external/sl4a:__subpackages__",
|
"//external/sl4a:__subpackages__",
|
||||||
"//frameworks/base/core/tests/bandwidthtests",
|
"//frameworks/base/core/tests/bandwidthtests",
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ package android.net;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Listener interface allowing objects to listen to various module event.
|
* Listener interface allowing objects to listen to various module event.
|
||||||
* {@hide}
|
* @hide
|
||||||
*/
|
*/
|
||||||
oneway interface IIntResultListener {
|
oneway interface IIntResultListener {
|
||||||
void onResult(int resultCode);
|
void onResult(int resultCode);
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ import android.net.TetheringInterface;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Status details for tethering downstream interfaces.
|
* Status details for tethering downstream interfaces.
|
||||||
* {@hide}
|
* @hide
|
||||||
*/
|
*/
|
||||||
parcelable TetherStatesParcel {
|
parcelable TetherStatesParcel {
|
||||||
TetheringInterface[] availableList;
|
TetheringInterface[] availableList;
|
||||||
|
|
|
||||||
|
|
@ -381,7 +381,7 @@ public class TetheringManager {
|
||||||
* @param context Context for the manager.
|
* @param context Context for the manager.
|
||||||
* @param connectorSupplier Supplier for the manager connector; may return null while the
|
* @param connectorSupplier Supplier for the manager connector; may return null while the
|
||||||
* service is not connected.
|
* service is not connected.
|
||||||
* {@hide}
|
* @hide
|
||||||
*/
|
*/
|
||||||
@SystemApi(client = MODULE_LIBRARIES)
|
@SystemApi(client = MODULE_LIBRARIES)
|
||||||
public TetheringManager(@NonNull final Context context,
|
public TetheringManager(@NonNull final Context context,
|
||||||
|
|
@ -574,7 +574,7 @@ public class TetheringManager {
|
||||||
* already released.
|
* already released.
|
||||||
* 2. This is not synchronous, so it's not useful to use try-with-resources.
|
* 2. This is not synchronous, so it's not useful to use try-with-resources.
|
||||||
*
|
*
|
||||||
* {@hide}
|
* @hide
|
||||||
*/
|
*/
|
||||||
@SystemApi(client = MODULE_LIBRARIES)
|
@SystemApi(client = MODULE_LIBRARIES)
|
||||||
@SuppressLint("NotCloseable")
|
@SuppressLint("NotCloseable")
|
||||||
|
|
@ -588,7 +588,7 @@ public class TetheringManager {
|
||||||
/**
|
/**
|
||||||
* Callback for requestTetheredInterface.
|
* Callback for requestTetheredInterface.
|
||||||
*
|
*
|
||||||
* {@hide}
|
* @hide
|
||||||
*/
|
*/
|
||||||
@SystemApi(client = MODULE_LIBRARIES)
|
@SystemApi(client = MODULE_LIBRARIES)
|
||||||
public interface TetheredInterfaceCallback {
|
public interface TetheredInterfaceCallback {
|
||||||
|
|
@ -694,7 +694,7 @@ public class TetheringManager {
|
||||||
* @param iface the interface name to tether.
|
* @param iface the interface name to tether.
|
||||||
* @return error a {@code TETHER_ERROR} value indicating success or failure type
|
* @return error a {@code TETHER_ERROR} value indicating success or failure type
|
||||||
*
|
*
|
||||||
* {@hide}
|
* @hide
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@SystemApi(client = MODULE_LIBRARIES)
|
@SystemApi(client = MODULE_LIBRARIES)
|
||||||
|
|
@ -729,7 +729,7 @@ public class TetheringManager {
|
||||||
* On SDK versions after {@link Build.VERSION_CODES.VANILLA_ICE_CREAM}, this will
|
* On SDK versions after {@link Build.VERSION_CODES.VANILLA_ICE_CREAM}, this will
|
||||||
* throw an UnsupportedOperationException.
|
* throw an UnsupportedOperationException.
|
||||||
*
|
*
|
||||||
* {@hide}
|
* @hide
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@SystemApi(client = MODULE_LIBRARIES)
|
@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
|
* used and an entitlement check is needed, downstream USB tethering will be enabled but will
|
||||||
* not have any upstream.
|
* not have any upstream.
|
||||||
*
|
*
|
||||||
* {@hide}
|
* @hide
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@SystemApi(client = MODULE_LIBRARIES)
|
@SystemApi(client = MODULE_LIBRARIES)
|
||||||
|
|
@ -1553,7 +1553,7 @@ public class TetheringManager {
|
||||||
* Helper function of #requestLatestTetheringEntitlementResult to remain backwards compatible
|
* Helper function of #requestLatestTetheringEntitlementResult to remain backwards compatible
|
||||||
* with ConnectivityManager#getLatestTetheringEntitlementResult
|
* with ConnectivityManager#getLatestTetheringEntitlementResult
|
||||||
*
|
*
|
||||||
* {@hide}
|
* @hide
|
||||||
*/
|
*/
|
||||||
// TODO: improve the usage of ResultReceiver, b/145096122
|
// TODO: improve the usage of ResultReceiver, b/145096122
|
||||||
@SystemApi(client = MODULE_LIBRARIES)
|
@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 {
|
namespace android {
|
||||||
|
|
||||||
int register_com_android_net_module_util_BpfMap(JNIEnv* env, char const* class_name);
|
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_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_BpfCoordinator(JNIEnv* env);
|
||||||
int register_com_android_networkstack_tethering_util_TetheringUtils(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,
|
if (register_com_android_net_module_util_BpfMap(env,
|
||||||
"com/android/networkstack/tethering/util/BpfMap") < 0) return JNI_ERR;
|
"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,
|
if (register_com_android_net_module_util_TcUtils(env,
|
||||||
"com/android/networkstack/tethering/util/TcUtils") < 0) return JNI_ERR;
|
"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.net.util.NetworkConstants.asByte;
|
||||||
import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
|
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.Inet4AddressUtils.intToInet4AddressHTH;
|
||||||
import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
|
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.TetheringConfiguration.USE_SYNC_SM;
|
||||||
import static com.android.networkstack.tethering.TetheringFeatureFlags.TETHERING_LOCAL_NETWORK_AGENT;
|
import static com.android.networkstack.tethering.TetheringFeatureFlags.TETHERING_AND_P2P_GO_LOCAL_AGENT;
|
||||||
import static com.android.networkstack.tethering.TetheringFeatureFlags.WIFIP2PGO_LOCAL_NETWORK_AGENT;
|
|
||||||
import static com.android.networkstack.tethering.util.PrefixUtils.asIpPrefix;
|
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.TetheringMessageBase.BASE_IPSERVER;
|
||||||
import static com.android.networkstack.tethering.util.TetheringUtils.getTransportTypeForTetherableType;
|
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.InterfaceParams;
|
||||||
import com.android.net.module.util.NetdUtils;
|
import com.android.net.module.util.NetdUtils;
|
||||||
import com.android.net.module.util.RoutingCoordinatorManager;
|
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.SharedLog;
|
||||||
import com.android.net.module.util.SyncStateMachine.StateInfo;
|
import com.android.net.module.util.SyncStateMachine.StateInfo;
|
||||||
import com.android.net.module.util.ip.InterfaceController;
|
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.InterfaceSet;
|
||||||
import com.android.networkstack.tethering.util.PrefixUtils;
|
import com.android.networkstack.tethering.util.PrefixUtils;
|
||||||
import com.android.networkstack.tethering.util.StateMachineShim;
|
import com.android.networkstack.tethering.util.StateMachineShim;
|
||||||
|
import com.android.tethering.mainline.beta.Flags;
|
||||||
|
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
import java.net.Inet6Address;
|
import java.net.Inet6Address;
|
||||||
|
|
@ -218,10 +220,24 @@ public class IpServer extends StateMachineShim {
|
||||||
DhcpServerCallbacks cb);
|
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) {
|
public boolean isTetheringFeatureNotChickenedOut(@NonNull Context context,
|
||||||
return DeviceConfigUtils.isTetheringFeatureEnabled(context, name);
|
@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. */
|
/** Create a NetworkAgent instance to be used by IpServer. */
|
||||||
|
|
@ -288,6 +304,7 @@ public class IpServer extends StateMachineShim {
|
||||||
private final boolean mUsingLegacyDhcp;
|
private final boolean mUsingLegacyDhcp;
|
||||||
private final int mP2pLeasesSubnetPrefixLength;
|
private final int mP2pLeasesSubnetPrefixLength;
|
||||||
private final boolean mIsWifiP2pDedicatedIpEnabled;
|
private final boolean mIsWifiP2pDedicatedIpEnabled;
|
||||||
|
private final boolean mUseRouteParcel;
|
||||||
|
|
||||||
private final Dependencies mDeps;
|
private final Dependencies mDeps;
|
||||||
|
|
||||||
|
|
@ -335,8 +352,8 @@ public class IpServer extends StateMachineShim {
|
||||||
private final Handler mHandler;
|
private final Handler mHandler;
|
||||||
private final Context mContext;
|
private final Context mContext;
|
||||||
|
|
||||||
private final boolean mSupportTetheringLocalAgent;
|
// Whether to enable tethering and Wi-Fi P2p Group Owner mode local network agent.
|
||||||
private final boolean mSupportWifiP2pGroupOwnerLocalAgent;
|
private final boolean mSupportTetheringAndP2pGoLocalAgent;
|
||||||
|
|
||||||
// This will be null if the TetheredState is not entered or feature not supported.
|
// This will be null if the TetheredState is not entered or feature not supported.
|
||||||
// This will be only accessed from the IpServer handler thread.
|
// This will be only accessed from the IpServer handler thread.
|
||||||
|
|
@ -381,11 +398,21 @@ public class IpServer extends StateMachineShim {
|
||||||
mLastError = TETHER_ERROR_NO_ERROR;
|
mLastError = TETHER_ERROR_NO_ERROR;
|
||||||
mServingMode = STATE_AVAILABLE;
|
mServingMode = STATE_AVAILABLE;
|
||||||
|
|
||||||
// Tethering network agent is supported on V+, and will be rolled out gradually.
|
// Determines support for the Tethering/P2P GO local network agent. This feature is
|
||||||
mSupportTetheringLocalAgent = SdkLevel.isAtLeastV()
|
// gated on Android V+ because it requires NET_CAPABILITY_LOCAL_NETWORK.
|
||||||
&& mDeps.isFeatureEnabled(mContext, TETHERING_LOCAL_NETWORK_AGENT);
|
// For 25Q4+, it is enabled by default with a kill switch to prevent impacting
|
||||||
mSupportWifiP2pGroupOwnerLocalAgent = mSupportTetheringLocalAgent
|
// existing devices if issues arise. For older V+ devices, rollout is controlled
|
||||||
&& mDeps.isFeatureEnabled(mContext, WIFIP2PGO_LOCAL_NETWORK_AGENT);
|
// 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();
|
mInitialState = new InitialState();
|
||||||
mLocalHotspotState = new LocalHotspotState();
|
mLocalHotspotState = new LocalHotspotState();
|
||||||
|
|
@ -848,6 +875,7 @@ public class IpServer extends StateMachineShim {
|
||||||
String upstreamIface = null;
|
String upstreamIface = null;
|
||||||
InterfaceParams upstreamIfaceParams = null;
|
InterfaceParams upstreamIfaceParams = null;
|
||||||
int upstreamIfIndex = NO_UPSTREAM;
|
int upstreamIfIndex = NO_UPSTREAM;
|
||||||
|
int pmtu6 = 1400; // default 'safe-ish' value
|
||||||
|
|
||||||
if (v6only != null) {
|
if (v6only != null) {
|
||||||
upstreamIface = v6only.getInterfaceName();
|
upstreamIface = v6only.getInterfaceName();
|
||||||
|
|
@ -856,7 +884,14 @@ public class IpServer extends StateMachineShim {
|
||||||
upstreamIfIndex = upstreamIfaceParams.index;
|
upstreamIfIndex = upstreamIfaceParams.index;
|
||||||
}
|
}
|
||||||
params = new RaParams();
|
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();
|
params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
|
||||||
|
|
||||||
if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface, ttlAdjustment);
|
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
|
// 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
|
// timing issue. It prevents that the IPv6 capability is updated later than
|
||||||
// CMD_TETHER_CONNECTION_CHANGED.
|
// CMD_TETHER_CONNECTION_CHANGED.
|
||||||
|
//
|
||||||
|
// TODO: I believe we need to push v6mtu into this call.
|
||||||
mBpfCoordinator.maybeAddUpstreamToLookupTable(upstreamIfIndex, upstreamIface);
|
mBpfCoordinator.maybeAddUpstreamToLookupTable(upstreamIfIndex, upstreamIface);
|
||||||
|
|
||||||
// If v6only is null, we pass in null to setRaParams(), which handles
|
// 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
|
// mLastIPv6UpstreamIfindex and mLastIPv6UpstreamPrefixes because BpfCoordinator will call
|
||||||
// IpServer#getIpv6UpstreamIfindex and IpServer#getIpv6UpstreamPrefixes to retrieve current
|
// IpServer#getIpv6UpstreamIfindex and IpServer#getIpv6UpstreamPrefixes to retrieve current
|
||||||
// upstream interface index and prefixes when handling upstream changes.
|
// upstream interface index and prefixes when handling upstream changes.
|
||||||
mBpfCoordinator.updateIpv6UpstreamInterface(this, upstreamIfIndex, upstreamPrefixes);
|
mBpfCoordinator.updateIpv6UpstreamInterface(this, upstreamIfIndex, upstreamPrefixes, pmtu6);
|
||||||
mLastIPv6LinkProperties = v6only;
|
mLastIPv6LinkProperties = v6only;
|
||||||
mLastIPv6UpstreamIfindex = upstreamIfIndex;
|
mLastIPv6UpstreamIfindex = upstreamIfIndex;
|
||||||
mLastIPv6UpstreamPrefixes = upstreamPrefixes;
|
mLastIPv6UpstreamPrefixes = upstreamPrefixes;
|
||||||
|
|
@ -896,7 +933,8 @@ public class IpServer extends StateMachineShim {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeRoutesFromNetwork(int netId, @NonNull final List<RouteInfo> toBeRemoved) {
|
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) {
|
if (removalFailures > 0) {
|
||||||
mLog.e("Failed to remove " + removalFailures
|
mLog.e("Failed to remove " + removalFailures
|
||||||
+ " IPv6 routes from network " + netId + ".");
|
+ " IPv6 routes from network " + netId + ".");
|
||||||
|
|
@ -927,15 +965,14 @@ public class IpServer extends StateMachineShim {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addRoutesToNetwork(int netId,
|
private void addRoutesToNetwork(int netId, @NonNull final List<RouteInfo> toBeAdded) {
|
||||||
@NonNull final List<RouteInfo> toBeAdded) {
|
|
||||||
// It's safe to call addInterfaceToNetwork() even if
|
// It's safe to call addInterfaceToNetwork() even if
|
||||||
// the interface is already in the network.
|
// the interface is already in the network.
|
||||||
addInterfaceToNetwork(netId, mIfaceName);
|
addInterfaceToNetwork(netId, mIfaceName);
|
||||||
try {
|
try {
|
||||||
// Add routes from local network. Note that adding routes that
|
// Add routes from local network. Note that adding routes that
|
||||||
// already exist does not cause an error (EEXIST is silently ignored).
|
// 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) {
|
} catch (IllegalStateException e) {
|
||||||
mLog.e("Failed to add IPv4/v6 routes to local table: " + e);
|
mLog.e("Failed to add IPv4/v6 routes to local table: " + e);
|
||||||
return;
|
return;
|
||||||
|
|
@ -949,6 +986,7 @@ public class IpServer extends StateMachineShim {
|
||||||
final List<RouteInfo> routesToBeRemoved =
|
final List<RouteInfo> routesToBeRemoved =
|
||||||
getLocalRoutesFor(mIfaceName, deprecatedPrefixes);
|
getLocalRoutesFor(mIfaceName, deprecatedPrefixes);
|
||||||
if (mTetheringAgent == null) {
|
if (mTetheringAgent == null) {
|
||||||
|
// Routes for local network are not considered local routes.
|
||||||
removeRoutesFromNetwork(LOCAL_NET_ID, routesToBeRemoved);
|
removeRoutesFromNetwork(LOCAL_NET_ID, routesToBeRemoved);
|
||||||
}
|
}
|
||||||
for (RouteInfo route : routesToBeRemoved) mLinkProperties.removeRoute(route);
|
for (RouteInfo route : routesToBeRemoved) mLinkProperties.removeRoute(route);
|
||||||
|
|
@ -1166,8 +1204,7 @@ public class IpServer extends StateMachineShim {
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
private void startServingInterface() {
|
private void startServingInterface() {
|
||||||
if (mSupportTetheringLocalAgent && (mSupportWifiP2pGroupOwnerLocalAgent
|
if (mSupportTetheringAndP2pGoLocalAgent) {
|
||||||
|| getScope() != CONNECTIVITY_SCOPE_LOCAL)) {
|
|
||||||
try {
|
try {
|
||||||
mTetheringAgent = mDeps.makeNetworkAgent(mContext, Looper.myLooper(), TAG,
|
mTetheringAgent = mDeps.makeNetworkAgent(mContext, Looper.myLooper(), TAG,
|
||||||
mInterfaceType, mLinkProperties);
|
mInterfaceType, mLinkProperties);
|
||||||
|
|
@ -1197,10 +1234,11 @@ public class IpServer extends StateMachineShim {
|
||||||
20 /* maxAttempts */, 50 /* pollingIntervalMs */);
|
20 /* maxAttempts */, 50 /* pollingIntervalMs */);
|
||||||
// Activate a route to dest and IPv6 link local.
|
// Activate a route to dest and IPv6 link local.
|
||||||
NetdUtils.modifyRoute(mNetd, NetdUtils.ModifyOperation.ADD, LOCAL_NET_ID,
|
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,
|
NetdUtils.modifyRoute(mNetd, NetdUtils.ModifyOperation.ADD, LOCAL_NET_ID,
|
||||||
new RouteInfo(new IpPrefix("fe80::/64"), null, mIfaceName,
|
new RouteInfo(new IpPrefix("fe80::/64"), null, mIfaceName,
|
||||||
RTN_UNICAST));
|
RTN_UNICAST), mUseRouteParcel);
|
||||||
}
|
}
|
||||||
} catch (RemoteException | ServiceSpecificException | IllegalStateException e) {
|
} catch (RemoteException | ServiceSpecificException | IllegalStateException e) {
|
||||||
mLog.e("Error Tethering", e);
|
mLog.e("Error Tethering", e);
|
||||||
|
|
@ -1330,6 +1368,7 @@ public class IpServer extends StateMachineShim {
|
||||||
final List<RouteInfo> routesToBeRemoved =
|
final List<RouteInfo> routesToBeRemoved =
|
||||||
List.of(getDirectConnectedRoute(deprecatedLinkAddress));
|
List.of(getDirectConnectedRoute(deprecatedLinkAddress));
|
||||||
if (mTetheringAgent == null) {
|
if (mTetheringAgent == null) {
|
||||||
|
// Routes for local network are not considered local routes.
|
||||||
removeRoutesFromNetwork(LOCAL_NET_ID, routesToBeRemoved);
|
removeRoutesFromNetwork(LOCAL_NET_ID, routesToBeRemoved);
|
||||||
}
|
}
|
||||||
for (RouteInfo route : routesToBeRemoved) mLinkProperties.removeRoute(route);
|
for (RouteInfo route : routesToBeRemoved) mLinkProperties.removeRoute(route);
|
||||||
|
|
@ -1440,7 +1479,7 @@ public class IpServer extends StateMachineShim {
|
||||||
for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
|
for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
|
||||||
mUpstreamIfaceSet = null;
|
mUpstreamIfaceSet = null;
|
||||||
mBpfCoordinator.updateIpv6UpstreamInterface(IpServer.this, NO_UPSTREAM,
|
mBpfCoordinator.updateIpv6UpstreamInterface(IpServer.this, NO_UPSTREAM,
|
||||||
Collections.emptySet());
|
Collections.emptySet(), 1400);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void cleanupUpstreamInterface(String upstreamIface) {
|
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.NetworkStackConstants;
|
||||||
import com.android.net.module.util.SharedLog;
|
import com.android.net.module.util.SharedLog;
|
||||||
import com.android.net.module.util.Struct.S32;
|
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.Tether4Key;
|
||||||
import com.android.net.module.util.bpf.Tether4Value;
|
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.bpf.TetherStatsValue;
|
||||||
import com.android.net.module.util.ip.ConntrackMonitor;
|
import com.android.net.module.util.ip.ConntrackMonitor;
|
||||||
import com.android.net.module.util.ip.ConntrackMonitor.ConntrackEventConsumer;
|
import com.android.net.module.util.ip.ConntrackMonitor.ConntrackEventConsumer;
|
||||||
|
|
@ -448,11 +448,11 @@ public class BpfCoordinator {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get stats BPF map. */
|
/** Get stats BPF map. */
|
||||||
@Nullable public IBpfMap<TetherStatsKey, TetherStatsValue> getBpfStatsMap() {
|
@Nullable public IBpfMap<S32, TetherStatsValue> getBpfStatsMap() {
|
||||||
if (!isAtLeastS()) return null;
|
if (!isAtLeastS()) return null;
|
||||||
try {
|
try {
|
||||||
return new BpfMap<>(TETHER_STATS_MAP_PATH,
|
return new BpfMap<>(TETHER_STATS_MAP_PATH,
|
||||||
TetherStatsKey.class, TetherStatsValue.class);
|
S32.class, TetherStatsValue.class);
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
Log.e(TAG, "Cannot create stats map: " + e);
|
Log.e(TAG, "Cannot create stats map: " + e);
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -460,11 +460,11 @@ public class BpfCoordinator {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get limit BPF map. */
|
/** Get limit BPF map. */
|
||||||
@Nullable public IBpfMap<TetherLimitKey, TetherLimitValue> getBpfLimitMap() {
|
@Nullable public IBpfMap<S32, S64> getBpfLimitMap() {
|
||||||
if (!isAtLeastS()) return null;
|
if (!isAtLeastS()) return null;
|
||||||
try {
|
try {
|
||||||
return new BpfMap<>(TETHER_LIMIT_MAP_PATH,
|
return new BpfMap<>(TETHER_LIMIT_MAP_PATH,
|
||||||
TetherLimitKey.class, TetherLimitValue.class);
|
S32.class, S64.class);
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
Log.e(TAG, "Cannot create limit map: " + e);
|
Log.e(TAG, "Cannot create limit map: " + e);
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -472,11 +472,11 @@ public class BpfCoordinator {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get dev BPF map. */
|
/** Get dev BPF map. */
|
||||||
@Nullable public IBpfMap<TetherDevKey, TetherDevValue> getBpfDevMap() {
|
@Nullable public IBpfMap<S32, S32> getBpfDevMap() {
|
||||||
if (!isAtLeastS()) return null;
|
if (!isAtLeastS()) return null;
|
||||||
try {
|
try {
|
||||||
return new BpfMap<>(TETHER_DEV_MAP_PATH,
|
return new BpfMap<>(TETHER_DEV_MAP_PATH,
|
||||||
TetherDevKey.class, TetherDevValue.class);
|
S32.class, S32.class);
|
||||||
} catch (ErrnoException e) {
|
} catch (ErrnoException e) {
|
||||||
Log.e(TAG, "Cannot create dev map: " + e);
|
Log.e(TAG, "Cannot create dev map: " + e);
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -501,6 +501,12 @@ public class BpfCoordinator {
|
||||||
lastMaxSessionCount);
|
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
|
* @see DeviceConfigUtils#isTetheringFeatureEnabled
|
||||||
*/
|
*/
|
||||||
|
|
@ -542,6 +548,7 @@ public class BpfCoordinator {
|
||||||
mBpfCoordinatorShim = BpfCoordinatorShim.getBpfCoordinatorShim(deps);
|
mBpfCoordinatorShim = BpfCoordinatorShim.getBpfCoordinatorShim(deps);
|
||||||
if (!mBpfCoordinatorShim.isInitialized()) {
|
if (!mBpfCoordinatorShim.isInitialized()) {
|
||||||
mLog.e("Bpf shim not initialized");
|
mLog.e("Bpf shim not initialized");
|
||||||
|
mDeps.sendBpfCoordinatorShimInitError();
|
||||||
}
|
}
|
||||||
|
|
||||||
// BPF IPv4 forwarding only supports on S+.
|
// BPF IPv4 forwarding only supports on S+.
|
||||||
|
|
@ -790,7 +797,7 @@ public class BpfCoordinator {
|
||||||
*/
|
*/
|
||||||
private void updateAllIpv6Rules(@NonNull final IpServer ipServer,
|
private void updateAllIpv6Rules(@NonNull final IpServer ipServer,
|
||||||
final InterfaceParams interfaceParams, int newUpstreamIfindex,
|
final InterfaceParams interfaceParams, int newUpstreamIfindex,
|
||||||
@NonNull final Set<IpPrefix> newUpstreamPrefixes) {
|
@NonNull final Set<IpPrefix> newUpstreamPrefixes, int pmtu) {
|
||||||
if (!isUsingBpf()) return;
|
if (!isUsingBpf()) return;
|
||||||
|
|
||||||
// Remove IPv6 downstream rules. Remove the old ones before adding the new rules, otherwise
|
// 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) {
|
for (final IpPrefix ipPrefix : newUpstreamPrefixes) {
|
||||||
addIpv6UpstreamRule(ipServer, new Ipv6UpstreamRule(
|
addIpv6UpstreamRule(ipServer, new Ipv6UpstreamRule(
|
||||||
newUpstreamIfindex, interfaceParams.index, ipPrefix,
|
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.
|
* Note that this can be only called on handler thread.
|
||||||
*/
|
*/
|
||||||
public void updateIpv6UpstreamInterface(@NonNull final IpServer ipServer, int upstreamIfindex,
|
public void updateIpv6UpstreamInterface(@NonNull final IpServer ipServer, int upstreamIfindex,
|
||||||
@NonNull Set<IpPrefix> upstreamPrefixes) {
|
@NonNull Set<IpPrefix> upstreamPrefixes, int pmtu) {
|
||||||
if (!isUsingBpf()) return;
|
if (!isUsingBpf()) return;
|
||||||
|
|
||||||
// If the upstream interface has changed, remove all rules and re-add them with the new
|
// 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);
|
final boolean upstreamSupportsBpf = checkUpstreamSupportsBpf(upstreamIfindex);
|
||||||
updateAllIpv6Rules(ipServer, interfaceParams,
|
updateAllIpv6Rules(ipServer, interfaceParams,
|
||||||
getInterfaceIndexForRule(upstreamIfindex, upstreamSupportsBpf),
|
getInterfaceIndexForRule(upstreamIfindex, upstreamSupportsBpf),
|
||||||
upstreamPrefixes);
|
upstreamPrefixes, pmtu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1059,12 +1066,12 @@ public class BpfCoordinator {
|
||||||
|
|
||||||
// Find the rules which are related with the given client.
|
// Find the rules which are related with the given client.
|
||||||
mBpfCoordinatorShim.tetherOffloadRuleForEach(UPSTREAM, (k, v) -> {
|
mBpfCoordinatorShim.tetherOffloadRuleForEach(UPSTREAM, (k, v) -> {
|
||||||
if (Arrays.equals(k.src4, clientAddr.getAddress())) {
|
if (Objects.equals(k.src4, clientAddr)) {
|
||||||
deleteUpstreamRuleKeys.add(k);
|
deleteUpstreamRuleKeys.add(k);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mBpfCoordinatorShim.tetherOffloadRuleForEach(DOWNSTREAM, (k, v) -> {
|
mBpfCoordinatorShim.tetherOffloadRuleForEach(DOWNSTREAM, (k, v) -> {
|
||||||
if (Arrays.equals(v.dst46, toIpv4MappedAddressBytes(clientAddr))) {
|
if (Objects.equals(v.dst46, clientAddr)) {
|
||||||
deleteDownstreamRuleKeys.add(k);
|
deleteDownstreamRuleKeys.add(k);
|
||||||
upstreamIndiceSet.add((int) k.iif);
|
upstreamIndiceSet.add((int) k.iif);
|
||||||
}
|
}
|
||||||
|
|
@ -1370,7 +1377,7 @@ public class BpfCoordinator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private void dumpBpfStats(@NonNull IndentingPrintWriter pw) {
|
private void dumpBpfStats(@NonNull IndentingPrintWriter pw) {
|
||||||
try (IBpfMap<TetherStatsKey, TetherStatsValue> map = mDeps.getBpfStatsMap()) {
|
try (IBpfMap<S32, TetherStatsValue> map = mDeps.getBpfStatsMap()) {
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
pw.println("No BPF stats map");
|
pw.println("No BPF stats map");
|
||||||
return;
|
return;
|
||||||
|
|
@ -1439,9 +1446,10 @@ public class BpfCoordinator {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String ipv6UpstreamRuleToString(TetherUpstream6Key key, Tether6Value value) {
|
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,
|
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) {
|
private void dumpIpv6UpstreamRules(IndentingPrintWriter pw) {
|
||||||
|
|
@ -1467,9 +1475,9 @@ public class BpfCoordinator {
|
||||||
} catch (UnknownHostException impossible) {
|
} catch (UnknownHostException impossible) {
|
||||||
throw new AssertionError("IP address array not valid IPv6 address!");
|
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),
|
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) {
|
private void dumpIpv6DownstreamRules(IndentingPrintWriter pw) {
|
||||||
|
|
@ -1492,13 +1500,13 @@ public class BpfCoordinator {
|
||||||
// duplicate bpf map dump code.
|
// duplicate bpf map dump code.
|
||||||
private void dumpBpfForwardingRulesIpv6(IndentingPrintWriter pw) {
|
private void dumpBpfForwardingRulesIpv6(IndentingPrintWriter pw) {
|
||||||
pw.println("IPv6 Upstream: iif(iface) [inDstMac] [sourcePrefix] -> oif(iface) etherType "
|
pw.println("IPv6 Upstream: iif(iface) [inDstMac] [sourcePrefix] -> oif(iface) etherType "
|
||||||
+ "[outSrcMac] [outDstMac]");
|
+ "[outSrcMac] [outDstMac] pmtu");
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
dumpIpv6UpstreamRules(pw);
|
dumpIpv6UpstreamRules(pw);
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
|
|
||||||
pw.println("IPv6 Downstream: iif(iface) [inDstMac] neigh6 -> oif(iface) etherType "
|
pw.println("IPv6 Downstream: iif(iface) [inDstMac] neigh6 -> oif(iface) etherType "
|
||||||
+ "[outSrcMac] [outDstMac]");
|
+ "[outSrcMac] [outDstMac] pmtu");
|
||||||
pw.increaseIndent();
|
pw.increaseIndent();
|
||||||
dumpIpv6DownstreamRules(pw);
|
dumpIpv6DownstreamRules(pw);
|
||||||
pw.decreaseIndent();
|
pw.decreaseIndent();
|
||||||
|
|
@ -1522,7 +1530,7 @@ public class BpfCoordinator {
|
||||||
// expected argument order.
|
// expected argument order.
|
||||||
// TODO: dump downstream4 map.
|
// TODO: dump downstream4 map.
|
||||||
if (CollectionUtils.contains(args, DUMPSYS_RAWMAP_ARG_STATS)) {
|
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);
|
BpfDump.dumpRawMap(statsMap, pw);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
pw.println("Error dumping stats map: " + e);
|
pw.println("Error dumping stats map: " + e);
|
||||||
|
|
@ -1552,20 +1560,15 @@ public class BpfCoordinator {
|
||||||
Tether4Key key, Tether4Value value) {
|
Tether4Key key, Tether4Value value) {
|
||||||
final String src4, public4, dst4;
|
final String src4, public4, dst4;
|
||||||
final int publicPort;
|
final int publicPort;
|
||||||
try {
|
src4 = key.src4.getHostAddress();
|
||||||
src4 = InetAddress.getByAddress(key.src4).getHostAddress();
|
if (downstream) {
|
||||||
if (downstream) {
|
public4 = key.dst4.getHostAddress();
|
||||||
public4 = InetAddress.getByAddress(key.dst4).getHostAddress();
|
publicPort = key.dstPort;
|
||||||
publicPort = key.dstPort;
|
} else {
|
||||||
} else {
|
public4 = value.src46.getHostAddress();
|
||||||
public4 = InetAddress.getByAddress(value.src46).getHostAddress();
|
publicPort = value.srcPort;
|
||||||
publicPort = value.srcPort;
|
|
||||||
}
|
|
||||||
dst4 = InetAddress.getByAddress(value.dst46).getHostAddress();
|
|
||||||
} catch (UnknownHostException impossible) {
|
|
||||||
throw new AssertionError("IP address array not valid IPv4 address!");
|
|
||||||
}
|
}
|
||||||
|
dst4 = value.dst46.getHostAddress();
|
||||||
final String ageStr = (value.lastUsed == 0) ? "-"
|
final String ageStr = (value.lastUsed == 0) ? "-"
|
||||||
: String.format("%dms", (now - value.lastUsed) / 1_000_000);
|
: 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",
|
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) {
|
private void dumpDevmap(@NonNull IndentingPrintWriter pw) {
|
||||||
try (IBpfMap<TetherDevKey, TetherDevValue> map = mDeps.getBpfDevMap()) {
|
try (IBpfMap<S32, S32> map = mDeps.getBpfDevMap()) {
|
||||||
if (map == null) {
|
if (map == null) {
|
||||||
pw.println("No devmap support");
|
pw.println("No devmap support");
|
||||||
return;
|
return;
|
||||||
|
|
@ -1651,8 +1654,8 @@ public class BpfCoordinator {
|
||||||
// Only get upstream interface name. Just do the best to make the index readable.
|
// 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
|
// TODO: get downstream interface name because the index is either upstream or
|
||||||
// downstream interface in dev map.
|
// downstream interface in dev map.
|
||||||
pw.println(String.format("%d (%s) -> %d (%s)", k.ifIndex, getIfName(k.ifIndex),
|
pw.println(String.format("%d (%s) -> %d (%s)", k.val, getIfName(k.val),
|
||||||
v.ifIndex, getIfName(v.ifIndex)));
|
v.val, getIfName(v.val)));
|
||||||
});
|
});
|
||||||
} catch (ErrnoException | IOException e) {
|
} catch (ErrnoException | IOException e) {
|
||||||
pw.println("Error dumping dev map: " + e);
|
pw.println("Error dumping dev map: " + e);
|
||||||
|
|
@ -1692,7 +1695,7 @@ public class BpfCoordinator {
|
||||||
// |field |oif |ethDst|ethSrc|ethPro|pmtu |
|
// |field |oif |ethDst|ethSrc|ethPro|pmtu |
|
||||||
// | | |mac |mac |to | |
|
// | | |mac |mac |to | |
|
||||||
// +------+------+------+------+------+------+
|
// +------+------+------+------+------+------+
|
||||||
// |value |upstre|-- |-- |ETH_P_|1500 |
|
// |value |upstre|-- |-- |ETH_P_|pmtu |
|
||||||
// | |am | | |IP | |
|
// | |am | | |IP | |
|
||||||
// +------+------+------+------+------+------+
|
// +------+------+------+------+------+------+
|
||||||
//
|
//
|
||||||
|
|
@ -1706,16 +1709,19 @@ public class BpfCoordinator {
|
||||||
public final MacAddress outSrcMac;
|
public final MacAddress outSrcMac;
|
||||||
@NonNull
|
@NonNull
|
||||||
public final MacAddress outDstMac;
|
public final MacAddress outDstMac;
|
||||||
|
public final int pmtu;
|
||||||
|
|
||||||
public Ipv6UpstreamRule(int upstreamIfindex, int downstreamIfindex,
|
public Ipv6UpstreamRule(int upstreamIfindex, int downstreamIfindex,
|
||||||
@NonNull IpPrefix sourcePrefix, @NonNull MacAddress inDstMac,
|
@NonNull IpPrefix sourcePrefix, @NonNull MacAddress inDstMac,
|
||||||
@NonNull MacAddress outSrcMac, @NonNull MacAddress outDstMac) {
|
@NonNull MacAddress outSrcMac, @NonNull MacAddress outDstMac,
|
||||||
|
int pmtu) {
|
||||||
this.upstreamIfindex = upstreamIfindex;
|
this.upstreamIfindex = upstreamIfindex;
|
||||||
this.downstreamIfindex = downstreamIfindex;
|
this.downstreamIfindex = downstreamIfindex;
|
||||||
this.sourcePrefix = sourcePrefix;
|
this.sourcePrefix = sourcePrefix;
|
||||||
this.inDstMac = inDstMac;
|
this.inDstMac = inDstMac;
|
||||||
this.outSrcMac = outSrcMac;
|
this.outSrcMac = outSrcMac;
|
||||||
this.outDstMac = outDstMac;
|
this.outDstMac = outDstMac;
|
||||||
|
this.pmtu = pmtu;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1732,8 +1738,7 @@ public class BpfCoordinator {
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
public Tether6Value makeTether6Value() {
|
public Tether6Value makeTether6Value() {
|
||||||
return new Tether6Value(upstreamIfindex, outDstMac, outSrcMac, ETH_P_IPV6,
|
return new Tether6Value(upstreamIfindex, outDstMac, outSrcMac, ETH_P_IPV6, pmtu);
|
||||||
NetworkStackConstants.ETHER_MTU);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
@ -2032,20 +2037,6 @@ public class BpfCoordinator {
|
||||||
return null;
|
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
|
// TODO: parse CTA_PROTOINFO of conntrack event in ConntrackMonitor. For TCP, only add rules
|
||||||
// while TCP status is established.
|
// while TCP status is established.
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
|
@ -2111,16 +2102,16 @@ public class BpfCoordinator {
|
||||||
private Tether4Key makeTetherUpstream4Key(
|
private Tether4Key makeTetherUpstream4Key(
|
||||||
@NonNull ConntrackEvent e, @NonNull ClientInfo c) {
|
@NonNull ConntrackEvent e, @NonNull ClientInfo c) {
|
||||||
return new Tether4Key(c.downstreamIfindex, c.downstreamMac,
|
return new Tether4Key(c.downstreamIfindex, c.downstreamMac,
|
||||||
e.tupleOrig.protoNum, e.tupleOrig.srcIp.getAddress(),
|
e.tupleOrig.protoNum, e.tupleOrig.srcIp, e.tupleOrig.dstIp,
|
||||||
e.tupleOrig.dstIp.getAddress(), e.tupleOrig.srcPort, e.tupleOrig.dstPort);
|
e.tupleOrig.srcPort, e.tupleOrig.dstPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
private Tether4Key makeTetherDownstream4Key(
|
private Tether4Key makeTetherDownstream4Key(
|
||||||
@NonNull ConntrackEvent e, @NonNull ClientInfo c, int upstreamIndex) {
|
@NonNull ConntrackEvent e, @NonNull ClientInfo c, int upstreamIndex) {
|
||||||
return new Tether4Key(upstreamIndex, NULL_MAC_ADDRESS /* dstMac (rawip) */,
|
return new Tether4Key(upstreamIndex, NULL_MAC_ADDRESS /* dstMac (rawip) */,
|
||||||
e.tupleReply.protoNum, e.tupleReply.srcIp.getAddress(),
|
e.tupleReply.protoNum, e.tupleReply.srcIp, e.tupleReply.dstIp,
|
||||||
e.tupleReply.dstIp.getAddress(), e.tupleReply.srcPort, e.tupleReply.dstPort);
|
e.tupleReply.srcPort, e.tupleReply.dstPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
|
@ -2129,8 +2120,7 @@ public class BpfCoordinator {
|
||||||
return new Tether4Value(upstreamInfo.ifIndex,
|
return new Tether4Value(upstreamInfo.ifIndex,
|
||||||
NULL_MAC_ADDRESS /* ethDstMac (rawip) */,
|
NULL_MAC_ADDRESS /* ethDstMac (rawip) */,
|
||||||
NULL_MAC_ADDRESS /* ethSrcMac (rawip) */, ETH_P_IP,
|
NULL_MAC_ADDRESS /* ethSrcMac (rawip) */, ETH_P_IP,
|
||||||
upstreamInfo.mtu, toIpv4MappedAddressBytes(e.tupleReply.dstIp),
|
upstreamInfo.mtu, e.tupleReply.dstIp, e.tupleReply.srcIp, e.tupleReply.dstPort,
|
||||||
toIpv4MappedAddressBytes(e.tupleReply.srcIp), e.tupleReply.dstPort,
|
|
||||||
e.tupleReply.srcPort, 0 /* lastUsed, filled by bpf prog only */);
|
e.tupleReply.srcPort, 0 /* lastUsed, filled by bpf prog only */);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2139,8 +2129,7 @@ public class BpfCoordinator {
|
||||||
@NonNull ClientInfo c, @NonNull UpstreamInfo upstreamInfo) {
|
@NonNull ClientInfo c, @NonNull UpstreamInfo upstreamInfo) {
|
||||||
return new Tether4Value(c.downstreamIfindex,
|
return new Tether4Value(c.downstreamIfindex,
|
||||||
c.clientMac, c.downstreamMac, ETH_P_IP, upstreamInfo.mtu,
|
c.clientMac, c.downstreamMac, ETH_P_IP, upstreamInfo.mtu,
|
||||||
toIpv4MappedAddressBytes(e.tupleOrig.dstIp),
|
e.tupleOrig.dstIp, e.tupleOrig.srcIp,
|
||||||
toIpv4MappedAddressBytes(e.tupleOrig.srcIp),
|
|
||||||
e.tupleOrig.dstPort, e.tupleOrig.srcPort,
|
e.tupleOrig.dstPort, e.tupleOrig.srcPort,
|
||||||
0 /* lastUsed, filled by bpf prog only */);
|
0 /* lastUsed, filled by bpf prog only */);
|
||||||
}
|
}
|
||||||
|
|
@ -2465,17 +2454,6 @@ public class BpfCoordinator {
|
||||||
return Math.max(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS, configInterval);
|
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
|
// Update CTA_TUPLE_ORIG timeout for a given conntrack entry. Note that there will also be
|
||||||
// coming a conntrack event to notify updated timeout.
|
// coming a conntrack event to notify updated timeout.
|
||||||
private void updateConntrackTimeout(byte proto, Inet4Address src4, short srcPort,
|
private void updateConntrackTimeout(byte proto, Inet4Address src4, short srcPort,
|
||||||
|
|
@ -2532,9 +2510,8 @@ public class BpfCoordinator {
|
||||||
// both directions for TCP.
|
// both directions for TCP.
|
||||||
mBpfCoordinatorShim.tetherOffloadRuleForEach(UPSTREAM, (k, v) -> {
|
mBpfCoordinatorShim.tetherOffloadRuleForEach(UPSTREAM, (k, v) -> {
|
||||||
if ((now - v.lastUsed) / 1_000_000 < CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS) {
|
if ((now - v.lastUsed) / 1_000_000 < CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS) {
|
||||||
updateConntrackTimeout((byte) k.l4proto,
|
updateConntrackTimeout((byte) k.l4proto, k.src4, (short) k.srcPort, k.dst4,
|
||||||
parseIPv4Address(k.src4), (short) k.srcPort,
|
(short) k.dstPort);
|
||||||
parseIPv4Address(k.dst4), (short) k.dstPort);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -2543,9 +2520,8 @@ public class BpfCoordinator {
|
||||||
// which is opposite direction for downstream map value.
|
// which is opposite direction for downstream map value.
|
||||||
mBpfCoordinatorShim.tetherOffloadRuleForEach(DOWNSTREAM, (k, v) -> {
|
mBpfCoordinatorShim.tetherOffloadRuleForEach(DOWNSTREAM, (k, v) -> {
|
||||||
if ((now - v.lastUsed) / 1_000_000 < CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS) {
|
if ((now - v.lastUsed) / 1_000_000 < CONNTRACK_TIMEOUT_UPDATE_INTERVAL_MS) {
|
||||||
updateConntrackTimeout((byte) k.l4proto,
|
updateConntrackTimeout((byte) k.l4proto, (Inet4Address) v.dst46, (short) v.dstPort,
|
||||||
parseIPv4Address(v.dst46), (short) v.dstPort,
|
(Inet4Address) v.src46, (short) v.srcPort);
|
||||||
parseIPv4Address(v.src46), (short) v.srcPort);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ import java.io.IOException;
|
||||||
/**
|
/**
|
||||||
* The classes and the methods for BPF utilization.
|
* The classes and the methods for BPF utilization.
|
||||||
*
|
*
|
||||||
* {@hide}
|
* @hide
|
||||||
*/
|
*/
|
||||||
public class BpfUtils {
|
public class BpfUtils {
|
||||||
static {
|
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_ENTITLEMENT_UNKNOWN;
|
||||||
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
|
import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
|
||||||
import static android.net.TetheringManager.TETHER_ERROR_PROVISIONING_FAILED;
|
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.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
|
||||||
import static com.android.networkstack.apishim.ConstantsShim.ACTION_TETHER_UNSUPPORTED_CARRIER_UI;
|
import static com.android.networkstack.apishim.ConstantsShim.ACTION_TETHER_UNSUPPORTED_CARRIER_UI;
|
||||||
|
|
@ -448,7 +449,8 @@ public class EntitlementManager {
|
||||||
return TETHERING_PROVISIONING_CARRIER_UNSUPPORT;
|
return TETHERING_PROVISIONING_CARRIER_UNSUPPORT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.isCarrierConfigAffirmsEntitlementCheckRequired) {
|
if (!config.isCarrierConfigAffirmsEntitlementCheckRequired
|
||||||
|
|| INVALID_SUBSCRIPTION_ID == config.activeDataSubId) {
|
||||||
return TETHERING_PROVISIONING_NOT_REQUIRED;
|
return TETHERING_PROVISIONING_NOT_REQUIRED;
|
||||||
}
|
}
|
||||||
return (config.provisioningApp.length == 2)
|
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;
|
IBinder binder;
|
||||||
if (!SdkLevel.isAtLeastS()) {
|
if (!SdkLevel.isAtLeastS()) {
|
||||||
final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
|
final ConnectivityManager cm = context.getSystemService(ConnectivityManager.class);
|
||||||
binder =
|
binder = new RoutingCoordinatorService(getINetd(context, log), cm::getAllNetworks,
|
||||||
new RoutingCoordinatorService(
|
context, false /* bluetoothTetheringUseRandomAddress */);
|
||||||
getINetd(context, log), cm::getAllNetworks, context);
|
|
||||||
} else {
|
} else {
|
||||||
binder = ConnectivityInternalApiUtil.getRoutingCoordinator(context);
|
binder = ConnectivityInternalApiUtil.getRoutingCoordinator(context);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,15 +61,8 @@ public class TetheringFeatureFlags {
|
||||||
public static final String TETHER_ACTIVE_SESSIONS_METRICS = "tether_active_sessions_metrics";
|
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.
|
* A kill switch to control whether the TETHERING_AND_P2P_GO_LOCAL_AGENT is enabled.
|
||||||
* Disabled by default.
|
|
||||||
*/
|
*/
|
||||||
public static final String TETHERING_LOCAL_NETWORK_AGENT = "tethering_local_network_agent";
|
public static final String TETHERING_AND_P2P_GO_LOCAL_AGENT =
|
||||||
|
"tethering_and_p2p_go_local_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";
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue