diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp
deleted file mode 100644
index 5526c657b874b..0000000000000
--- a/packages/Tethering/Android.bp
+++ /dev/null
@@ -1,137 +0,0 @@
-//
-// Copyright (C) 2019 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.
-//
-
-java_defaults {
- name: "TetheringAndroidLibraryDefaults",
- sdk_version: "module_current",
- srcs: [
- "src/**/*.java",
- ":framework-tethering-shared-srcs",
- ":tethering-module-utils-srcs",
- ":services-tethering-shared-srcs",
- ],
- static_libs: [
- "androidx.annotation_annotation",
- "netd_aidl_interface-unstable-java",
- "netlink-client",
- // TODO: use networkstack-client instead of just including the AIDL interface
- "networkstack-aidl-interfaces-unstable-java",
- "android.hardware.tetheroffload.config-V1.0-java",
- "android.hardware.tetheroffload.control-V1.0-java",
- "net-utils-framework-common",
- "net-utils-device-common",
- ],
- libs: [
- "framework-statsd.stubs.module_lib",
- "framework-tethering.impl",
- "framework-wifi",
- "unsupportedappusage",
- ],
- plugins: ["java_api_finder"],
- manifest: "AndroidManifestBase.xml",
-}
-
-// Build tethering static library, used to compile both variants of the tethering.
-android_library {
- name: "TetheringApiCurrentLib",
- defaults: ["TetheringAndroidLibraryDefaults"],
-}
-
-// Due to b/143733063, APK can't access a jni lib that is in APEX (but not in the APK).
-cc_library {
- name: "libtetherutilsjni",
- sdk_version: "current",
- apex_available: [
- "//apex_available:platform", // Used by InProcessTethering
- "com.android.tethering",
- ],
- min_sdk_version: "current",
- srcs: [
- "jni/android_net_util_TetheringUtils.cpp",
- ],
- shared_libs: [
- "liblog",
- "libnativehelper_compat_libc++",
- ],
-
- // We cannot use plain "libc++" here to link libc++ dynamically because it results in:
- // java.lang.UnsatisfiedLinkError: dlopen failed: library "libc++_shared.so" not found
- // even if "libc++" is added into jni_libs below. Adding "libc++_shared" into jni_libs doesn't
- // build because soong complains of:
- // module Tethering missing dependencies: libc++_shared
- //
- // So, link libc++ statically. This means that we also need to ensure that all the C++ libraries
- // we depend on do not dynamically link libc++. This is currently the case, because liblog is
- // C-only and libnativehelper_compat_libc also uses stl: "c++_static".
- stl: "c++_static",
-
- cflags: [
- "-Wall",
- "-Werror",
- "-Wno-unused-parameter",
- "-Wthread-safety",
- ],
-
- ldflags: ["-Wl,--exclude-libs=ALL,-error-limit=0"],
-}
-
-// Common defaults for compiling the actual APK.
-java_defaults {
- name: "TetheringAppDefaults",
- sdk_version: "module_current",
- privileged: true,
- jni_libs: [
- "libtetherutilsjni",
- ],
- resource_dirs: [
- "res",
- ],
- libs: [
- "framework-tethering",
- "framework-wifi",
- ],
- jarjar_rules: "jarjar-rules.txt",
- optimize: {
- proguard_flags_files: ["proguard.flags"],
- },
-}
-
-// Non-updatable tethering running in the system server process for devices not using the module
-android_app {
- name: "InProcessTethering",
- defaults: ["TetheringAppDefaults"],
- static_libs: ["TetheringApiCurrentLib"],
- certificate: "platform",
- manifest: "AndroidManifest_InProcess.xml",
- // InProcessTethering is a replacement for Tethering
- overrides: ["Tethering"],
- apex_available: ["com.android.tethering"],
- min_sdk_version: "current",
-}
-
-// Updatable tethering packaged as an application
-android_app {
- name: "Tethering",
- defaults: ["TetheringAppDefaults"],
- static_libs: ["TetheringApiCurrentLib"],
- certificate: "networkstack",
- manifest: "AndroidManifest.xml",
- use_embedded_native_libs: true,
- // The permission configuration *must* be included to ensure security of the device
- required: ["NetworkPermissionConfig"],
- apex_available: ["com.android.tethering"],
- min_sdk_version: "current",
-}
diff --git a/packages/Tethering/AndroidManifest.xml b/packages/Tethering/AndroidManifest.xml
deleted file mode 100644
index e6444f3ead5c4..0000000000000
--- a/packages/Tethering/AndroidManifest.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/Tethering/AndroidManifestBase.xml b/packages/Tethering/AndroidManifestBase.xml
deleted file mode 100644
index 97c3988829fe1..0000000000000
--- a/packages/Tethering/AndroidManifestBase.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
diff --git a/packages/Tethering/AndroidManifest_InProcess.xml b/packages/Tethering/AndroidManifest_InProcess.xml
deleted file mode 100644
index b1f124097c79b..0000000000000
--- a/packages/Tethering/AndroidManifest_InProcess.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/Tethering/OWNERS b/packages/Tethering/OWNERS
deleted file mode 100644
index a6c21fc16becc..0000000000000
--- a/packages/Tethering/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-set noparent # while performing migration - b/167962976
-baligh@google.com
diff --git a/packages/Tethering/TEST_MAPPING b/packages/Tethering/TEST_MAPPING
deleted file mode 100644
index 5617b0c13c1ca..0000000000000
--- a/packages/Tethering/TEST_MAPPING
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "presubmit": [
- {
- "name": "TetheringTests"
- }
- ],
- "postsubmit": [
- {
- "name": "TetheringIntegrationTests"
- }
- ]
-}
diff --git a/packages/Tethering/apex/Android.bp b/packages/Tethering/apex/Android.bp
deleted file mode 100644
index 05243749f765b..0000000000000
--- a/packages/Tethering/apex/Android.bp
+++ /dev/null
@@ -1,48 +0,0 @@
-//
-// Copyright (C) 2019 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.
-//
-
-apex {
- name: "com.android.tethering",
- updatable: true,
- min_sdk_version: "current",
- java_libs: ["framework-tethering"],
- bpfs: ["offload.o"],
- apps: ["Tethering"],
- manifest: "manifest.json",
- key: "com.android.tethering.key",
-
- androidManifest: "AndroidManifest.xml",
-}
-
-apex_key {
- name: "com.android.tethering.key",
- public_key: "com.android.tethering.avbpubkey",
- private_key: "com.android.tethering.pem",
-}
-
-android_app_certificate {
- name: "com.android.tethering.certificate",
- certificate: "com.android.tethering",
-}
-
-override_apex {
- name: "com.android.tethering.inprocess",
- base: "com.android.tethering",
- package_name: "com.android.tethering.inprocess",
- apps: [
- "InProcessTethering",
- ],
-}
diff --git a/packages/Tethering/apex/AndroidManifest.xml b/packages/Tethering/apex/AndroidManifest.xml
deleted file mode 100644
index 4aae3cc3000de..0000000000000
--- a/packages/Tethering/apex/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
diff --git a/packages/Tethering/apex/com.android.tethering.avbpubkey b/packages/Tethering/apex/com.android.tethering.avbpubkey
deleted file mode 100644
index 9a2c0174e4965..0000000000000
Binary files a/packages/Tethering/apex/com.android.tethering.avbpubkey and /dev/null differ
diff --git a/packages/Tethering/apex/com.android.tethering.pem b/packages/Tethering/apex/com.android.tethering.pem
deleted file mode 100644
index d4f39abd3bb21..0000000000000
--- a/packages/Tethering/apex/com.android.tethering.pem
+++ /dev/null
@@ -1,51 +0,0 @@
------BEGIN RSA PRIVATE KEY-----
-MIIJKgIBAAKCAgEA+AWTp03PBRMGt4mVNLt5PDoFFSfmFOVTM7jt5AJXnQMIDsAM
-1cyWGWRridGIpoHAaCALVgW5aRySgi8yV5xP4w0YHcKbfh9M6I9oz4RUo4GQBZfX
-+lFIGaLjb6I3tEJxPuxps4sW26Io63ihwTnKeGyADHdHGWDUs9WU0Ml+QTvKrdjy
-qC03M0dehYXILGiA9m+UXwKoKxhWgfDUhWLhDBUtLJLPL4WeqKc9sG9h+zzVqE+8
-LzJsfrodKhTTrLpWOXi6YLRTk8dzsuPz/Nu98sJd1w3fHd20DrmkqsxVhgN1h+nk
-zcPpxyGYIP6qYVZCmIXCwZZNtPeb7y/tOs967VHoZ4Qj7p2tE0CAWFMZFGjA/pcZ
-7fi6CsIuMOYBbj4+wRlJwpG1g5zSJBCjzhv7dZp8S5oXmLShNYOMYEdsPfaZbm08
-3pVY+k8DVf7idcANXNw1lM+sPbE2hp5VuEuVpK+ca5x8hIMpTqJ84wDAjnC1kCwm
-X2xfNvYPKNF58SvqlNCPN8X7hQjoeaEb7w24vCdZMRqeGBmu1GNQvCyzbBO0huQm
-f5CQPrZjPcnoImlP879VPxY4YB6tAjsA/ZLiub9VdT108lCjb5r8criMzpMAA/AQ
-NqQLWFI3M43xPemGBTiIguTYgpRgGcdRZf7XuTgTY5qzQZZuZMVuwaqSD2cCAwEA
-AQKCAgEA0jMvw3BPTrakT7Lb8JgelKt7mUV6WyVMUZ6eh0pw5JIoJxAfEKfWYmjY
-NzKNRMjcv6LA2MP7MplTld/YI6ZHkl+Lm9VOISL39HVuV8mIThbFb+gT1INEvu1t
-IjRyT2SsQ67rmo377mLNmVtgg7mt3kfecjI44MpPGqad/CF4zmKVUKd4aI4BpYUM
-F8+dKf3bpoBEWA2RZwy2bGQmSXHW132vDoLR8y2knL04rCqJ+PrC/WWuULXEe9bS
-VtLV3yMBZq3qD4Fk/+7fILLPGvNFVdPi4htQiChYrM4rP9HzfaO63VieYMF0hR70
-pqoOznXj9Q4QVC9FZmUgFCQjQ1+KhqJw3OldIo0SnvpsLdTO/inKkhQWKC5HlPyh
-/rqvro2j3pTHWPAziuBr+oQPcdVCOlCBZ+B99L1tO7aGktVPEIVQG7G7jlFMBiJ1
-j/kRGk2RTX8RaPQJTnwUqp8mWUV2fwxHiXNadjejA5ZU3eQT2eAOhXl1w6Lv2jEl
-0wMOwPMJGcF77CcqnnWHON8fkxCbAfyy5Uo6Pm9g/Zzecn+ji2sabG7Ge5t0gzdL
-LKRcGoyakN2CrbQ8pxlCTgE4HX5oPY+VuqOf8L3AIWIJBsyLbXHVkL1mqQ/Ed2uz
-zaaSFYUZw81+m/5bl8JLPaIFNPyikZrXTD0YRer3V06XiyP/kYECggEBAP033xeF
-OhgRwkRTjd68hwRJpyHsZDWxHiUqQf6l6yFv5mEE355G2IGI7cZmR2+tUDjQdxLv
-tAZIszTK4PFCdVTeWfGVFbVF84eNWLB124pHDMM79GN/AMcuHnQPR756a8IO1hIy
-4KxIUE1a1PKN5b9IgE5Lu4TZM96HDpFcUAmCT5urdYDmg3++IWT9PYQlGS7Hhiar
-r+Hh646waM8Qx619CwXBqy+Y37+WHVbYqJClr6AcpVMrGA+6cgpskFpZAPLsoy7G
-RSsVfyV8pH2JKm/hzk7XCwIpczxeWQSfpJWZ+oOPFHu+zM60Cdj2UrQyKrNHwew8
-+WYe9eCA+MiNBcECggEBAPq/F1vdqROiLv9uzhKb8ybgdL7CmREELiqwK+MvNE9t
-W7lQz7lcWzav+b2n0M+VJBxUWB3XClgoIvA/AllgTgsYXfKAxNakhKLSBoMmvKCW
-HtWcGr/D3RcmacK+DTMWlVS/LuueAFLuH6UmBIUFKc+qA5x7oQecAFALBFupE3G4
-LtAspLBI6P8gRtRav5p2whs9H8qjYcyf2f6liWpkmFITcXvPvAxFHicR6ZJdwZ/S
-PiX2LJQnOpT7L3+2PWnYwzFStb4MkMGlFKcscU9CvS53JcP/J4Asjk0I4zDB2gri
-xzFHPlVzCr2IVVGptKCQ3sdYiMIzQKzEXQHCU8h37ycCggEBAJu8aC48Fz3Edlm1
-ldS+2L9vWSaJEBzhoSu0cMBgZVu8SdGzwKDE69XHVI4oS5lI28UFmaaA3JTc07MN
-cAmSGT2oP2NQkPhbXGsrKLfm1K6YAiZ1Ulp7OwxFth8lYreo7Wt92nV46yuqkhDx
-Y3UGhp39xkPhWiRbvgYHxJLsVqFyjumsK2mq3IeNdVZ6VgJXGsTlnAFeqJ7hZxHs
-N5natSRjeosA0PtGJ57agZLvT8Ue0gREef3LzFGoFwmIOcQHZ4kAt2BGOzZDU17H
-6Rb4bKxBEbT1l2St/5zKXi90zDHicOvG7Q8qiyY6HrBc1wLSs+ZtpLxZx/3h3tFE
-IT6fVUECggEBAMSAQm8Ey76OJ+SXUjk1K50442SnHcs/Cmr7urkEQitImUwl71Pk
-87pst/uP6szypOTqmE9yOTIS6iZ6Sn3+QcriIqWrkhZfwW3Tx7S6A7KZUrq15iSH
-+thsiw9JXxC9TvOmC8AsBzb2U6hZncsc28JZCxFztSNAduJDb/vhCVLiMxWDFuDr
-kmR1R+yc3XDQRpeQFDz6QudYEj9EPOc6xD/16sZLaqP2+oVFvVSt0tJLsdaQECle
-gMNGAdhE2eX8MCOUHMc+E6cdlozYAEhMFfO2/cqWR79jq3TlVR3dnOFRDScqHMhc
-KnuTvsELjHkUbvGsCSiff7yk+fop7vy4OJsCggEAPemJdItO2rhib8EofrZdY72I
-oifX1jhPZ1BWD2GKgcx+eVyJGbONBbJVexvvskTfZBvCcAegmgp+sngP6MO6yZkr
-cHMfAJeApYZnshsgXksHGMDtSB50/w1JLrc/nqpxdpy/aTazt0Eu1pLWpze1HFZ/
-Xyu4PcmrU+4P1vN7c396slHMktEvly6QqOn4nfBbGDJ17Ow6X1XFvGjAxQPIDTB+
-6loV14AHymwmqwMrGn84O72rzqyw+41GxW5+oXhOZ4MeXF3u89TBLWvXDpPy/YQU
-EiKpodN0YeEn6Ghzplan8rUha+7TP7AYnS5pCszsCHKd03Py0lMLkF+uAfVsDA==
------END RSA PRIVATE KEY-----
diff --git a/packages/Tethering/apex/com.android.tethering.pk8 b/packages/Tethering/apex/com.android.tethering.pk8
deleted file mode 100644
index 3b94405945cb5..0000000000000
Binary files a/packages/Tethering/apex/com.android.tethering.pk8 and /dev/null differ
diff --git a/packages/Tethering/apex/com.android.tethering.x509.pem b/packages/Tethering/apex/com.android.tethering.x509.pem
deleted file mode 100644
index a1786e35e8545..0000000000000
--- a/packages/Tethering/apex/com.android.tethering.x509.pem
+++ /dev/null
@@ -1,35 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIGKTCCBBGgAwIBAgIUNiSs5EMqxCZ31gWWCcRJVp9HffAwDQYJKoZIhvcNAQEL
-BQAwgaIxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH
-DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy
-b2lkMR4wHAYDVQQDDBVjb20uYW5kcm9pZC50ZXRoZXJpbmcxIjAgBgkqhkiG9w0B
-CQEWE2FuZHJvaWRAYW5kcm9pZC5jb20wIBcNMTkxMjE4MDcwMDQ4WhgPNDc1NzEx
-MTMwNzAwNDhaMIGiMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEW
-MBQGA1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UE
-CwwHQW5kcm9pZDEeMBwGA1UEAwwVY29tLmFuZHJvaWQudGV0aGVyaW5nMSIwIAYJ
-KoZIhvcNAQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMIICIjANBgkqhkiG9w0BAQEF
-AAOCAg8AMIICCgKCAgEAxvTUA4seblYjZLfTVNwZuJH914QVNFTj+vD94pWmt5Aq
-sH1DVTpBvpXXegc/P5HI2XF/71poSBib1WaQSuXG0fU5K75T18bOGL0qF+fhMtBO
-wUyvulcjO0h4XE/xf0txY54exUjAA4JS9ERGJOgb4GOwSbPyzekfmzIyCZ2Yawwu
-+oGwD2ZNzZRaPOoWxjwohBWQ6mySuvF9RRRb300qmxxUGFM9Ki3aqrWlYlHEOwOC
-M+gIXxYFO7S+yUzf6/gMZLOz2YqfcTOup4hAxtExR7niutxJSsRLPBL237exAJoz
-OupoXjtWAlPK4ZwZ/Nl1jdTWauJ+Kv3WqzhHGEb2gn3ZpeO3IdOjJhDgFJ6m1OT/
-kjRbW1LCuKGrKaoqsEDT2X3a7Izfripn65hSNTfR5gNLtgELaI3/vXi8Fmzw1AfH
-+qi6ulElZvSwx0qm+S0QiPyGFlxrsdnHoGJl1tzjJW8KdNZRvzRLUQtbphPp+VkL
-5i0bNKum+AwbfdUkLkNLfw9XdbujgBkZTZDQbZGsNjgrvyXcPO2KiJee0hVCZRs0
-rhDi5Pfm7BnN/I2vaTRz/W4mdct9H2RWMuqlSH90JvmKtWcND8ahmOJ3sggrvzfO
-QNs3k4JTRecamMzqIkylhlnEC4FjWc6Bx4wsEpwBMZOkF/tGGMZYf2C09a8tpP0C
-AwEAAaNTMFEwHQYDVR0OBBYEFNP5gIpNWmq0xa411M1GaRPbEijvMB8GA1UdIwQY
-MBaAFNP5gIpNWmq0xa411M1GaRPbEijvMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZI
-hvcNAQELBQADggIBADJGmU3QP4EGbt6eBhVPeo/efsqrHsuB2fvFzvIobJbfkSob
-cmvjbzIikOlPAgFWj8lT5SDcIWRorFf1u2JylClJ0nSDcqJMHVKmT7wseV/KtX//
-1yUyJFRQVzmjC89dp8OIc00GmItivKLer3NbJdkR3rTUjg7+bNUO27Qp3AFREmiJ
-P+M7ouvcQRvByUWbp/LOrJpMdJLysRBO562RwrtwTjltdvufyYswbBZOKEiUh1Jc
-Ged+3+SJdhwq3Wy+R3Uj7YE7mUMu1QNbANIMrwF8W93EA53eoL2+cKmuaVU6ZURL
-xgSJaY6TrunnSI9XTROLtjsFlJorYWy2tvG7Q5Hw3OkO2Xdz/mm85VTkiusg9DMB
-WWTv607YtsIO0FhKmcV4bp3q/EkRj3t/zLvL9uFJrWDGkuShZq6fQvqbCvaokOPY
-+M0ZRIwgwa9UpEE0BMklVWqR6BGyap614gOgcOjYM70WRNl59Qne+g128ZN7g9nz
-61F70i7kUngV0ZUz1/Fu/NCG+6wGF85ZbFmQl60YHPDw1FtjVUuKyBblaDzdJunx
-yQr2t9RUokzFBFK0lGW3+yf0WDQ5fqTMs5h8bz1FCq8/HzWmpdOfqePLe4zsld3b
-1nFuSohaIfbn/HDdTNtTBGQPgz8ZswQ6ejJJqTLz9D/odbqn9LeIhDZXcQTf
------END CERTIFICATE-----
diff --git a/packages/Tethering/apex/manifest.json b/packages/Tethering/apex/manifest.json
deleted file mode 100644
index 8836c4e50333b..0000000000000
--- a/packages/Tethering/apex/manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "com.android.tethering",
- "version": 300900700
-}
diff --git a/packages/Tethering/bpf_progs/Android.bp b/packages/Tethering/bpf_progs/Android.bp
deleted file mode 100644
index d54f861486653..0000000000000
--- a/packages/Tethering/bpf_progs/Android.bp
+++ /dev/null
@@ -1,33 +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.
-//
-
-//
-// bpf kernel programs
-//
-bpf {
- name: "offload.o",
- srcs: ["offload.c"],
- cflags: [
- "-Wall",
- "-Werror",
- ],
- include_dirs: [
- // TODO: get rid of system/netd.
- "system/netd/bpf_progs", // for bpf_net_helpers.h
- "system/netd/libnetdbpf/include", // for bpf_shared.h
- "system/netd/libnetdutils/include", // for UidConstants.h
- ],
-}
diff --git a/packages/Tethering/bpf_progs/offload.c b/packages/Tethering/bpf_progs/offload.c
deleted file mode 100644
index cc5af3127b02c..0000000000000
--- a/packages/Tethering/bpf_progs/offload.c
+++ /dev/null
@@ -1,207 +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.
- */
-
-#include
-#include
-#include
-#include
-#include
-
-#include "bpf_helpers.h"
-#include "bpf_net_helpers.h"
-#include "netdbpf/bpf_shared.h"
-
-DEFINE_BPF_MAP_GRW(tether_ingress_map, HASH, TetherIngressKey, TetherIngressValue, 64,
- AID_NETWORK_STACK)
-
-// Tethering stats, indexed by upstream interface.
-DEFINE_BPF_MAP_GRW(tether_stats_map, HASH, uint32_t, TetherStatsValue, 16, AID_NETWORK_STACK)
-
-// Tethering data limit, indexed by upstream interface.
-// (tethering allowed when stats[iif].rxBytes + stats[iif].txBytes < limit[iif])
-DEFINE_BPF_MAP_GRW(tether_limit_map, HASH, uint32_t, uint64_t, 16, AID_NETWORK_STACK)
-
-static inline __always_inline int do_forward(struct __sk_buff* skb, bool is_ethernet) {
- int l2_header_size = is_ethernet ? sizeof(struct ethhdr) : 0;
- void* data = (void*)(long)skb->data;
- const void* data_end = (void*)(long)skb->data_end;
- struct ethhdr* eth = is_ethernet ? data : NULL; // used iff is_ethernet
- struct ipv6hdr* ip6 = is_ethernet ? (void*)(eth + 1) : data;
-
- // Must be meta-ethernet IPv6 frame
- if (skb->protocol != htons(ETH_P_IPV6)) return TC_ACT_OK;
-
- // Must have (ethernet and) ipv6 header
- if (data + l2_header_size + sizeof(*ip6) > data_end) return TC_ACT_OK;
-
- // Ethertype - if present - must be IPv6
- if (is_ethernet && (eth->h_proto != htons(ETH_P_IPV6))) return TC_ACT_OK;
-
- // IP version must be 6
- if (ip6->version != 6) return TC_ACT_OK;
-
- // Cannot decrement during forward if already zero or would be zero,
- // Let the kernel's stack handle these cases and generate appropriate ICMP errors.
- if (ip6->hop_limit <= 1) return TC_ACT_OK;
-
- // Protect against forwarding packets sourced from ::1 or fe80::/64 or other weirdness.
- __be32 src32 = ip6->saddr.s6_addr32[0];
- if (src32 != htonl(0x0064ff9b) && // 64:ff9b:/32 incl. XLAT464 WKP
- (src32 & htonl(0xe0000000)) != htonl(0x20000000)) // 2000::/3 Global Unicast
- return TC_ACT_OK;
-
- TetherIngressKey k = {
- .iif = skb->ifindex,
- .neigh6 = ip6->daddr,
- };
-
- TetherIngressValue* v = bpf_tether_ingress_map_lookup_elem(&k);
-
- // If we don't find any offload information then simply let the core stack handle it...
- if (!v) return TC_ACT_OK;
-
- uint32_t stat_and_limit_k = skb->ifindex;
-
- TetherStatsValue* stat_v = bpf_tether_stats_map_lookup_elem(&stat_and_limit_k);
-
- // If we don't have anywhere to put stats, then abort...
- if (!stat_v) return TC_ACT_OK;
-
- uint64_t* limit_v = bpf_tether_limit_map_lookup_elem(&stat_and_limit_k);
-
- // If we don't have a limit, then abort...
- if (!limit_v) return TC_ACT_OK;
-
- // Required IPv6 minimum mtu is 1280, below that not clear what we should do, abort...
- const int pmtu = v->pmtu;
- if (pmtu < IPV6_MIN_MTU) return TC_ACT_OK;
-
- // Approximate handling of TCP/IPv6 overhead for incoming LRO/GRO packets: default
- // outbound path mtu of 1500 is not necessarily correct, but worst case we simply
- // undercount, which is still better then not accounting for this overhead at all.
- // Note: this really shouldn't be device/path mtu at all, but rather should be
- // derived from this particular connection's mss (ie. from gro segment size).
- // This would require a much newer kernel with newer ebpf accessors.
- // (This is also blindly assuming 12 bytes of tcp timestamp option in tcp header)
- uint64_t packets = 1;
- uint64_t bytes = skb->len;
- if (bytes > pmtu) {
- const int tcp_overhead = sizeof(struct ipv6hdr) + sizeof(struct tcphdr) + 12;
- const int mss = pmtu - tcp_overhead;
- const uint64_t payload = bytes - tcp_overhead;
- packets = (payload + mss - 1) / mss;
- bytes = tcp_overhead * packets + payload;
- }
-
- // Are we past the limit? If so, then abort...
- // Note: will not overflow since u64 is 936 years even at 5Gbps.
- // Do not drop here. Offload is just that, whenever we fail to handle
- // a packet we let the core stack deal with things.
- // (The core stack needs to handle limits correctly anyway,
- // since we don't offload all traffic in both directions)
- if (stat_v->rxBytes + stat_v->txBytes + bytes > *limit_v) return TC_ACT_OK;
-
- if (!is_ethernet) {
- is_ethernet = true;
- l2_header_size = sizeof(struct ethhdr);
- // Try to inject an ethernet header, and simply return if we fail
- if (bpf_skb_change_head(skb, l2_header_size, /*flags*/ 0)) {
- __sync_fetch_and_add(&stat_v->rxErrors, 1);
- return TC_ACT_OK;
- }
-
- // bpf_skb_change_head() invalidates all pointers - reload them
- data = (void*)(long)skb->data;
- data_end = (void*)(long)skb->data_end;
- eth = data;
- ip6 = (void*)(eth + 1);
-
- // I do not believe this can ever happen, but keep the verifier happy...
- if (data + l2_header_size + sizeof(*ip6) > data_end) {
- __sync_fetch_and_add(&stat_v->rxErrors, 1);
- return TC_ACT_SHOT;
- }
- };
-
- // CHECKSUM_COMPLETE is a 16-bit one's complement sum,
- // thus corrections for it need to be done in 16-byte chunks at even offsets.
- // IPv6 nexthdr is at offset 6, while hop limit is at offset 7
- uint8_t old_hl = ip6->hop_limit;
- --ip6->hop_limit;
- uint8_t new_hl = ip6->hop_limit;
-
- // bpf_csum_update() always succeeds if the skb is CHECKSUM_COMPLETE and returns an error
- // (-ENOTSUPP) if it isn't.
- bpf_csum_update(skb, 0xFFFF - ntohs(old_hl) + ntohs(new_hl));
-
- __sync_fetch_and_add(&stat_v->rxPackets, packets);
- __sync_fetch_and_add(&stat_v->rxBytes, bytes);
-
- // Overwrite any mac header with the new one
- *eth = v->macHeader;
-
- // Redirect to forwarded interface.
- //
- // Note that bpf_redirect() cannot fail unless you pass invalid flags.
- // The redirect actually happens after the ebpf program has already terminated,
- // and can fail for example for mtu reasons at that point in time, but there's nothing
- // we can do about it here.
- return bpf_redirect(v->oif, 0 /* this is effectively BPF_F_EGRESS */);
-}
-
-SEC("schedcls/ingress/tether_ether")
-int sched_cls_ingress_tether_ether(struct __sk_buff* skb) {
- return do_forward(skb, true);
-}
-
-// Note: section names must be unique to prevent programs from appending to each other,
-// so instead the bpf loader will strip everything past the final $ symbol when actually
-// pinning the program into the filesystem.
-//
-// bpf_skb_change_head() is only present on 4.14+ and 2 trivial kernel patches are needed:
-// ANDROID: net: bpf: Allow TC programs to call BPF_FUNC_skb_change_head
-// ANDROID: net: bpf: permit redirect from ingress L3 to egress L2 devices at near max mtu
-// (the first of those has already been upstreamed)
-//
-// 5.4 kernel support was only added to Android Common Kernel in R,
-// and thus a 5.4 kernel always supports this.
-//
-// Hence, this mandatory (must load successfully) implementation for 5.4+ kernels:
-DEFINE_BPF_PROG_KVER("schedcls/ingress/tether_rawip$5_4", AID_ROOT, AID_ROOT,
- sched_cls_ingress_tether_rawip_5_4, KVER(5, 4, 0))
-(struct __sk_buff* skb) {
- return do_forward(skb, false);
-}
-
-// and this identical optional (may fail to load) implementation for [4.14..5.4) patched kernels:
-DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE("schedcls/ingress/tether_rawip$4_14", AID_ROOT, AID_ROOT,
- sched_cls_ingress_tether_rawip_4_14, KVER(4, 14, 0),
- KVER(5, 4, 0))
-(struct __sk_buff* skb) {
- return do_forward(skb, false);
-}
-
-// and define a no-op stub for [4.9,4.14) and unpatched [4.14,5.4) kernels.
-// (if the above real 4.14+ program loaded successfully, then bpfloader will have already pinned
-// it at the same location this one would be pinned at and will thus skip loading this stub)
-DEFINE_BPF_PROG_KVER_RANGE("schedcls/ingress/tether_rawip$stub", AID_ROOT, AID_ROOT,
- sched_cls_ingress_tether_rawip_stub, KVER_NONE, KVER(5, 4, 0))
-(struct __sk_buff* skb) {
- return TC_ACT_OK;
-}
-
-LICENSE("Apache 2.0");
-CRITICAL("netd");
diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp
deleted file mode 100644
index ddb6880753b4d..0000000000000
--- a/packages/Tethering/common/TetheringLib/Android.bp
+++ /dev/null
@@ -1,50 +0,0 @@
-//
-// Copyright (C) 2019 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.
-
-java_sdk_library {
- name: "framework-tethering",
- defaults: ["framework-module-defaults"],
- impl_library_visibility: [
- "//frameworks/base/packages/Tethering:__subpackages__",
- "//packages/modules/Connectivity/Tethering:__subpackages__",
- ],
-
- srcs: [":framework-tethering-srcs"],
-
- jarjar_rules: "jarjar-rules.txt",
- installable: true,
-
- hostdex: true, // for hiddenapi check
- apex_available: ["com.android.tethering"],
- permitted_packages: ["android.net"],
-}
-
-filegroup {
- name: "framework-tethering-srcs",
- srcs: [
- "src/android/net/TetheredClient.aidl",
- "src/android/net/TetheredClient.java",
- "src/android/net/TetheringManager.java",
- "src/android/net/TetheringConstants.java",
- "src/android/net/IIntResultListener.aidl",
- "src/android/net/ITetheringEventCallback.aidl",
- "src/android/net/ITetheringConnector.aidl",
- "src/android/net/TetheringCallbackStartedParcel.aidl",
- "src/android/net/TetheringConfigurationParcel.aidl",
- "src/android/net/TetheringRequestParcel.aidl",
- "src/android/net/TetherStatesParcel.aidl",
- ],
- path: "src"
-}
diff --git a/packages/Tethering/common/TetheringLib/api/current.txt b/packages/Tethering/common/TetheringLib/api/current.txt
deleted file mode 100644
index d802177e249b3..0000000000000
--- a/packages/Tethering/common/TetheringLib/api/current.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/packages/Tethering/common/TetheringLib/api/module-lib-current.txt b/packages/Tethering/common/TetheringLib/api/module-lib-current.txt
deleted file mode 100644
index 6ddb122936e7f..0000000000000
--- a/packages/Tethering/common/TetheringLib/api/module-lib-current.txt
+++ /dev/null
@@ -1,41 +0,0 @@
-// Signature format: 2.0
-package android.net {
-
- public final class TetheringConstants {
- field public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
- field public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
- field public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
- field public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
- field public static final String EXTRA_SET_ALARM = "extraSetAlarm";
- }
-
- public class TetheringManager {
- ctor public TetheringManager(@NonNull android.content.Context, @NonNull java.util.function.Supplier);
- method public int getLastTetherError(@NonNull String);
- method @NonNull public String[] getTetherableBluetoothRegexs();
- method @NonNull public String[] getTetherableIfaces();
- method @NonNull public String[] getTetherableUsbRegexs();
- method @NonNull public String[] getTetherableWifiRegexs();
- method @NonNull public String[] getTetheredIfaces();
- method @NonNull public String[] getTetheringErroredIfaces();
- method public boolean isTetheringSupported();
- method public boolean isTetheringSupported(@NonNull String);
- method public void requestLatestTetheringEntitlementResult(int, @NonNull android.os.ResultReceiver, boolean);
- method @Deprecated public int setUsbTethering(boolean);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(int, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @Deprecated public int tether(@NonNull String);
- method @Deprecated public int untether(@NonNull String);
- }
-
- public static interface TetheringManager.TetheringEventCallback {
- method public default void onTetherableInterfaceRegexpsChanged(@NonNull android.net.TetheringManager.TetheringInterfaceRegexps);
- }
-
- public static class TetheringManager.TetheringInterfaceRegexps {
- method @NonNull public java.util.List getTetherableBluetoothRegexs();
- method @NonNull public java.util.List getTetherableUsbRegexs();
- method @NonNull public java.util.List getTetherableWifiRegexs();
- }
-
-}
-
diff --git a/packages/Tethering/common/TetheringLib/api/module-lib-removed.txt b/packages/Tethering/common/TetheringLib/api/module-lib-removed.txt
deleted file mode 100644
index d802177e249b3..0000000000000
--- a/packages/Tethering/common/TetheringLib/api/module-lib-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/packages/Tethering/common/TetheringLib/api/removed.txt b/packages/Tethering/common/TetheringLib/api/removed.txt
deleted file mode 100644
index d802177e249b3..0000000000000
--- a/packages/Tethering/common/TetheringLib/api/removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/packages/Tethering/common/TetheringLib/api/system-current.txt b/packages/Tethering/common/TetheringLib/api/system-current.txt
deleted file mode 100644
index edd1ebb5f751e..0000000000000
--- a/packages/Tethering/common/TetheringLib/api/system-current.txt
+++ /dev/null
@@ -1,99 +0,0 @@
-// Signature format: 2.0
-package android.net {
-
- public final class TetheredClient implements android.os.Parcelable {
- ctor public TetheredClient(@NonNull android.net.MacAddress, @NonNull java.util.Collection, int);
- method public int describeContents();
- method @NonNull public java.util.List getAddresses();
- method @NonNull public android.net.MacAddress getMacAddress();
- method public int getTetheringType();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator CREATOR;
- }
-
- public static final class TetheredClient.AddressInfo implements android.os.Parcelable {
- method public int describeContents();
- method @NonNull public android.net.LinkAddress getAddress();
- method @Nullable public String getHostname();
- method public void writeToParcel(@NonNull android.os.Parcel, int);
- field @NonNull public static final android.os.Parcelable.Creator CREATOR;
- }
-
- public class TetheringManager {
- method @RequiresPermission(android.Manifest.permission.ACCESS_NETWORK_STATE) public void registerTetheringEventCallback(@NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.TetheringEventCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void requestLatestTetheringEntitlementResult(int, boolean, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.OnTetheringEntitlementResultListener);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void startTethering(@NonNull android.net.TetheringManager.TetheringRequest, @NonNull java.util.concurrent.Executor, @NonNull android.net.TetheringManager.StartTetheringCallback);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopAllTethering();
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public void stopTethering(int);
- method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.ACCESS_NETWORK_STATE}) public void unregisterTetheringEventCallback(@NonNull android.net.TetheringManager.TetheringEventCallback);
- field public static final String ACTION_TETHER_STATE_CHANGED = "android.net.conn.TETHER_STATE_CHANGED";
- field public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
- field public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
- field public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
- field public static final String EXTRA_ERRORED_TETHER = "erroredArray";
- field public static final int TETHERING_BLUETOOTH = 2; // 0x2
- field public static final int TETHERING_ETHERNET = 5; // 0x5
- field public static final int TETHERING_INVALID = -1; // 0xffffffff
- field public static final int TETHERING_NCM = 4; // 0x4
- field public static final int TETHERING_USB = 1; // 0x1
- field public static final int TETHERING_WIFI = 0; // 0x0
- field public static final int TETHERING_WIFI_P2P = 3; // 0x3
- field public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12; // 0xc
- field public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9; // 0x9
- field public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8; // 0x8
- field public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13; // 0xd
- field public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10; // 0xa
- field public static final int TETHER_ERROR_INTERNAL_ERROR = 5; // 0x5
- field public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15; // 0xf
- field public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14; // 0xe
- field public static final int TETHER_ERROR_NO_ERROR = 0; // 0x0
- field public static final int TETHER_ERROR_PROVISIONING_FAILED = 11; // 0xb
- field public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2; // 0x2
- field public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6; // 0x6
- field public static final int TETHER_ERROR_UNAVAIL_IFACE = 4; // 0x4
- field public static final int TETHER_ERROR_UNKNOWN_IFACE = 1; // 0x1
- field public static final int TETHER_ERROR_UNKNOWN_TYPE = 16; // 0x10
- field public static final int TETHER_ERROR_UNSUPPORTED = 3; // 0x3
- field public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7; // 0x7
- field public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2; // 0x2
- field public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1; // 0x1
- field public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0; // 0x0
- }
-
- public static interface TetheringManager.OnTetheringEntitlementResultListener {
- method public void onTetheringEntitlementResult(int);
- }
-
- public static interface TetheringManager.StartTetheringCallback {
- method public default void onTetheringFailed(int);
- method public default void onTetheringStarted();
- }
-
- public static interface TetheringManager.TetheringEventCallback {
- method public default void onClientsChanged(@NonNull java.util.Collection);
- method public default void onError(@NonNull String, int);
- method public default void onOffloadStatusChanged(int);
- method public default void onTetherableInterfacesChanged(@NonNull java.util.List);
- method public default void onTetheredInterfacesChanged(@NonNull java.util.List);
- method public default void onTetheringSupported(boolean);
- method public default void onUpstreamChanged(@Nullable android.net.Network);
- }
-
- public static class TetheringManager.TetheringRequest {
- method @Nullable public android.net.LinkAddress getClientStaticIpv4Address();
- method @Nullable public android.net.LinkAddress getLocalIpv4Address();
- method public boolean getShouldShowEntitlementUi();
- method public int getTetheringType();
- method public boolean isExemptFromEntitlementCheck();
- }
-
- public static class TetheringManager.TetheringRequest.Builder {
- ctor public TetheringManager.TetheringRequest.Builder(int);
- method @NonNull public android.net.TetheringManager.TetheringRequest build();
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setExemptFromEntitlementCheck(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setShouldShowEntitlementUi(boolean);
- method @NonNull @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public android.net.TetheringManager.TetheringRequest.Builder setStaticIpv4Addresses(@NonNull android.net.LinkAddress, @NonNull android.net.LinkAddress);
- }
-
-}
-
diff --git a/packages/Tethering/common/TetheringLib/api/system-removed.txt b/packages/Tethering/common/TetheringLib/api/system-removed.txt
deleted file mode 100644
index d802177e249b3..0000000000000
--- a/packages/Tethering/common/TetheringLib/api/system-removed.txt
+++ /dev/null
@@ -1 +0,0 @@
-// Signature format: 2.0
diff --git a/packages/Tethering/common/TetheringLib/jarjar-rules.txt b/packages/Tethering/common/TetheringLib/jarjar-rules.txt
deleted file mode 100644
index e459fad549932..0000000000000
--- a/packages/Tethering/common/TetheringLib/jarjar-rules.txt
+++ /dev/null
@@ -1 +0,0 @@
-# jarjar rules for the bootclasspath tethering framework library here
\ No newline at end of file
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/IIntResultListener.aidl b/packages/Tethering/common/TetheringLib/src/android/net/IIntResultListener.aidl
deleted file mode 100644
index c3d66ee145260..0000000000000
--- a/packages/Tethering/common/TetheringLib/src/android/net/IIntResultListener.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net;
-
-/**
- * Listener interface allowing objects to listen to various module event.
- * {@hide}
- */
-oneway interface IIntResultListener {
- void onResult(int resultCode);
-}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
deleted file mode 100644
index cf094aac2cbe9..0000000000000
--- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringConnector.aidl
+++ /dev/null
@@ -1,52 +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 android.net;
-
-import android.net.IIntResultListener;
-import android.net.ITetheringEventCallback;
-import android.net.TetheringRequestParcel;
-import android.os.ResultReceiver;
-
-/** @hide */
-oneway interface ITetheringConnector {
- void tether(String iface, String callerPkg, String callingAttributionTag,
- IIntResultListener receiver);
-
- void untether(String iface, String callerPkg, String callingAttributionTag,
- IIntResultListener receiver);
-
- void setUsbTethering(boolean enable, String callerPkg,
- String callingAttributionTag, IIntResultListener receiver);
-
- void startTethering(in TetheringRequestParcel request, String callerPkg,
- String callingAttributionTag, IIntResultListener receiver);
-
- void stopTethering(int type, String callerPkg, String callingAttributionTag,
- IIntResultListener receiver);
-
- void requestLatestTetheringEntitlementResult(int type, in ResultReceiver receiver,
- boolean showEntitlementUi, String callerPkg, String callingAttributionTag);
-
- void registerTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);
-
- void unregisterTetheringEventCallback(ITetheringEventCallback callback, String callerPkg);
-
- void isTetheringSupported(String callerPkg, String callingAttributionTag,
- IIntResultListener receiver);
-
- void stopAllTethering(String callerPkg, String callingAttributionTag,
- IIntResultListener receiver);
-}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl b/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
deleted file mode 100644
index b4e3ba46791c6..0000000000000
--- a/packages/Tethering/common/TetheringLib/src/android/net/ITetheringEventCallback.aidl
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net;
-
-import android.net.Network;
-import android.net.TetheredClient;
-import android.net.TetheringConfigurationParcel;
-import android.net.TetheringCallbackStartedParcel;
-import android.net.TetherStatesParcel;
-
-/**
- * Callback class for receiving tethering changed events.
- * @hide
- */
-oneway interface ITetheringEventCallback
-{
- /** Called immediately after the callbacks are registered */
- void onCallbackStarted(in TetheringCallbackStartedParcel parcel);
- void onCallbackStopped(int errorCode);
- void onUpstreamChanged(in Network network);
- void onConfigurationChanged(in TetheringConfigurationParcel config);
- void onTetherStatesChanged(in TetherStatesParcel states);
- void onTetherClientsChanged(in List clients);
- void onOffloadStatusChanged(int status);
-}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl
deleted file mode 100644
index 3d842b3374284..0000000000000
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetherStatesParcel.aidl
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net;
-
-/**
- * Status details for tethering downstream interfaces.
- * {@hide}
- */
-parcelable TetherStatesParcel {
- String[] availableList;
- String[] tetheredList;
- String[] localOnlyList;
- String[] erroredIfaceList;
- // List of Last error code corresponding to each errored iface in erroredIfaceList. */
- // TODO: Improve this as b/143122247.
- int[] lastErrorList;
-}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl
deleted file mode 100644
index 0b279b882367a..0000000000000
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.aidl
+++ /dev/null
@@ -1,18 +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 android.net;
-
-@JavaOnlyStableParcelable parcelable TetheredClient;
\ No newline at end of file
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
deleted file mode 100644
index 0b223f42b9541..0000000000000
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheredClient.java
+++ /dev/null
@@ -1,239 +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 android.net;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * Information on a tethered downstream client.
- * @hide
- */
-@SystemApi
-public final class TetheredClient implements Parcelable {
- @NonNull
- private final MacAddress mMacAddress;
- @NonNull
- private final List mAddresses;
- // TODO: use an @IntDef here
- private final int mTetheringType;
-
- public TetheredClient(@NonNull MacAddress macAddress,
- @NonNull Collection addresses, int tetheringType) {
- mMacAddress = macAddress;
- mAddresses = new ArrayList<>(addresses);
- mTetheringType = tetheringType;
- }
-
- private TetheredClient(@NonNull Parcel in) {
- this(in.readParcelable(null), in.createTypedArrayList(AddressInfo.CREATOR), in.readInt());
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeParcelable(mMacAddress, flags);
- dest.writeTypedList(mAddresses);
- dest.writeInt(mTetheringType);
- }
-
- /**
- * Get the MAC address used to identify the client.
- */
- @NonNull
- public MacAddress getMacAddress() {
- return mMacAddress;
- }
-
- /**
- * Get information on the list of addresses that are associated with the client.
- */
- @NonNull
- public List getAddresses() {
- return new ArrayList<>(mAddresses);
- }
-
- /**
- * Get the type of tethering used by the client.
- * @return one of the {@code TetheringManager#TETHERING_*} constants.
- */
- public int getTetheringType() {
- return mTetheringType;
- }
-
- /**
- * Return a new {@link TetheredClient} that has all the attributes of this instance, plus the
- * {@link AddressInfo} of the provided {@link TetheredClient}.
- *
- *
Duplicate addresses are removed.
- * @hide
- */
- public TetheredClient addAddresses(@NonNull TetheredClient other) {
- final LinkedHashSet newAddresses = new LinkedHashSet<>(
- mAddresses.size() + other.mAddresses.size());
- newAddresses.addAll(mAddresses);
- newAddresses.addAll(other.mAddresses);
- return new TetheredClient(mMacAddress, newAddresses, mTetheringType);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mMacAddress, mAddresses, mTetheringType);
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof TetheredClient)) return false;
- final TetheredClient other = (TetheredClient) obj;
- return mMacAddress.equals(other.mMacAddress)
- && mAddresses.equals(other.mAddresses)
- && mTetheringType == other.mTetheringType;
- }
-
- /**
- * Information on an lease assigned to a tethered client.
- */
- public static final class AddressInfo implements Parcelable {
- @NonNull
- private final LinkAddress mAddress;
- @Nullable
- private final String mHostname;
-
- /** @hide */
- public AddressInfo(@NonNull LinkAddress address, @Nullable String hostname) {
- this.mAddress = address;
- this.mHostname = hostname;
- }
-
- private AddressInfo(Parcel in) {
- this(in.readParcelable(null), in.readString());
- }
-
- @Override
- public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeParcelable(mAddress, flags);
- dest.writeString(mHostname);
- }
-
- /**
- * Get the link address (including prefix length and lifetime) used by the client.
- *
- * This may be an IPv4 or IPv6 address.
- */
- @NonNull
- public LinkAddress getAddress() {
- return mAddress;
- }
-
- /**
- * Get the hostname that was advertised by the client when obtaining its address, if any.
- */
- @Nullable
- public String getHostname() {
- return mHostname;
- }
-
- /**
- * Get the expiration time of the address assigned to the client.
- * @hide
- */
- public long getExpirationTime() {
- return mAddress.getExpirationTime();
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mAddress, mHostname);
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof AddressInfo)) return false;
- final AddressInfo other = (AddressInfo) obj;
- // Use .equals() for addresses as all changes, including address expiry changes,
- // should be included.
- return other.mAddress.equals(mAddress)
- && Objects.equals(mHostname, other.mHostname);
- }
-
- @NonNull
- public static final Creator CREATOR = new Creator() {
- @NonNull
- @Override
- public AddressInfo createFromParcel(@NonNull Parcel in) {
- return new AddressInfo(in);
- }
-
- @NonNull
- @Override
- public AddressInfo[] newArray(int size) {
- return new AddressInfo[size];
- }
- };
-
- @NonNull
- @Override
- public String toString() {
- return "AddressInfo {"
- + mAddress
- + (mHostname != null ? ", hostname " + mHostname : "")
- + "}";
- }
- }
-
- @Override
- public int describeContents() {
- return 0;
- }
-
- @NonNull
- public static final Creator CREATOR = new Creator() {
- @NonNull
- @Override
- public TetheredClient createFromParcel(@NonNull Parcel in) {
- return new TetheredClient(in);
- }
-
- @NonNull
- @Override
- public TetheredClient[] newArray(int size) {
- return new TetheredClient[size];
- }
- };
-
- @NonNull
- @Override
- public String toString() {
- return "TetheredClient {hwAddr " + mMacAddress
- + ", addresses " + mAddresses
- + ", tetheringType " + mTetheringType
- + "}";
- }
-}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
deleted file mode 100644
index 253eacbd23e79..0000000000000
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringCallbackStartedParcel.aidl
+++ /dev/null
@@ -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 android.net;
-
-import android.net.Network;
-import android.net.TetheredClient;
-import android.net.TetheringConfigurationParcel;
-import android.net.TetherStatesParcel;
-
-/**
- * Initial information reported by tethering upon callback registration.
- * @hide
- */
-parcelable TetheringCallbackStartedParcel {
- boolean tetheringSupported;
- Network upstreamNetwork;
- TetheringConfigurationParcel config;
- TetherStatesParcel states;
- List tetheredClients;
- int offloadStatus;
-}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl
deleted file mode 100644
index 89f38132ffadc..0000000000000
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConfigurationParcel.aidl
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net;
-
-/**
- * Configuration details for tethering.
- * @hide
- */
-parcelable TetheringConfigurationParcel {
- int subId;
- String[] tetherableUsbRegexs;
- String[] tetherableWifiRegexs;
- String[] tetherableBluetoothRegexs;
- boolean isDunRequired;
- boolean chooseUpstreamAutomatically;
- int[] preferredUpstreamIfaceTypes;
- String[] legacyDhcpRanges;
- String[] defaultIPv4DNS;
- boolean enableLegacyDhcpServer;
- String[] provisioningApp;
- String provisioningAppNoUi;
- int provisioningCheckPeriod;
-}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
deleted file mode 100644
index f14def6a3a02a..0000000000000
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringConstants.java
+++ /dev/null
@@ -1,93 +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 android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-
-import android.annotation.SystemApi;
-import android.os.ResultReceiver;
-
-/**
- * Collections of constants for internal tethering usage.
- *
- *
These hidden constants are not in TetheringManager as they are not part of the API stubs
- * generated for TetheringManager, which prevents the tethering module from linking them at
- * build time.
- * TODO: investigate changing the tethering build rules so that Tethering can reference hidden
- * symbols from framework-tethering even when they are in a non-hidden class.
- * @hide
- */
-@SystemApi(client = MODULE_LIBRARIES)
-public final class TetheringConstants {
- /** An explicit private class to avoid exposing constructor.*/
- private TetheringConstants() { }
-
- /**
- * Extra used for communicating with the TetherService and TetherProvisioningActivity.
- * Includes the type of tethering to enable if any.
- */
- public static final String EXTRA_ADD_TETHER_TYPE = "extraAddTetherType";
- /**
- * Extra used for communicating with the TetherService. Includes the type of tethering for
- * which to cancel provisioning.
- */
- public static final String EXTRA_REM_TETHER_TYPE = "extraRemTetherType";
- /**
- * Extra used for communicating with the TetherService. True to schedule a recheck of tether
- * provisioning.
- */
- public static final String EXTRA_SET_ALARM = "extraSetAlarm";
- /**
- * Tells the TetherService to run a provision check now.
- */
- public static final String EXTRA_RUN_PROVISION = "extraRunProvision";
- /**
- * Extra used for communicating with the TetherService and TetherProvisioningActivity.
- * Contains the {@link ResultReceiver} which will receive provisioning results.
- * Can not be empty.
- */
- public static final String EXTRA_PROVISION_CALLBACK = "extraProvisionCallback";
-
- /**
- * Extra used for communicating with the TetherService and TetherProvisioningActivity.
- * Contains the subId of current active cellular upstream.
- * @hide
- */
- public static final String EXTRA_TETHER_SUBID = "android.net.extra.TETHER_SUBID";
-
- /**
- * Extra used for telling TetherProvisioningActivity the entitlement package name and class
- * name to start UI entitlement check.
- * @hide
- */
- public static final String EXTRA_TETHER_UI_PROVISIONING_APP_NAME =
- "android.net.extra.TETHER_UI_PROVISIONING_APP_NAME";
-
- /**
- * Extra used for telling TetherService the intent action to start silent entitlement check.
- * @hide
- */
- public static final String EXTRA_TETHER_SILENT_PROVISIONING_ACTION =
- "android.net.extra.TETHER_SILENT_PROVISIONING_ACTION";
-
- /**
- * Extra used for TetherService to receive the response of provisioning check.
- * @hide
- */
- public static final String EXTRA_TETHER_PROVISIONING_RESPONSE =
- "android.net.extra.TETHER_PROVISIONING_RESPONSE";
-}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
deleted file mode 100644
index 97fb4974d0f6f..0000000000000
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ /dev/null
@@ -1,1364 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net;
-
-import static android.annotation.SystemApi.Client.MODULE_LIBRARIES;
-
-import android.Manifest;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.annotation.RequiresPermission;
-import android.annotation.SystemApi;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.IBinder;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.util.ArrayMap;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Objects;
-import java.util.concurrent.Executor;
-import java.util.function.Supplier;
-
-/**
- * This class provides the APIs to control the tethering service.
- *
The primary responsibilities of this class are to provide the APIs for applications to
- * start tethering, stop tethering, query configuration and query status.
- *
- * @hide
- */
-@SystemApi
-public class TetheringManager {
- private static final String TAG = TetheringManager.class.getSimpleName();
- private static final int DEFAULT_TIMEOUT_MS = 60_000;
- private static final long CONNECTOR_POLL_INTERVAL_MILLIS = 200L;
-
- @GuardedBy("mConnectorWaitQueue")
- @Nullable
- private ITetheringConnector mConnector;
- @GuardedBy("mConnectorWaitQueue")
- @NonNull
- private final List mConnectorWaitQueue = new ArrayList<>();
- private final Supplier mConnectorSupplier;
-
- private final TetheringCallbackInternal mCallback;
- private final Context mContext;
- private final ArrayMap
- mTetheringEventCallbacks = new ArrayMap<>();
-
- private volatile TetheringConfigurationParcel mTetheringConfiguration;
- private volatile TetherStatesParcel mTetherStatesParcel;
-
- /**
- * Broadcast Action: A tetherable connection has come or gone.
- * Uses {@code TetheringManager.EXTRA_AVAILABLE_TETHER},
- * {@code TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY},
- * {@code TetheringManager.EXTRA_ACTIVE_TETHER}, and
- * {@code TetheringManager.EXTRA_ERRORED_TETHER} to indicate
- * the current state of tethering. Each include a list of
- * interface names in that state (may be empty).
- */
- public static final String ACTION_TETHER_STATE_CHANGED =
- "android.net.conn.TETHER_STATE_CHANGED";
-
- /**
- * gives a String[] listing all the interfaces configured for
- * tethering and currently available for tethering.
- */
- public static final String EXTRA_AVAILABLE_TETHER = "availableArray";
-
- /**
- * gives a String[] listing all the interfaces currently in local-only
- * mode (ie, has DHCPv4+IPv6-ULA support and no packet forwarding)
- */
- public static final String EXTRA_ACTIVE_LOCAL_ONLY = "android.net.extra.ACTIVE_LOCAL_ONLY";
-
- /**
- * gives a String[] listing all the interfaces currently tethered
- * (ie, has DHCPv4 support and packets potentially forwarded/NATed)
- */
- public static final String EXTRA_ACTIVE_TETHER = "tetherArray";
-
- /**
- * gives a String[] listing all the interfaces we tried to tether and
- * failed. Use {@link #getLastTetherError} to find the error code
- * for any interfaces listed here.
- */
- public static final String EXTRA_ERRORED_TETHER = "erroredArray";
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = false, value = {
- TETHERING_WIFI,
- TETHERING_USB,
- TETHERING_BLUETOOTH,
- TETHERING_WIFI_P2P,
- TETHERING_NCM,
- TETHERING_ETHERNET,
- })
- public @interface TetheringType {
- }
-
- /**
- * Invalid tethering type.
- * @see #startTethering.
- */
- public static final int TETHERING_INVALID = -1;
-
- /**
- * Wifi tethering type.
- * @see #startTethering.
- */
- public static final int TETHERING_WIFI = 0;
-
- /**
- * USB tethering type.
- * @see #startTethering.
- */
- public static final int TETHERING_USB = 1;
-
- /**
- * Bluetooth tethering type.
- * @see #startTethering.
- */
- public static final int TETHERING_BLUETOOTH = 2;
-
- /**
- * Wifi P2p tethering type.
- * Wifi P2p tethering is set through events automatically, and don't
- * need to start from #startTethering.
- */
- public static final int TETHERING_WIFI_P2P = 3;
-
- /**
- * Ncm local tethering type.
- * @see #startTethering(TetheringRequest, Executor, StartTetheringCallback)
- */
- public static final int TETHERING_NCM = 4;
-
- /**
- * Ethernet tethering type.
- * @see #startTethering(TetheringRequest, Executor, StartTetheringCallback)
- */
- public static final int TETHERING_ETHERNET = 5;
-
- /**
- * WIGIG tethering type. Use a separate type to prevent
- * conflicts with TETHERING_WIFI
- * This type is only used internally by the tethering module
- * @hide
- */
- public static final int TETHERING_WIGIG = 6;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- TETHER_ERROR_NO_ERROR,
- TETHER_ERROR_PROVISIONING_FAILED,
- TETHER_ERROR_ENTITLEMENT_UNKNOWN,
- })
- public @interface EntitlementResult {
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- TETHER_ERROR_NO_ERROR,
- TETHER_ERROR_UNKNOWN_IFACE,
- TETHER_ERROR_SERVICE_UNAVAIL,
- TETHER_ERROR_INTERNAL_ERROR,
- TETHER_ERROR_TETHER_IFACE_ERROR,
- TETHER_ERROR_ENABLE_FORWARDING_ERROR,
- TETHER_ERROR_DISABLE_FORWARDING_ERROR,
- TETHER_ERROR_IFACE_CFG_ERROR,
- TETHER_ERROR_DHCPSERVER_ERROR,
- })
- public @interface TetheringIfaceError {
- }
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- TETHER_ERROR_SERVICE_UNAVAIL,
- TETHER_ERROR_INTERNAL_ERROR,
- TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION,
- TETHER_ERROR_UNKNOWN_TYPE,
- })
- public @interface StartTetheringError {
- }
-
- public static final int TETHER_ERROR_NO_ERROR = 0;
- public static final int TETHER_ERROR_UNKNOWN_IFACE = 1;
- public static final int TETHER_ERROR_SERVICE_UNAVAIL = 2;
- public static final int TETHER_ERROR_UNSUPPORTED = 3;
- public static final int TETHER_ERROR_UNAVAIL_IFACE = 4;
- public static final int TETHER_ERROR_INTERNAL_ERROR = 5;
- public static final int TETHER_ERROR_TETHER_IFACE_ERROR = 6;
- public static final int TETHER_ERROR_UNTETHER_IFACE_ERROR = 7;
- public static final int TETHER_ERROR_ENABLE_FORWARDING_ERROR = 8;
- public static final int TETHER_ERROR_DISABLE_FORWARDING_ERROR = 9;
- public static final int TETHER_ERROR_IFACE_CFG_ERROR = 10;
- public static final int TETHER_ERROR_PROVISIONING_FAILED = 11;
- public static final int TETHER_ERROR_DHCPSERVER_ERROR = 12;
- public static final int TETHER_ERROR_ENTITLEMENT_UNKNOWN = 13;
- public static final int TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION = 14;
- public static final int TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION = 15;
- public static final int TETHER_ERROR_UNKNOWN_TYPE = 16;
-
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(flag = false, value = {
- TETHER_HARDWARE_OFFLOAD_STOPPED,
- TETHER_HARDWARE_OFFLOAD_STARTED,
- TETHER_HARDWARE_OFFLOAD_FAILED,
- })
- public @interface TetherOffloadStatus {
- }
-
- /** Tethering offload status is stopped. */
- public static final int TETHER_HARDWARE_OFFLOAD_STOPPED = 0;
- /** Tethering offload status is started. */
- public static final int TETHER_HARDWARE_OFFLOAD_STARTED = 1;
- /** Fail to start tethering offload. */
- public static final int TETHER_HARDWARE_OFFLOAD_FAILED = 2;
-
- /**
- * Create a TetheringManager object for interacting with the tethering service.
- *
- * @param context Context for the manager.
- * @param connectorSupplier Supplier for the manager connector; may return null while the
- * service is not connected.
- * {@hide}
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public TetheringManager(@NonNull final Context context,
- @NonNull Supplier connectorSupplier) {
- mContext = context;
- mCallback = new TetheringCallbackInternal();
- mConnectorSupplier = connectorSupplier;
-
- final String pkgName = mContext.getOpPackageName();
-
- final IBinder connector = mConnectorSupplier.get();
- // If the connector is available on start, do not start a polling thread. This introduces
- // differences in the thread that sends the oneway binder calls to the service between the
- // first few seconds after boot and later, but it avoids always having differences between
- // the first usage of TetheringManager from a process and subsequent usages (so the
- // difference is only on boot). On boot binder calls may be queued until the service comes
- // up and be sent from a worker thread; later, they are always sent from the caller thread.
- // Considering that it's just oneway binder calls, and ordering is preserved, this seems
- // better than inconsistent behavior persisting after boot.
- if (connector != null) {
- mConnector = ITetheringConnector.Stub.asInterface(connector);
- } else {
- startPollingForConnector();
- }
-
- Log.i(TAG, "registerTetheringEventCallback:" + pkgName);
- getConnector(c -> c.registerTetheringEventCallback(mCallback, pkgName));
- }
-
- private void startPollingForConnector() {
- new Thread(() -> {
- while (true) {
- try {
- Thread.sleep(CONNECTOR_POLL_INTERVAL_MILLIS);
- } catch (InterruptedException e) {
- // Not much to do here, the system needs to wait for the connector
- }
-
- final IBinder connector = mConnectorSupplier.get();
- if (connector != null) {
- onTetheringConnected(ITetheringConnector.Stub.asInterface(connector));
- return;
- }
- }
- }).start();
- }
-
- private interface ConnectorConsumer {
- void onConnectorAvailable(ITetheringConnector connector) throws RemoteException;
- }
-
- private void onTetheringConnected(ITetheringConnector connector) {
- // Process the connector wait queue in order, including any items that are added
- // while processing.
- //
- // 1. Copy the queue to a local variable under lock.
- // 2. Drain the local queue with the lock released (otherwise, enqueuing future commands
- // would block on the lock).
- // 3. Acquire the lock again. If any new tasks were queued during step 2, goto 1.
- // If not, set mConnector to non-null so future tasks are run immediately, not queued.
- //
- // For this to work, all calls to the tethering service must use getConnector(), which
- // ensures that tasks are added to the queue with the lock held.
- //
- // Once mConnector is set to non-null, it will never be null again. If the network stack
- // process crashes, no recovery is possible.
- // TODO: evaluate whether it is possible to recover from network stack process crashes
- // (though in most cases the system will have crashed when the network stack process
- // crashes).
- do {
- final List localWaitQueue;
- synchronized (mConnectorWaitQueue) {
- localWaitQueue = new ArrayList<>(mConnectorWaitQueue);
- mConnectorWaitQueue.clear();
- }
-
- // Allow more tasks to be added at the end without blocking while draining the queue.
- for (ConnectorConsumer task : localWaitQueue) {
- try {
- task.onConnectorAvailable(connector);
- } catch (RemoteException e) {
- // Most likely the network stack process crashed, which is likely to crash the
- // system. Keep processing other requests but report the error loudly.
- Log.wtf(TAG, "Error processing request for the tethering connector", e);
- }
- }
-
- synchronized (mConnectorWaitQueue) {
- if (mConnectorWaitQueue.size() == 0) {
- mConnector = connector;
- return;
- }
- }
- } while (true);
- }
-
- /**
- * Asynchronously get the ITetheringConnector to execute some operation.
- *
- *
If the connector is already available, the operation will be executed on the caller's
- * thread. Otherwise it will be queued and executed on a worker thread. The operation should be
- * limited to performing oneway binder calls to minimize differences due to threading.
- */
- private void getConnector(ConnectorConsumer consumer) {
- final ITetheringConnector connector;
- synchronized (mConnectorWaitQueue) {
- connector = mConnector;
- if (connector == null) {
- mConnectorWaitQueue.add(consumer);
- return;
- }
- }
-
- try {
- consumer.onConnectorAvailable(connector);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
- }
-
- private interface RequestHelper {
- void runRequest(ITetheringConnector connector, IIntResultListener listener);
- }
-
- // Used to dispatch legacy ConnectivityManager methods that expect tethering to be able to
- // return results and perform operations synchronously.
- // TODO: remove once there are no callers of these legacy methods.
- private class RequestDispatcher {
- private final ConditionVariable mWaiting;
- public volatile int mRemoteResult;
-
- private final IIntResultListener mListener = new IIntResultListener.Stub() {
- @Override
- public void onResult(final int resultCode) {
- mRemoteResult = resultCode;
- mWaiting.open();
- }
- };
-
- RequestDispatcher() {
- mWaiting = new ConditionVariable();
- }
-
- int waitForResult(final RequestHelper request) {
- getConnector(c -> request.runRequest(c, mListener));
- if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) {
- throw new IllegalStateException("Callback timeout");
- }
-
- throwIfPermissionFailure(mRemoteResult);
-
- return mRemoteResult;
- }
- }
-
- private void throwIfPermissionFailure(final int errorCode) {
- switch (errorCode) {
- case TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION:
- throw new SecurityException("No android.permission.TETHER_PRIVILEGED"
- + " or android.permission.WRITE_SETTINGS permission");
- case TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION:
- throw new SecurityException(
- "No android.permission.ACCESS_NETWORK_STATE permission");
- }
- }
-
- private class TetheringCallbackInternal extends ITetheringEventCallback.Stub {
- private volatile int mError = TETHER_ERROR_NO_ERROR;
- private final ConditionVariable mWaitForCallback = new ConditionVariable();
-
- @Override
- public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
- mTetheringConfiguration = parcel.config;
- mTetherStatesParcel = parcel.states;
- mWaitForCallback.open();
- }
-
- @Override
- public void onCallbackStopped(int errorCode) {
- mError = errorCode;
- mWaitForCallback.open();
- }
-
- @Override
- public void onUpstreamChanged(Network network) { }
-
- @Override
- public void onConfigurationChanged(TetheringConfigurationParcel config) {
- mTetheringConfiguration = config;
- }
-
- @Override
- public void onTetherStatesChanged(TetherStatesParcel states) {
- mTetherStatesParcel = states;
- }
-
- @Override
- public void onTetherClientsChanged(List clients) { }
-
- @Override
- public void onOffloadStatusChanged(int status) { }
-
- public void waitForStarted() {
- mWaitForCallback.block(DEFAULT_TIMEOUT_MS);
- throwIfPermissionFailure(mError);
- }
- }
-
- /**
- * Attempt to tether the named interface. This will setup a dhcp server
- * on the interface, forward and NAT IP v4 packets and forward DNS requests
- * to the best active upstream network interface. Note that if no upstream
- * IP network interface is available, dhcp will still run and traffic will be
- * allowed between the tethered devices and this device, though upstream net
- * access will of course fail until an upstream network interface becomes
- * active.
- *
- * @deprecated The only usages is PanService. It uses this for legacy reasons
- * and will migrate away as soon as possible.
- *
- * @param iface the interface name to tether.
- * @return error a {@code TETHER_ERROR} value indicating success or failure type
- *
- * {@hide}
- */
- @Deprecated
- @SystemApi(client = MODULE_LIBRARIES)
- public int tether(@NonNull final String iface) {
- final String callerPkg = mContext.getOpPackageName();
- Log.i(TAG, "tether caller:" + callerPkg);
- final RequestDispatcher dispatcher = new RequestDispatcher();
-
- return dispatcher.waitForResult((connector, listener) -> {
- try {
- connector.tether(iface, callerPkg, getAttributionTag(), listener);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
- });
- }
-
- /**
- * @return the context's attribution tag
- */
- private @Nullable String getAttributionTag() {
- return null;
- }
-
- /**
- * Stop tethering the named interface.
- *
- * @deprecated The only usages is PanService. It uses this for legacy reasons
- * and will migrate away as soon as possible.
- *
- * {@hide}
- */
- @Deprecated
- @SystemApi(client = MODULE_LIBRARIES)
- public int untether(@NonNull final String iface) {
- final String callerPkg = mContext.getOpPackageName();
- Log.i(TAG, "untether caller:" + callerPkg);
-
- final RequestDispatcher dispatcher = new RequestDispatcher();
-
- return dispatcher.waitForResult((connector, listener) -> {
- try {
- connector.untether(iface, callerPkg, getAttributionTag(), listener);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
- });
- }
-
- /**
- * Attempt to both alter the mode of USB and Tethering of USB.
- *
- * @deprecated New client should not use this API anymore. All clients should use
- * #startTethering or #stopTethering which encapsulate proper entitlement logic. If the API is
- * used and an entitlement check is needed, downstream USB tethering will be enabled but will
- * not have any upstream.
- *
- * {@hide}
- */
- @Deprecated
- @SystemApi(client = MODULE_LIBRARIES)
- public int setUsbTethering(final boolean enable) {
- final String callerPkg = mContext.getOpPackageName();
- Log.i(TAG, "setUsbTethering caller:" + callerPkg);
-
- final RequestDispatcher dispatcher = new RequestDispatcher();
-
- return dispatcher.waitForResult((connector, listener) -> {
- try {
- connector.setUsbTethering(enable, callerPkg, getAttributionTag(),
- listener);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
- });
- }
-
- /**
- * Use with {@link #startTethering} to specify additional parameters when starting tethering.
- */
- public static class TetheringRequest {
- /** A configuration set for TetheringRequest. */
- private final TetheringRequestParcel mRequestParcel;
-
- private TetheringRequest(final TetheringRequestParcel request) {
- mRequestParcel = request;
- }
-
- /** Builder used to create TetheringRequest. */
- public static class Builder {
- private final TetheringRequestParcel mBuilderParcel;
-
- /** Default constructor of Builder. */
- public Builder(@TetheringType final int type) {
- mBuilderParcel = new TetheringRequestParcel();
- mBuilderParcel.tetheringType = type;
- mBuilderParcel.localIPv4Address = null;
- mBuilderParcel.staticClientAddress = null;
- mBuilderParcel.exemptFromEntitlementCheck = false;
- mBuilderParcel.showProvisioningUi = true;
- }
-
- /**
- * Configure tethering with static IPv4 assignment.
- *
- * A DHCP server will be started, but will only be able to offer the client address.
- * The two addresses must be in the same prefix.
- *
- * @param localIPv4Address The preferred local IPv4 link address to use.
- * @param clientAddress The static client address.
- */
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
- @NonNull
- public Builder setStaticIpv4Addresses(@NonNull final LinkAddress localIPv4Address,
- @NonNull final LinkAddress clientAddress) {
- Objects.requireNonNull(localIPv4Address);
- Objects.requireNonNull(clientAddress);
- if (!checkStaticAddressConfiguration(localIPv4Address, clientAddress)) {
- throw new IllegalArgumentException("Invalid server or client addresses");
- }
-
- mBuilderParcel.localIPv4Address = localIPv4Address;
- mBuilderParcel.staticClientAddress = clientAddress;
- return this;
- }
-
- /** Start tethering without entitlement checks. */
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
- @NonNull
- public Builder setExemptFromEntitlementCheck(boolean exempt) {
- mBuilderParcel.exemptFromEntitlementCheck = exempt;
- return this;
- }
-
- /**
- * If an entitlement check is needed, sets whether to show the entitlement UI or to
- * perform a silent entitlement check. By default, the entitlement UI is shown.
- */
- @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED)
- @NonNull
- public Builder setShouldShowEntitlementUi(boolean showUi) {
- mBuilderParcel.showProvisioningUi = showUi;
- return this;
- }
-
- /** Build {@link TetheringRequest] with the currently set configuration. */
- @NonNull
- public TetheringRequest build() {
- return new TetheringRequest(mBuilderParcel);
- }
- }
-
- /**
- * Get the local IPv4 address, if one was configured with
- * {@link Builder#setStaticIpv4Addresses}.
- */
- @Nullable
- public LinkAddress getLocalIpv4Address() {
- return mRequestParcel.localIPv4Address;
- }
-
- /**
- * Get the static IPv4 address of the client, if one was configured with
- * {@link Builder#setStaticIpv4Addresses}.
- */
- @Nullable
- public LinkAddress getClientStaticIpv4Address() {
- return mRequestParcel.staticClientAddress;
- }
-
- /** Get tethering type. */
- @TetheringType
- public int getTetheringType() {
- return mRequestParcel.tetheringType;
- }
-
- /** Check if exempt from entitlement check. */
- public boolean isExemptFromEntitlementCheck() {
- return mRequestParcel.exemptFromEntitlementCheck;
- }
-
- /** Check if show entitlement ui. */
- public boolean getShouldShowEntitlementUi() {
- return mRequestParcel.showProvisioningUi;
- }
-
- /**
- * Check whether the two addresses are ipv4 and in the same prefix.
- * @hide
- */
- public static boolean checkStaticAddressConfiguration(
- @NonNull final LinkAddress localIPv4Address,
- @NonNull final LinkAddress clientAddress) {
- return localIPv4Address.getPrefixLength() == clientAddress.getPrefixLength()
- && localIPv4Address.isIpv4() && clientAddress.isIpv4()
- && new IpPrefix(localIPv4Address.toString()).equals(
- new IpPrefix(clientAddress.toString()));
- }
-
- /**
- * Get a TetheringRequestParcel from the configuration
- * @hide
- */
- public TetheringRequestParcel getParcel() {
- return mRequestParcel;
- }
-
- /** String of TetheringRequest detail. */
- public String toString() {
- return "TetheringRequest [ type= " + mRequestParcel.tetheringType
- + ", localIPv4Address= " + mRequestParcel.localIPv4Address
- + ", staticClientAddress= " + mRequestParcel.staticClientAddress
- + ", exemptFromEntitlementCheck= "
- + mRequestParcel.exemptFromEntitlementCheck + ", showProvisioningUi= "
- + mRequestParcel.showProvisioningUi + " ]";
- }
- }
-
- /**
- * Callback for use with {@link #startTethering} to find out whether tethering succeeded.
- */
- public interface StartTetheringCallback {
- /**
- * Called when tethering has been successfully started.
- */
- default void onTetheringStarted() {}
-
- /**
- * Called when starting tethering failed.
- *
- * @param error The error that caused the failure.
- */
- default void onTetheringFailed(@StartTetheringError final int error) {}
- }
-
- /**
- * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
- * fails, stopTethering will be called automatically.
- *
- *
Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
- * fail if a tethering entitlement check is required.
- *
- * @param request a {@link TetheringRequest} which can specify the preferred configuration.
- * @param executor {@link Executor} to specify the thread upon which the callback of
- * TetheringRequest will be invoked.
- * @param callback A callback that will be called to indicate the success status of the
- * tethering start request.
- */
- @RequiresPermission(anyOf = {
- android.Manifest.permission.TETHER_PRIVILEGED,
- android.Manifest.permission.WRITE_SETTINGS
- })
- public void startTethering(@NonNull final TetheringRequest request,
- @NonNull final Executor executor, @NonNull final StartTetheringCallback callback) {
- final String callerPkg = mContext.getOpPackageName();
- Log.i(TAG, "startTethering caller:" + callerPkg);
-
- final IIntResultListener listener = new IIntResultListener.Stub() {
- @Override
- public void onResult(final int resultCode) {
- executor.execute(() -> {
- if (resultCode == TETHER_ERROR_NO_ERROR) {
- callback.onTetheringStarted();
- } else {
- callback.onTetheringFailed(resultCode);
- }
- });
- }
- };
- getConnector(c -> c.startTethering(request.getParcel(), callerPkg,
- getAttributionTag(), listener));
- }
-
- /**
- * Starts tethering and runs tether provisioning for the given type if needed. If provisioning
- * fails, stopTethering will be called automatically.
- *
- *
Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
- * fail if a tethering entitlement check is required.
- *
- * @param type The tethering type, on of the {@code TetheringManager#TETHERING_*} constants.
- * @param executor {@link Executor} to specify the thread upon which the callback of
- * TetheringRequest will be invoked.
- * @hide
- */
- @RequiresPermission(anyOf = {
- android.Manifest.permission.TETHER_PRIVILEGED,
- android.Manifest.permission.WRITE_SETTINGS
- })
- @SystemApi(client = MODULE_LIBRARIES)
- public void startTethering(int type, @NonNull final Executor executor,
- @NonNull final StartTetheringCallback callback) {
- startTethering(new TetheringRequest.Builder(type).build(), executor, callback);
- }
-
- /**
- * Stops tethering for the given type. Also cancels any provisioning rechecks for that type if
- * applicable.
- *
- *
Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
- * fail if a tethering entitlement check is required.
- */
- @RequiresPermission(anyOf = {
- android.Manifest.permission.TETHER_PRIVILEGED,
- android.Manifest.permission.WRITE_SETTINGS
- })
- public void stopTethering(@TetheringType final int type) {
- final String callerPkg = mContext.getOpPackageName();
- Log.i(TAG, "stopTethering caller:" + callerPkg);
-
- getConnector(c -> c.stopTethering(type, callerPkg, getAttributionTag(),
- new IIntResultListener.Stub() {
- @Override
- public void onResult(int resultCode) {
- // TODO: provide an API to obtain result
- // This has never been possible as stopTethering has always been void and never
- // taken a callback object. The only indication that callers have is if the call
- // results in a TETHER_STATE_CHANGE broadcast.
- }
- }));
- }
-
- /**
- * Callback for use with {@link #getLatestTetheringEntitlementResult} to find out whether
- * entitlement succeeded.
- */
- public interface OnTetheringEntitlementResultListener {
- /**
- * Called to notify entitlement result.
- *
- * @param resultCode an int value of entitlement result. It may be one of
- * {@link #TETHER_ERROR_NO_ERROR},
- * {@link #TETHER_ERROR_PROVISIONING_FAILED}, or
- * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN}.
- */
- void onTetheringEntitlementResult(@EntitlementResult int result);
- }
-
- /**
- * Request the latest value of the tethering entitlement check.
- *
- *
This method will only return the latest entitlement result if it is available. If no
- * cached entitlement result is available, and {@code showEntitlementUi} is false,
- * {@link #TETHER_ERROR_ENTITLEMENT_UNKNOWN} will be returned. If {@code showEntitlementUi} is
- * true, entitlement will be run.
- *
- *
Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
- * fail if a tethering entitlement check is required.
- *
- * @param type the downstream type of tethering. Must be one of {@code #TETHERING_*} constants.
- * @param showEntitlementUi a boolean indicating whether to check result for the UI-based
- * entitlement check or the silent entitlement check.
- * @param executor the executor on which callback will be invoked.
- * @param listener an {@link OnTetheringEntitlementResultListener} which will be called to
- * notify the caller of the result of entitlement check. The listener may be called zero
- * or one time.
- */
- @RequiresPermission(anyOf = {
- android.Manifest.permission.TETHER_PRIVILEGED,
- android.Manifest.permission.WRITE_SETTINGS
- })
- public void requestLatestTetheringEntitlementResult(@TetheringType int type,
- boolean showEntitlementUi,
- @NonNull Executor executor,
- @NonNull final OnTetheringEntitlementResultListener listener) {
- if (listener == null) {
- throw new IllegalArgumentException(
- "OnTetheringEntitlementResultListener cannot be null.");
- }
-
- ResultReceiver wrappedListener = new ResultReceiver(null /* handler */) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- executor.execute(() -> {
- listener.onTetheringEntitlementResult(resultCode);
- });
- }
- };
-
- requestLatestTetheringEntitlementResult(type, wrappedListener,
- showEntitlementUi);
- }
-
- /**
- * Helper function of #requestLatestTetheringEntitlementResult to remain backwards compatible
- * with ConnectivityManager#getLatestTetheringEntitlementResult
- *
- * {@hide}
- */
- // TODO: improve the usage of ResultReceiver, b/145096122
- @SystemApi(client = MODULE_LIBRARIES)
- public void requestLatestTetheringEntitlementResult(@TetheringType final int type,
- @NonNull final ResultReceiver receiver, final boolean showEntitlementUi) {
- final String callerPkg = mContext.getOpPackageName();
- Log.i(TAG, "getLatestTetheringEntitlementResult caller:" + callerPkg);
-
- getConnector(c -> c.requestLatestTetheringEntitlementResult(
- type, receiver, showEntitlementUi, callerPkg, getAttributionTag()));
- }
-
- /**
- * Callback for use with {@link registerTetheringEventCallback} to find out tethering
- * upstream status.
- */
- public interface TetheringEventCallback {
- /**
- * Called when tethering supported status changed.
- *
- *
This will be called immediately after the callback is registered, and may be called
- * multiple times later upon changes.
- *
- *
Tethering may be disabled via system properties, device configuration, or device
- * policy restrictions.
- *
- * @param supported The new supported status
- */
- default void onTetheringSupported(boolean supported) {}
-
- /**
- * Called when tethering upstream changed.
- *
- *
This will be called immediately after the callback is registered, and may be called
- * multiple times later upon changes.
- *
- * @param network the {@link Network} of tethering upstream. Null means tethering doesn't
- * have any upstream.
- */
- default void onUpstreamChanged(@Nullable Network network) {}
-
- /**
- * Called when there was a change in tethering interface regular expressions.
- *
- *
This will be called immediately after the callback is registered, and may be called
- * multiple times later upon changes.
- * @param reg The new regular expressions.
- *
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- default void onTetherableInterfaceRegexpsChanged(@NonNull TetheringInterfaceRegexps reg) {}
-
- /**
- * Called when there was a change in the list of tetherable interfaces. Tetherable
- * interface means this interface is available and can be used for tethering.
- *
- *
This will be called immediately after the callback is registered, and may be called
- * multiple times later upon changes.
- * @param interfaces The list of tetherable interface names.
- */
- default void onTetherableInterfacesChanged(@NonNull List interfaces) {}
-
- /**
- * Called when there was a change in the list of tethered interfaces.
- *
- *
This will be called immediately after the callback is registered, and may be called
- * multiple times later upon changes.
- * @param interfaces The list of 0 or more String of currently tethered interface names.
- */
- default void onTetheredInterfacesChanged(@NonNull List interfaces) {}
-
- /**
- * Called when an error occurred configuring tethering.
- *
- *
This will be called immediately after the callback is registered if the latest status
- * on the interface is an error, and may be called multiple times later upon changes.
- * @param ifName Name of the interface.
- * @param error One of {@code TetheringManager#TETHER_ERROR_*}.
- */
- default void onError(@NonNull String ifName, @TetheringIfaceError int error) {}
-
- /**
- * Called when the list of tethered clients changes.
- *
- *
This callback provides best-effort information on connected clients based on state
- * known to the system, however the list cannot be completely accurate (and should not be
- * used for security purposes). For example, clients behind a bridge and using static IP
- * assignments are not visible to the tethering device; or even when using DHCP, such
- * clients may still be reported by this callback after disconnection as the system cannot
- * determine if they are still connected.
- * @param clients The new set of tethered clients; the collection is not ordered.
- */
- default void onClientsChanged(@NonNull Collection clients) {}
-
- /**
- * Called when tethering offload status changes.
- *
- *
This will be called immediately after the callback is registered.
- * @param status The offload status.
- */
- default void onOffloadStatusChanged(@TetherOffloadStatus int status) {}
- }
-
- /**
- * Regular expressions used to identify tethering interfaces.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public static class TetheringInterfaceRegexps {
- private final String[] mTetherableBluetoothRegexs;
- private final String[] mTetherableUsbRegexs;
- private final String[] mTetherableWifiRegexs;
-
- /** @hide */
- public TetheringInterfaceRegexps(@NonNull String[] tetherableBluetoothRegexs,
- @NonNull String[] tetherableUsbRegexs, @NonNull String[] tetherableWifiRegexs) {
- mTetherableBluetoothRegexs = tetherableBluetoothRegexs.clone();
- mTetherableUsbRegexs = tetherableUsbRegexs.clone();
- mTetherableWifiRegexs = tetherableWifiRegexs.clone();
- }
-
- @NonNull
- public List getTetherableBluetoothRegexs() {
- return Collections.unmodifiableList(Arrays.asList(mTetherableBluetoothRegexs));
- }
-
- @NonNull
- public List getTetherableUsbRegexs() {
- return Collections.unmodifiableList(Arrays.asList(mTetherableUsbRegexs));
- }
-
- @NonNull
- public List getTetherableWifiRegexs() {
- return Collections.unmodifiableList(Arrays.asList(mTetherableWifiRegexs));
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(mTetherableBluetoothRegexs, mTetherableUsbRegexs,
- mTetherableWifiRegexs);
- }
-
- @Override
- public boolean equals(@Nullable Object obj) {
- if (!(obj instanceof TetheringInterfaceRegexps)) return false;
- final TetheringInterfaceRegexps other = (TetheringInterfaceRegexps) obj;
- return Arrays.equals(mTetherableBluetoothRegexs, other.mTetherableBluetoothRegexs)
- && Arrays.equals(mTetherableUsbRegexs, other.mTetherableUsbRegexs)
- && Arrays.equals(mTetherableWifiRegexs, other.mTetherableWifiRegexs);
- }
- }
-
- /**
- * Start listening to tethering change events. Any new added callback will receive the last
- * tethering status right away. If callback is registered,
- * {@link TetheringEventCallback#onUpstreamChanged} will immediately be called. If tethering
- * has no upstream or disabled, the argument of callback will be null. The same callback object
- * cannot be registered twice.
- *
- * @param executor the executor on which callback will be invoked.
- * @param callback the callback to be called when tethering has change events.
- */
- @RequiresPermission(Manifest.permission.ACCESS_NETWORK_STATE)
- public void registerTetheringEventCallback(@NonNull Executor executor,
- @NonNull TetheringEventCallback callback) {
- final String callerPkg = mContext.getOpPackageName();
- Log.i(TAG, "registerTetheringEventCallback caller:" + callerPkg);
-
- synchronized (mTetheringEventCallbacks) {
- if (mTetheringEventCallbacks.containsKey(callback)) {
- throw new IllegalArgumentException("callback was already registered.");
- }
- final ITetheringEventCallback remoteCallback = new ITetheringEventCallback.Stub() {
- // Only accessed with a lock on this object
- private final HashMap mErrorStates = new HashMap<>();
- private String[] mLastTetherableInterfaces = null;
- private String[] mLastTetheredInterfaces = null;
-
- @Override
- public void onUpstreamChanged(Network network) throws RemoteException {
- executor.execute(() -> {
- callback.onUpstreamChanged(network);
- });
- }
-
- private synchronized void sendErrorCallbacks(final TetherStatesParcel newStates) {
- for (int i = 0; i < newStates.erroredIfaceList.length; i++) {
- final String iface = newStates.erroredIfaceList[i];
- final Integer lastError = mErrorStates.get(iface);
- final int newError = newStates.lastErrorList[i];
- if (newError != TETHER_ERROR_NO_ERROR
- && !Objects.equals(lastError, newError)) {
- callback.onError(iface, newError);
- }
- mErrorStates.put(iface, newError);
- }
- }
-
- private synchronized void maybeSendTetherableIfacesChangedCallback(
- final TetherStatesParcel newStates) {
- if (Arrays.equals(mLastTetherableInterfaces, newStates.availableList)) return;
- mLastTetherableInterfaces = newStates.availableList.clone();
- callback.onTetherableInterfacesChanged(
- Collections.unmodifiableList(Arrays.asList(mLastTetherableInterfaces)));
- }
-
- private synchronized void maybeSendTetheredIfacesChangedCallback(
- final TetherStatesParcel newStates) {
- if (Arrays.equals(mLastTetheredInterfaces, newStates.tetheredList)) return;
- mLastTetheredInterfaces = newStates.tetheredList.clone();
- callback.onTetheredInterfacesChanged(
- Collections.unmodifiableList(Arrays.asList(mLastTetheredInterfaces)));
- }
-
- // Called immediately after the callbacks are registered.
- @Override
- public void onCallbackStarted(TetheringCallbackStartedParcel parcel) {
- executor.execute(() -> {
- callback.onTetheringSupported(parcel.tetheringSupported);
- callback.onUpstreamChanged(parcel.upstreamNetwork);
- sendErrorCallbacks(parcel.states);
- sendRegexpsChanged(parcel.config);
- maybeSendTetherableIfacesChangedCallback(parcel.states);
- maybeSendTetheredIfacesChangedCallback(parcel.states);
- callback.onClientsChanged(parcel.tetheredClients);
- callback.onOffloadStatusChanged(parcel.offloadStatus);
- });
- }
-
- @Override
- public void onCallbackStopped(int errorCode) {
- executor.execute(() -> {
- throwIfPermissionFailure(errorCode);
- });
- }
-
- private void sendRegexpsChanged(TetheringConfigurationParcel parcel) {
- callback.onTetherableInterfaceRegexpsChanged(new TetheringInterfaceRegexps(
- parcel.tetherableBluetoothRegexs,
- parcel.tetherableUsbRegexs,
- parcel.tetherableWifiRegexs));
- }
-
- @Override
- public void onConfigurationChanged(TetheringConfigurationParcel config) {
- executor.execute(() -> sendRegexpsChanged(config));
- }
-
- @Override
- public void onTetherStatesChanged(TetherStatesParcel states) {
- executor.execute(() -> {
- sendErrorCallbacks(states);
- maybeSendTetherableIfacesChangedCallback(states);
- maybeSendTetheredIfacesChangedCallback(states);
- });
- }
-
- @Override
- public void onTetherClientsChanged(final List clients) {
- executor.execute(() -> callback.onClientsChanged(clients));
- }
-
- @Override
- public void onOffloadStatusChanged(final int status) {
- executor.execute(() -> callback.onOffloadStatusChanged(status));
- }
- };
- getConnector(c -> c.registerTetheringEventCallback(remoteCallback, callerPkg));
- mTetheringEventCallbacks.put(callback, remoteCallback);
- }
- }
-
- /**
- * Remove tethering event callback previously registered with
- * {@link #registerTetheringEventCallback}.
- *
- * @param callback previously registered callback.
- */
- @RequiresPermission(anyOf = {
- Manifest.permission.TETHER_PRIVILEGED,
- Manifest.permission.ACCESS_NETWORK_STATE
- })
- public void unregisterTetheringEventCallback(@NonNull final TetheringEventCallback callback) {
- final String callerPkg = mContext.getOpPackageName();
- Log.i(TAG, "unregisterTetheringEventCallback caller:" + callerPkg);
-
- synchronized (mTetheringEventCallbacks) {
- ITetheringEventCallback remoteCallback = mTetheringEventCallbacks.remove(callback);
- if (remoteCallback == null) {
- throw new IllegalArgumentException("callback was not registered.");
- }
-
- getConnector(c -> c.unregisterTetheringEventCallback(remoteCallback, callerPkg));
- }
- }
-
- /**
- * Get a more detailed error code after a Tethering or Untethering
- * request asynchronously failed.
- *
- * @param iface The name of the interface of interest
- * @return error The error code of the last error tethering or untethering the named
- * interface
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public int getLastTetherError(@NonNull final String iface) {
- mCallback.waitForStarted();
- if (mTetherStatesParcel == null) return TETHER_ERROR_NO_ERROR;
-
- int i = 0;
- for (String errored : mTetherStatesParcel.erroredIfaceList) {
- if (iface.equals(errored)) return mTetherStatesParcel.lastErrorList[i];
-
- i++;
- }
- return TETHER_ERROR_NO_ERROR;
- }
-
- /**
- * Get the list of regular expressions that define any tetherable
- * USB network interfaces. If USB tethering is not supported by the
- * device, this list should be empty.
- *
- * @return an array of 0 or more regular expression Strings defining
- * what interfaces are considered tetherable usb interfaces.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public @NonNull String[] getTetherableUsbRegexs() {
- mCallback.waitForStarted();
- return mTetheringConfiguration.tetherableUsbRegexs;
- }
-
- /**
- * Get the list of regular expressions that define any tetherable
- * Wifi network interfaces. If Wifi tethering is not supported by the
- * device, this list should be empty.
- *
- * @return an array of 0 or more regular expression Strings defining
- * what interfaces are considered tetherable wifi interfaces.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public @NonNull String[] getTetherableWifiRegexs() {
- mCallback.waitForStarted();
- return mTetheringConfiguration.tetherableWifiRegexs;
- }
-
- /**
- * Get the list of regular expressions that define any tetherable
- * Bluetooth network interfaces. If Bluetooth tethering is not supported by the
- * device, this list should be empty.
- *
- * @return an array of 0 or more regular expression Strings defining
- * what interfaces are considered tetherable bluetooth interfaces.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public @NonNull String[] getTetherableBluetoothRegexs() {
- mCallback.waitForStarted();
- return mTetheringConfiguration.tetherableBluetoothRegexs;
- }
-
- /**
- * Get the set of tetherable, available interfaces. This list is limited by
- * device configuration and current interface existence.
- *
- * @return an array of 0 or more Strings of tetherable interface names.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public @NonNull String[] getTetherableIfaces() {
- mCallback.waitForStarted();
- if (mTetherStatesParcel == null) return new String[0];
-
- return mTetherStatesParcel.availableList;
- }
-
- /**
- * Get the set of tethered interfaces.
- *
- * @return an array of 0 or more String of currently tethered interface names.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public @NonNull String[] getTetheredIfaces() {
- mCallback.waitForStarted();
- if (mTetherStatesParcel == null) return new String[0];
-
- return mTetherStatesParcel.tetheredList;
- }
-
- /**
- * Get the set of interface names which attempted to tether but
- * failed. Re-attempting to tether may cause them to reset to the Tethered
- * state. Alternatively, causing the interface to be destroyed and recreated
- * may cause them to reset to the available state.
- * {@link TetheringManager#getLastTetherError} can be used to get more
- * information on the cause of the errors.
- *
- * @return an array of 0 or more String indicating the interface names
- * which failed to tether.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public @NonNull String[] getTetheringErroredIfaces() {
- mCallback.waitForStarted();
- if (mTetherStatesParcel == null) return new String[0];
-
- return mTetherStatesParcel.erroredIfaceList;
- }
-
- /**
- * Get the set of tethered dhcp ranges.
- *
- * @deprecated This API just return the default value which is not used in DhcpServer.
- * @hide
- */
- @Deprecated
- public @NonNull String[] getTetheredDhcpRanges() {
- mCallback.waitForStarted();
- return mTetheringConfiguration.legacyDhcpRanges;
- }
-
- /**
- * Check if the device allows for tethering. It may be disabled via
- * {@code ro.tether.denied} system property, Settings.TETHER_SUPPORTED or
- * due to device configuration.
- *
- * @return a boolean - {@code true} indicating Tethering is supported.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public boolean isTetheringSupported() {
- final String callerPkg = mContext.getOpPackageName();
-
- return isTetheringSupported(callerPkg);
- }
-
- /**
- * Check if the device allows for tethering. It may be disabled via {@code ro.tether.denied}
- * system property, Settings.TETHER_SUPPORTED or due to device configuration. This is useful
- * for system components that query this API on behalf of an app. In particular, Bluetooth
- * has @UnsupportedAppUsage calls that will let apps turn on bluetooth tethering if they have
- * the right permissions, but such an app needs to know whether it can (permissions as well
- * as support from the device) turn on tethering in the first place to show the appropriate UI.
- *
- * @param callerPkg The caller package name, if it is not matching the calling uid,
- * SecurityException would be thrown.
- * @return a boolean - {@code true} indicating Tethering is supported.
- * @hide
- */
- @SystemApi(client = MODULE_LIBRARIES)
- public boolean isTetheringSupported(@NonNull final String callerPkg) {
-
- final RequestDispatcher dispatcher = new RequestDispatcher();
- final int ret = dispatcher.waitForResult((connector, listener) -> {
- try {
- connector.isTetheringSupported(callerPkg, getAttributionTag(), listener);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
- });
-
- return ret == TETHER_ERROR_NO_ERROR;
- }
-
- /**
- * Stop all active tethering.
- *
- *
Without {@link android.Manifest.permission.TETHER_PRIVILEGED} permission, the call will
- * fail if a tethering entitlement check is required.
- */
- @RequiresPermission(anyOf = {
- android.Manifest.permission.TETHER_PRIVILEGED,
- android.Manifest.permission.WRITE_SETTINGS
- })
- public void stopAllTethering() {
- final String callerPkg = mContext.getOpPackageName();
- Log.i(TAG, "stopAllTethering caller:" + callerPkg);
-
- getConnector(c -> c.stopAllTethering(callerPkg, getAttributionTag(),
- new IIntResultListener.Stub() {
- @Override
- public void onResult(int resultCode) {
- // TODO: add an API parameter to send result to caller.
- // This has never been possible as stopAllTethering has always been void
- // and never taken a callback object. The only indication that callers have
- // is if the call results in a TETHER_STATE_CHANGE broadcast.
- }
- }));
- }
-}
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl b/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
deleted file mode 100644
index c0280d3dbfaf1..0000000000000
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringRequestParcel.aidl
+++ /dev/null
@@ -1,31 +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 android.net;
-
-import android.net.LinkAddress;
-
-/**
- * Configuration details for requesting tethering.
- * @hide
- */
-parcelable TetheringRequestParcel {
- int tetheringType;
- LinkAddress localIPv4Address;
- LinkAddress staticClientAddress;
- boolean exemptFromEntitlementCheck;
- boolean showProvisioningUi;
-}
diff --git a/packages/Tethering/jarjar-rules.txt b/packages/Tethering/jarjar-rules.txt
deleted file mode 100644
index 591861f5b837a..0000000000000
--- a/packages/Tethering/jarjar-rules.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-# These must be kept in sync with the framework-tethering-shared-srcs filegroup.
-# Classes from the framework-tethering-shared-srcs filegroup.
-# If there are files in that filegroup that are not covered below, the classes in the
-# module will be overwritten by the ones in the framework.
-rule com.android.internal.util.** com.android.networkstack.tethering.util.@1
-rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1
-
-rule android.net.shared.Inet4AddressUtils* com.android.networkstack.tethering.shared.Inet4AddressUtils@1
-
-# Classes from net-utils-framework-common
-rule com.android.net.module.util.** com.android.networkstack.tethering.util.@1
\ No newline at end of file
diff --git a/packages/Tethering/jni/android_net_util_TetheringUtils.cpp b/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
deleted file mode 100644
index 94c871d8a366b..0000000000000
--- a/packages/Tethering/jni/android_net_util_TetheringUtils.cpp
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright (C) 2017 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.
- */
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#define LOG_TAG "TetheringUtils"
-#include
-
-namespace android {
-
-static const uint32_t kIPv6NextHeaderOffset = offsetof(ip6_hdr, ip6_nxt);
-static const uint32_t kIPv6PayloadStart = sizeof(ip6_hdr);
-static const uint32_t kICMPv6TypeOffset = kIPv6PayloadStart + offsetof(icmp6_hdr, icmp6_type);
-
-static void android_net_util_setupIcmpFilter(JNIEnv *env, jobject javaFd, uint32_t type) {
- sock_filter filter_code[] = {
- // Check header is ICMPv6.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kIPv6NextHeaderOffset),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, IPPROTO_ICMPV6, 0, 3),
-
- // Check ICMPv6 type.
- BPF_STMT(BPF_LD | BPF_B | BPF_ABS, kICMPv6TypeOffset),
- BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, type, 0, 1),
-
- // Accept or reject.
- BPF_STMT(BPF_RET | BPF_K, 0xffff),
- BPF_STMT(BPF_RET | BPF_K, 0)
- };
-
- const sock_fprog filter = {
- sizeof(filter_code) / sizeof(filter_code[0]),
- filter_code,
- };
-
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
- if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
- }
-}
-
-static void android_net_util_setupNaSocket(JNIEnv *env, jobject clazz, jobject javaFd)
-{
- android_net_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_ADVERT);
-}
-
-static void android_net_util_setupNsSocket(JNIEnv *env, jobject clazz, jobject javaFd)
-{
- android_net_util_setupIcmpFilter(env, javaFd, ND_NEIGHBOR_SOLICIT);
-}
-
-static void android_net_util_setupRaSocket(JNIEnv *env, jobject clazz, jobject javaFd,
- jint ifIndex)
-{
- static const int kLinkLocalHopLimit = 255;
-
- int fd = jniGetFDFromFileDescriptor(env, javaFd);
-
- // Set an ICMPv6 filter that only passes Router Solicitations.
- struct icmp6_filter rs_only;
- ICMP6_FILTER_SETBLOCKALL(&rs_only);
- ICMP6_FILTER_SETPASS(ND_ROUTER_SOLICIT, &rs_only);
- socklen_t len = sizeof(rs_only);
- if (setsockopt(fd, IPPROTO_ICMPV6, ICMP6_FILTER, &rs_only, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(ICMP6_FILTER): %s", strerror(errno));
- return;
- }
-
- // Most/all of the rest of these options can be set via Java code, but
- // because we're here on account of setting an icmp6_filter go ahead
- // and do it all natively for now.
-
- // Set the multicast hoplimit to 255 (link-local only).
- int hops = kLinkLocalHopLimit;
- len = sizeof(hops);
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &hops, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(IPV6_MULTICAST_HOPS): %s", strerror(errno));
- return;
- }
-
- // Set the unicast hoplimit to 255 (link-local only).
- hops = kLinkLocalHopLimit;
- len = sizeof(hops);
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &hops, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(IPV6_UNICAST_HOPS): %s", strerror(errno));
- return;
- }
-
- // Explicitly disable multicast loopback.
- int off = 0;
- len = sizeof(off);
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &off, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(IPV6_MULTICAST_LOOP): %s", strerror(errno));
- return;
- }
-
- // Specify the IPv6 interface to use for outbound multicast.
- len = sizeof(ifIndex);
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifIndex, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(IPV6_MULTICAST_IF): %s", strerror(errno));
- return;
- }
-
- // Additional options to be considered:
- // - IPV6_TCLASS
- // - IPV6_RECVPKTINFO
- // - IPV6_RECVHOPLIMIT
-
- // Bind to [::].
- const struct sockaddr_in6 sin6 = {
- .sin6_family = AF_INET6,
- .sin6_port = 0,
- .sin6_flowinfo = 0,
- .sin6_addr = IN6ADDR_ANY_INIT,
- .sin6_scope_id = 0,
- };
- auto sa = reinterpret_cast(&sin6);
- len = sizeof(sin6);
- if (bind(fd, sa, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "bind(IN6ADDR_ANY): %s", strerror(errno));
- return;
- }
-
- // Join the all-routers multicast group, ff02::2%index.
- struct ipv6_mreq all_rtrs = {
- .ipv6mr_multiaddr = {{{0xff,2,0,0,0,0,0,0,0,0,0,0,0,0,0,2}}},
- .ipv6mr_interface = ifIndex,
- };
- len = sizeof(all_rtrs);
- if (setsockopt(fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &all_rtrs, len) != 0) {
- jniThrowExceptionFmt(env, "java/net/SocketException",
- "setsockopt(IPV6_JOIN_GROUP): %s", strerror(errno));
- return;
- }
-}
-
-/*
- * JNI registration.
- */
-static const JNINativeMethod gMethods[] = {
- /* name, signature, funcPtr */
- { "setupNaSocket", "(Ljava/io/FileDescriptor;)V",
- (void*) android_net_util_setupNaSocket },
- { "setupNsSocket", "(Ljava/io/FileDescriptor;)V",
- (void*) android_net_util_setupNsSocket },
- { "setupRaSocket", "(Ljava/io/FileDescriptor;I)V",
- (void*) android_net_util_setupRaSocket },
-};
-
-int register_android_net_util_TetheringUtils(JNIEnv* env) {
- return jniRegisterNativeMethods(env,
- "android/net/util/TetheringUtils",
- gMethods, NELEM(gMethods));
-}
-
-extern "C" jint JNI_OnLoad(JavaVM* vm, void*) {
- JNIEnv *env;
- if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) {
- __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, "ERROR: GetEnv failed");
- return JNI_ERR;
- }
-
- if (register_android_net_util_TetheringUtils(env) < 0) {
- return JNI_ERR;
- }
-
- return JNI_VERSION_1_6;
-}
-
-}; // namespace android
diff --git a/packages/Tethering/proguard.flags b/packages/Tethering/proguard.flags
deleted file mode 100644
index 86b903353cf5e..0000000000000
--- a/packages/Tethering/proguard.flags
+++ /dev/null
@@ -1,9 +0,0 @@
-# Keep class's integer static field for MessageUtils to parsing their name.
--keep class com.android.networkstack.tethering.Tethering$TetherMainSM {
- static final int CMD_*;
- static final int EVENT_*;
-}
-
--keepclassmembers class android.net.ip.IpServer {
- static final int CMD_*;
-}
diff --git a/packages/Tethering/res/drawable-hdpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-hdpi/stat_sys_tether_bluetooth.png
deleted file mode 100644
index 9451174d65d7c..0000000000000
Binary files a/packages/Tethering/res/drawable-hdpi/stat_sys_tether_bluetooth.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-hdpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-hdpi/stat_sys_tether_general.png
deleted file mode 100644
index 79d5756ae38ed..0000000000000
Binary files a/packages/Tethering/res/drawable-hdpi/stat_sys_tether_general.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-hdpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-hdpi/stat_sys_tether_usb.png
deleted file mode 100644
index cae1bd1b2574c..0000000000000
Binary files a/packages/Tethering/res/drawable-hdpi/stat_sys_tether_usb.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-ldpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-ldpi/stat_sys_tether_bluetooth.png
deleted file mode 100644
index ffe8e8c982326..0000000000000
Binary files a/packages/Tethering/res/drawable-ldpi/stat_sys_tether_bluetooth.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-ldpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-ldpi/stat_sys_tether_general.png
deleted file mode 100644
index ca20f73520909..0000000000000
Binary files a/packages/Tethering/res/drawable-ldpi/stat_sys_tether_general.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-ldpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-ldpi/stat_sys_tether_usb.png
deleted file mode 100644
index 65e907565ec15..0000000000000
Binary files a/packages/Tethering/res/drawable-ldpi/stat_sys_tether_usb.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-mdpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-mdpi/stat_sys_tether_bluetooth.png
deleted file mode 100644
index f42dae0fdcb90..0000000000000
Binary files a/packages/Tethering/res/drawable-mdpi/stat_sys_tether_bluetooth.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-mdpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-mdpi/stat_sys_tether_general.png
deleted file mode 100644
index 065516185ad48..0000000000000
Binary files a/packages/Tethering/res/drawable-mdpi/stat_sys_tether_general.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-mdpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-mdpi/stat_sys_tether_usb.png
deleted file mode 100644
index 2e2b8ca2e9cb0..0000000000000
Binary files a/packages/Tethering/res/drawable-mdpi/stat_sys_tether_usb.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_bluetooth.png
deleted file mode 100644
index 3f57d1c76ccb1..0000000000000
Binary files a/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_bluetooth.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_general.png
deleted file mode 100644
index 34b0cb36736a6..0000000000000
Binary files a/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_general.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_usb.png
deleted file mode 100644
index 36afe485b5bb6..0000000000000
Binary files a/packages/Tethering/res/drawable-xhdpi/stat_sys_tether_usb.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png b/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png
deleted file mode 100644
index 25acfbb01ba4c..0000000000000
Binary files a/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_bluetooth.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_general.png b/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_general.png
deleted file mode 100644
index 5c656012e6157..0000000000000
Binary files a/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_general.png and /dev/null differ
diff --git a/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_usb.png b/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_usb.png
deleted file mode 100644
index 28b4b5438e55a..0000000000000
Binary files a/packages/Tethering/res/drawable-xxhdpi/stat_sys_tether_usb.png and /dev/null differ
diff --git a/packages/Tethering/res/values-af/strings.xml b/packages/Tethering/res/values-af/strings.xml
deleted file mode 100644
index 056168b12e893..0000000000000
--- a/packages/Tethering/res/values-af/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Verbinding of warmkol is aktief"
- "Tik om op te stel."
- "Verbinding is gedeaktiveer"
- "Kontak jou administrateur vir besonderhede"
- "Warmkol- en verbindingstatus"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-am/strings.xml b/packages/Tethering/res/values-am/strings.xml
deleted file mode 100644
index ac468dd14414f..0000000000000
--- a/packages/Tethering/res/values-am/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "እንደ ሞደም መሰካት ወይም መገናኛ ነጥብ ገባሪ"
- "ለማዋቀር መታ ያድርጉ።"
- "እንደ ሞደም መሰካት ተሰናክሏል"
- "ለዝርዝሮች የእርስዎን አስተዳዳሪ ያነጋግሩ"
- "መገናኛ ነጥብ እና እንደ ሞደም የመሰካት ሁኔታ"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ar/strings.xml b/packages/Tethering/res/values-ar/strings.xml
deleted file mode 100644
index 7d5bad34da04f..0000000000000
--- a/packages/Tethering/res/values-ar/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "النطاق نشط أو نقطة الاتصال نشطة"
- "انقر للإعداد."
- "التوصيل متوقف."
- "تواصَل مع المشرف للحصول على التفاصيل."
- "حالة نقطة الاتصال والتوصيل"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-as/strings.xml b/packages/Tethering/res/values-as/strings.xml
deleted file mode 100644
index 091350455ba00..0000000000000
--- a/packages/Tethering/res/values-as/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "টে\'ডাৰিং অথবা হ\'টস্প\'ট সক্ৰিয় অৱস্থাত আছে"
- "ছেট আপ কৰিবলৈ টিপক।"
- "টে\'ডাৰিঙৰ সুবিধাটো অক্ষম কৰি থোৱা হৈছে"
- "সবিশেষ জানিবলৈ আপোনাৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক"
- "হ’টস্প\'ট আৰু টে\'ডাৰিঙৰ স্থিতি"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-az/strings.xml b/packages/Tethering/res/values-az/strings.xml
deleted file mode 100644
index dce70da178f14..0000000000000
--- a/packages/Tethering/res/values-az/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Birləşmə və ya hotspot aktivdir"
- "Ayarlamaq üçün toxunun."
- "Birləşmə deaktivdir"
- "Detallar üçün adminlə əlaqə saxlayın"
- "Hotspot & birləşmə statusu"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-b+sr+Latn/strings.xml b/packages/Tethering/res/values-b+sr+Latn/strings.xml
deleted file mode 100644
index b0774ec9a8409..0000000000000
--- a/packages/Tethering/res/values-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Privezivanje ili hotspot je aktivan"
- "Dodirnite da biste podesili."
- "Privezivanje je onemogućeno"
- "Potražite detalje od administratora"
- "Status hotspota i privezivanja"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-be/strings.xml b/packages/Tethering/res/values-be/strings.xml
deleted file mode 100644
index a8acebe2e992f..0000000000000
--- a/packages/Tethering/res/values-be/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Мадэм або хот-спот актыўныя"
- "Дакраніцеся, каб наладзіць."
- "Рэжым мадэма выключаны"
- "Звярніцеся да адміністратара па падрабязную інфармацыю"
- "Стан \"Хот-спот і мадэм\""
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-bg/strings.xml b/packages/Tethering/res/values-bg/strings.xml
deleted file mode 100644
index 94fb2d8f176a8..0000000000000
--- a/packages/Tethering/res/values-bg/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Има активна споделена връзка или точка за достъп"
- "Докоснете, за да настроите."
- "Функцията за тетъринг е деактивирана"
- "Свържете се с администратора си за подробности"
- "Състояние на функцията за точка за достъп и тетъринг"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-bn/strings.xml b/packages/Tethering/res/values-bn/strings.xml
deleted file mode 100644
index aea02b9ddff8e..0000000000000
--- a/packages/Tethering/res/values-bn/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "টিথারিং বা হটস্পট চালু আছে"
- "সেট-আপ করতে ট্যাপ করুন।"
- "টিথারিং বন্ধ করা আছে"
- "বিশদে জানতে অ্যাডমিনের সাথে যোগাযোগ করুন"
- "হটস্পট ও টিথারিং স্ট্যাটাস"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-bs/strings.xml b/packages/Tethering/res/values-bs/strings.xml
deleted file mode 100644
index de232724c5d94..0000000000000
--- a/packages/Tethering/res/values-bs/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Aktivno je povezivanje putem mobitela ili pristupna tačka"
- "Dodirnite da postavite."
- "Povezivanje putem mobitela je onemogućeno"
- "Kontaktirajte svog administratora za detalje"
- "Status pristupne tačke i povezivanja putem mobitela"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ca/strings.xml b/packages/Tethering/res/values-ca/strings.xml
deleted file mode 100644
index 88b795c1f8b2d..0000000000000
--- a/packages/Tethering/res/values-ca/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Compartició de xarxa o punt d\'accés Wi‑Fi actius"
- "Toca per configurar."
- "La compartició de xarxa està desactivada"
- "Contacta amb el teu administrador per obtenir més informació"
- "Estat del punt d\'accés Wi‑Fi i de la compartició de xarxa"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-cs/strings.xml b/packages/Tethering/res/values-cs/strings.xml
deleted file mode 100644
index 8c1b83bf3ee3f..0000000000000
--- a/packages/Tethering/res/values-cs/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tethering nebo hotspot je aktivní"
- "Klepnutím zahájíte nastavení."
- "Tethering je zakázán"
- "O podrobnosti požádejte administrátora"
- "Stav hotspotu a tetheringu"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-da/strings.xml b/packages/Tethering/res/values-da/strings.xml
deleted file mode 100644
index f413e7054819c..0000000000000
--- a/packages/Tethering/res/values-da/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Netdeling eller hotspot er aktivt"
- "Tryk for at konfigurere."
- "Netdeling er deaktiveret"
- "Kontakt din administrator for at få oplysninger"
- "Status for hotspot og netdeling"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-de/strings.xml b/packages/Tethering/res/values-de/strings.xml
deleted file mode 100644
index f057d7824e81d..0000000000000
--- a/packages/Tethering/res/values-de/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tethering oder Hotspot aktiv"
- "Zum Einrichten tippen."
- "Tethering ist deaktiviert"
- "Bitte wende dich für weitere Informationen an den Administrator"
- "Hotspot- und Tethering-Status"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-el/strings.xml b/packages/Tethering/res/values-el/strings.xml
deleted file mode 100644
index b3c986bdafd6c..0000000000000
--- a/packages/Tethering/res/values-el/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Πρόσδεση ή σύνδεση σημείου πρόσβασης ενεργή"
- "Πατήστε για ρύθμιση."
- "Η σύνδεση είναι απενεργοποιημένη"
- "Επικοινωνήστε με τον διαχειριστή σας για λεπτομέρειες"
- "Κατάσταση σημείου πρόσβασης Wi-Fi και σύνδεσης"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-en-rAU/strings.xml b/packages/Tethering/res/values-en-rAU/strings.xml
deleted file mode 100644
index 769e01208afc2..0000000000000
--- a/packages/Tethering/res/values-en-rAU/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tethering or hotspot active"
- "Tap to set up."
- "Tethering is disabled"
- "Contact your admin for details"
- "Hotspot and tethering status"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-en-rCA/strings.xml b/packages/Tethering/res/values-en-rCA/strings.xml
deleted file mode 100644
index 769e01208afc2..0000000000000
--- a/packages/Tethering/res/values-en-rCA/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tethering or hotspot active"
- "Tap to set up."
- "Tethering is disabled"
- "Contact your admin for details"
- "Hotspot and tethering status"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-en-rGB/strings.xml b/packages/Tethering/res/values-en-rGB/strings.xml
deleted file mode 100644
index 769e01208afc2..0000000000000
--- a/packages/Tethering/res/values-en-rGB/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tethering or hotspot active"
- "Tap to set up."
- "Tethering is disabled"
- "Contact your admin for details"
- "Hotspot and tethering status"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-en-rIN/strings.xml b/packages/Tethering/res/values-en-rIN/strings.xml
deleted file mode 100644
index 769e01208afc2..0000000000000
--- a/packages/Tethering/res/values-en-rIN/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tethering or hotspot active"
- "Tap to set up."
- "Tethering is disabled"
- "Contact your admin for details"
- "Hotspot and tethering status"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-en-rXC/strings.xml b/packages/Tethering/res/values-en-rXC/strings.xml
deleted file mode 100644
index f1674bed4eb75..0000000000000
--- a/packages/Tethering/res/values-en-rXC/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tethering or hotspot active"
- "Tap to set up."
- "Tethering is disabled"
- "Contact your admin for details"
- "Hotspot & tethering status"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-es-rUS/strings.xml b/packages/Tethering/res/values-es-rUS/strings.xml
deleted file mode 100644
index 63689f43997c2..0000000000000
--- a/packages/Tethering/res/values-es-rUS/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Conexión a red o hotspot conectados"
- "Presiona para configurar esta opción."
- "Se inhabilitó la conexión mediante dispositivo portátil"
- "Para obtener más información, comunícate con el administrador"
- "Estado del hotspot y la conexión mediante dispositivo portátil"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-es/strings.xml b/packages/Tethering/res/values-es/strings.xml
deleted file mode 100644
index 9a34ed5e388a1..0000000000000
--- a/packages/Tethering/res/values-es/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Conexión compartida o punto de acceso activos"
- "Toca para configurar."
- "La conexión compartida está inhabilitada"
- "Solicita más información a tu administrador"
- "Estado del punto de acceso y de la conexión compartida"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-et/strings.xml b/packages/Tethering/res/values-et/strings.xml
deleted file mode 100644
index 0970341ab0cd1..0000000000000
--- a/packages/Tethering/res/values-et/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Jagamine või kuumkoht on aktiivne"
- "Puudutage seadistamiseks."
- "Jagamine on keelatud"
- "Lisateabe saamiseks võtke ühendust oma administraatoriga"
- "Kuumkoha ja jagamise olek"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-eu/strings.xml b/packages/Tethering/res/values-eu/strings.xml
deleted file mode 100644
index 632019e2ef1be..0000000000000
--- a/packages/Tethering/res/values-eu/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Konexioa partekatzea edo wifi-gunea aktibo dago"
- "Sakatu konfiguratzeko."
- "Desgaituta dago konexioa partekatzeko aukera"
- "Xehetasunak lortzeko, jarri administratzailearekin harremanetan"
- "Wifi-gunearen eta konexioa partekatzeko eginbidearen egoera"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-fa/strings.xml b/packages/Tethering/res/values-fa/strings.xml
deleted file mode 100644
index 2e21c85fa179c..0000000000000
--- a/packages/Tethering/res/values-fa/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "اشتراکگذاری اینترنت یا نقطه اتصال فعال"
- "برای راهاندازی ضربه بزنید."
- "اشتراکگذاری اینترنت غیرفعال است"
- "برای جزئیات، با سرپرستتان تماس بگیرید"
- "وضعیت نقطه اتصال و اشتراکگذاری اینترنت"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-fi/strings.xml b/packages/Tethering/res/values-fi/strings.xml
deleted file mode 100644
index 413db3f0f8c91..0000000000000
--- a/packages/Tethering/res/values-fi/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Yhteyden jakaminen tai hotspot käytössä"
- "Ota käyttöön napauttamalla."
- "Yhteyden jakaminen on poistettu käytöstä"
- "Pyydä lisätietoja järjestelmänvalvojalta"
- "Hotspotin ja yhteyden jakamisen tila"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-fr-rCA/strings.xml b/packages/Tethering/res/values-fr-rCA/strings.xml
deleted file mode 100644
index eb2e4ba540009..0000000000000
--- a/packages/Tethering/res/values-fr-rCA/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Partage de connexion ou point d\'accès sans fil activé"
- "Touchez pour configurer."
- "Le partage de connexion est désactivé"
- "Communiquez avec votre administrateur pour obtenir plus de détails"
- "Point d\'accès et partage de connexion"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-fr/strings.xml b/packages/Tethering/res/values-fr/strings.xml
deleted file mode 100644
index 22259c52ab9e8..0000000000000
--- a/packages/Tethering/res/values-fr/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Partage de connexion ou point d\'accès activé"
- "Appuyez pour effectuer la configuration."
- "Le partage de connexion est désactivé"
- "Pour en savoir plus, contactez votre administrateur"
- "État du point d\'accès et du partage de connexion"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-gl/strings.xml b/packages/Tethering/res/values-gl/strings.xml
deleted file mode 100644
index ded82fcd54ad0..0000000000000
--- a/packages/Tethering/res/values-gl/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Conexión compartida ou zona wifi activada"
- "Toca para configurar."
- "A conexión compartida está desactivada"
- "Contacta co administrador para obter información"
- "Estado da zona wifi e da conexión compartida"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-gu/strings.xml b/packages/Tethering/res/values-gu/strings.xml
deleted file mode 100644
index 7cbbc2de3d91a..0000000000000
--- a/packages/Tethering/res/values-gu/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "ઇન્ટરનેટ શેર કરવાની સુવિધા અથવા હૉટસ્પૉટ સક્રિય છે"
- "સેટઅપ કરવા માટે ટૅપ કરો."
- "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરી છે"
- "વિગતો માટે તમારા વ્યવસ્થાપકનો સંપર્ક કરો"
- "હૉટસ્પૉટ અને ઇન્ટરનેટ શેર કરવાની સુવિધાનું સ્ટેટસ"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-hi/strings.xml b/packages/Tethering/res/values-hi/strings.xml
deleted file mode 100644
index 08af81b826b32..0000000000000
--- a/packages/Tethering/res/values-hi/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "टेदरिंग या हॉटस्पॉट चालू है"
- "सेट अप करने के लिए टैप करें."
- "टेदरिंग बंद है"
- "जानकारी के लिए अपने एडमिन से संपर्क करें"
- "हॉटस्पॉट और टेदरिंग की स्थिति"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-hr/strings.xml b/packages/Tethering/res/values-hr/strings.xml
deleted file mode 100644
index 827c135f205d8..0000000000000
--- a/packages/Tethering/res/values-hr/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Modemsko povezivanje ili žarišna točka aktivni"
- "Dodirnite da biste postavili."
- "Modemsko je povezivanje onemogućeno"
- "Obratite se administratoru da biste saznali pojedinosti"
- "Status žarišne točke i modemskog povezivanja"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-hu/strings.xml b/packages/Tethering/res/values-hu/strings.xml
deleted file mode 100644
index eb68d6babf8f4..0000000000000
--- a/packages/Tethering/res/values-hu/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Megosztás vagy aktív hotspot"
- "Koppintson a beállításhoz."
- "Az internetmegosztás le van tiltva"
- "A részletekért forduljon rendszergazdájához"
- "Hotspot és internetmegosztás állapota"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-hy/strings.xml b/packages/Tethering/res/values-hy/strings.xml
deleted file mode 100644
index 912941e53835e..0000000000000
--- a/packages/Tethering/res/values-hy/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Մոդեմի ռեժիմը միացված է"
- "Հպեք՝ կարգավորելու համար։"
- "Մոդեմի ռեժիմն անջատված է"
- "Մանրամասների համար դիմեք ձեր ադմինիստրատորին"
- "Թեժ կետի և մոդեմի ռեժիմի կարգավիճակը"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-in/strings.xml b/packages/Tethering/res/values-in/strings.xml
deleted file mode 100644
index a4e175a439e9c..0000000000000
--- a/packages/Tethering/res/values-in/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tethering atau hotspot aktif"
- "Ketuk untuk menyiapkan."
- "Tethering dinonaktifkan"
- "Hubungi admin untuk mengetahui detailnya"
- "Status hotspot & tethering"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-is/strings.xml b/packages/Tethering/res/values-is/strings.xml
deleted file mode 100644
index e9f6670bcd092..0000000000000
--- a/packages/Tethering/res/values-is/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Kveikt á tjóðrun eða aðgangsstað"
- "Ýttu til að setja upp."
- "Slökkt er á tjóðrun"
- "Hafðu samband við kerfisstjórann til að fá upplýsingar"
- "Staða heits reits og tjóðrunar"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-it/strings.xml b/packages/Tethering/res/values-it/strings.xml
deleted file mode 100644
index ffb9196f5ee31..0000000000000
--- a/packages/Tethering/res/values-it/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Hotspot o tethering attivo"
- "Tocca per impostare."
- "Tethering disattivato"
- "Contatta il tuo amministratore per avere informazioni dettagliate"
- "Stato hotspot e tethering"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-iw/strings.xml b/packages/Tethering/res/values-iw/strings.xml
deleted file mode 100644
index 7adcb47350c1b..0000000000000
--- a/packages/Tethering/res/values-iw/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "נקודה לשיתוף אינטרנט או שיתוף אינטרנט בין מכשירים: בסטטוס פעיל"
- "יש להקיש כדי להגדיר."
- "שיתוף האינטרנט בין מכשירים מושבת"
- "לפרטים, יש לפנות למנהל המערכת"
- "סטטוס של נקודה לשיתוף אינטרנט ושיתוף אינטרנט בין מכשירים"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ja/strings.xml b/packages/Tethering/res/values-ja/strings.xml
deleted file mode 100644
index f68a73010b361..0000000000000
--- a/packages/Tethering/res/values-ja/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "テザリングまたはアクセス ポイントが有効です"
- "タップしてセットアップします。"
- "テザリングは無効に設定されています"
- "詳しくは、管理者にお問い合わせください"
- "アクセス ポイントとテザリングのステータス"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ka/strings.xml b/packages/Tethering/res/values-ka/strings.xml
deleted file mode 100644
index 7c22e82bd370a..0000000000000
--- a/packages/Tethering/res/values-ka/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "ტეტერინგი ან უსადენო ქსელი აქტიურია"
- "შეეხეთ დასაყენებლად."
- "ტეტერინგი გათიშულია"
- "დამატებითი ინფორმაციისთვის დაუკავშირდით თქვენს ადმინისტრატორს"
- "უსადენო ქსელის და ტეტერინგის სტატუსი"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-kk/strings.xml b/packages/Tethering/res/values-kk/strings.xml
deleted file mode 100644
index 0857d06de243e..0000000000000
--- a/packages/Tethering/res/values-kk/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Тетеринг немесе хотспот қосулы"
- "Реттеу үшін түртіңіз."
- "Тетеринг өшірілді."
- "Мәліметтерді әкімшіден алыңыз."
- "Хотспот және тетеринг күйі"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-km/strings.xml b/packages/Tethering/res/values-km/strings.xml
deleted file mode 100644
index 536e3d1703b19..0000000000000
--- a/packages/Tethering/res/values-km/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "ការភ្ជាប់ ឬហតស្ប៉តកំពុងដំណើរការ"
- "ចុចដើម្បីរៀបចំ។"
- "ការភ្ជាប់ត្រូវបានបិទ"
- "ទាក់ទងអ្នកគ្រប់គ្រងរបស់អ្នក ដើម្បីទទួលបានព័ត៌មានលម្អិត"
- "ស្ថានភាពនៃការភ្ជាប់ និងហតស្ប៉ត"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-kn/strings.xml b/packages/Tethering/res/values-kn/strings.xml
deleted file mode 100644
index 32f54926f4bf0..0000000000000
--- a/packages/Tethering/res/values-kn/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "ಟೆಥರಿಂಗ್ ಅಥವಾ ಹಾಟ್ಸ್ಪಾಟ್ ಸಕ್ರಿಯವಾಗಿದೆ"
- "ಸೆಟಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ."
- "ಟೆಥರಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"
- "ವಿವರಗಳಿಗಾಗಿ ನಿಮ್ಮ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ"
- "ಹಾಟ್ಸ್ಪಾಟ್ ಮತ್ತು ಟೆಥರಿಂಗ್ ಸ್ಥಿತಿ"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ko/strings.xml b/packages/Tethering/res/values-ko/strings.xml
deleted file mode 100644
index 156b24786db55..0000000000000
--- a/packages/Tethering/res/values-ko/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "테더링 또는 핫스팟 사용"
- "설정하려면 탭하세요."
- "테더링이 사용 중지됨"
- "자세한 정보는 관리자에게 문의하세요."
- "핫스팟 및 테더링 상태"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ky/strings.xml b/packages/Tethering/res/values-ky/strings.xml
deleted file mode 100644
index 18ee5fd35718b..0000000000000
--- a/packages/Tethering/res/values-ky/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Модем режими күйүп турат"
- "Жөндөө үчүн таптап коюңуз."
- "Телефонду модем катары колдонууга болбойт"
- "Кеңири маалымат үчүн администраторуңузга кайрылыңыз"
- "Байланыш түйүнүнүн жана модем режиминин статусу"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-lo/strings.xml b/packages/Tethering/res/values-lo/strings.xml
deleted file mode 100644
index b12767018c3aa..0000000000000
--- a/packages/Tethering/res/values-lo/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "ເປີດການປ່ອຍສັນຍານ ຫຼື ຮັອດສະປອດແລ້ວ"
- "ແຕະເພື່ອຕັ້ງຄ່າ."
- "ການປ່ອຍສັນຍານຖືກປິດໄວ້"
- "ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບສຳລັບລາຍລະອຽດ"
- "ສະຖານະຮັອດສະປອດ ແລະ ການປ່ອຍສັນຍານ"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-lt/strings.xml b/packages/Tethering/res/values-lt/strings.xml
deleted file mode 100644
index 8427baf39f31a..0000000000000
--- a/packages/Tethering/res/values-lt/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Įrenginys naudojamas kaip modemas arba įjungtas viešosios interneto prieigos taškas"
- "Palieskite, kad nustatytumėte."
- "Įrenginio kaip modemo naudojimas išjungtas"
- "Jei reikia išsamios informacijos, susisiekite su administratoriumi"
- "Viešosios interneto prieigos taško ir įrenginio kaip modemo naudojimo būsena"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-lv/strings.xml b/packages/Tethering/res/values-lv/strings.xml
deleted file mode 100644
index aa2d6990e04f0..0000000000000
--- a/packages/Tethering/res/values-lv/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Piesaiste vai tīklājs ir aktīvs."
- "Pieskarieties, lai to iestatītu."
- "Piesaiste ir atspējota"
- "Lai iegūtu detalizētu informāciju, sazinieties ar savu administratoru."
- "Tīklāja un piesaistes statuss"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-af/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-af/strings.xml
deleted file mode 100644
index 19d659c6ce366..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-af/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Verbinding het nie internet nie"
- "Toestelle kan nie koppel nie"
- "Skakel verbinding af"
- "Warmkol of verbinding is aan"
- "Bykomende heffings kan geld terwyl jy swerf"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-am/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-am/strings.xml
deleted file mode 100644
index 8995430b4f093..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-am/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ማስተሳሰር ምንም በይነመረብ የለውም"
- "መሣሪያዎችን ማገናኘት አይቻልም"
- "ማስተሳሰርን አጥፋ"
- "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል"
- "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ar/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ar/strings.xml
deleted file mode 100644
index 54f3b5389ae98..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ar/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ما مِن اتصال بالإنترنت خلال التوصيل"
- "تعذّر اتصال الأجهزة"
- "إيقاف التوصيل"
- "نقطة الاتصال أو التوصيل مفعّلان"
- "قد يتم تطبيق رسوم إضافية أثناء التجوال."
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-as/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-as/strings.xml
deleted file mode 100644
index e215141c9eb63..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-as/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই"
- "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি"
- "টে\'ডাৰিং অফ কৰক"
- "হটস্পট অথবা টে\'ডাৰিং অন আছে"
- "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-az/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-az/strings.xml
deleted file mode 100644
index 1fd8e4c963a7f..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-az/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Modemin internetə girişi yoxdur"
- "Cihazları qoşmaq mümkün deyil"
- "Modemi deaktiv edin"
- "Hotspot və ya modem aktivdir"
- "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml
deleted file mode 100644
index 1abe4f3aa3c7c..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Privezivanje nema pristup internetu"
- "Povezivanje uređaja nije uspelo"
- "Isključi privezivanje"
- "Uključen je hotspot ili privezivanje"
- "Možda važe dodatni troškovi u romingu"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-be/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-be/strings.xml
deleted file mode 100644
index 38dbd1e3914fd..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-be/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту"
- "Не ўдалося падключыць прылады"
- "Выключыць рэжым мадэма"
- "Хот-спот або рэжым мадэма ўключаны"
- "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-bg/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-bg/strings.xml
deleted file mode 100644
index 04b44db5c1a49..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-bg/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Тетърингът няма връзка с интернет"
- "Устройствата не могат да установят връзка"
- "Изключване на тетъринга"
- "Точката за достъп или тетърингът са включени"
- "Възможно е да ви бъдат начислени допълнителни такси при роуминг"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-bn/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-bn/strings.xml
deleted file mode 100644
index 579d1be1c1ea2..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-bn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই"
- "ডিভাইস কানেক্ট করতে পারছে না"
- "টিথারিং বন্ধ করুন"
- "হটস্পট বা টিথারিং চালু আছে"
- "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-bs/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-bs/strings.xml
deleted file mode 100644
index 9ce3efe6c39de..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-bs/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Povezivanje putem mobitela nema internet"
- "Uređaji se ne mogu povezati"
- "Isključi povezivanje putem mobitela"
- "Pristupna tačka ili povezivanje putem mobitela je uključeno"
- "Mogu nastati dodatni troškovi u romingu"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ca/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ca/strings.xml
deleted file mode 100644
index 46d4c35b9b83c..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ca/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "La compartició de xarxa no té accés a Internet"
- "No es poden connectar els dispositius"
- "Desactiva la compartició de xarxa"
- "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa"
- "És possible que s\'apliquin costos addicionals en itinerància"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-cs/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-cs/strings.xml
deleted file mode 100644
index cc13860b3da18..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-cs/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering nemá připojení k internetu"
- "Zařízení se nemůžou připojit"
- "Vypnout tethering"
- "Je zapnutý hotspot nebo tethering"
- "Při roamingu mohou být účtovány dodatečné poplatky"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-da/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-da/strings.xml
deleted file mode 100644
index 92c3ae11567de..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-da/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Netdeling har ingen internetforbindelse"
- "Enheder kan ikke oprette forbindelse"
- "Deaktiver netdeling"
- "Hotspot eller netdeling er aktiveret"
- "Der opkræves muligvis yderligere gebyrer ved roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-de/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-de/strings.xml
deleted file mode 100644
index 967eb4db2e772..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-de/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering hat keinen Internetzugriff"
- "Geräte können sich nicht verbinden"
- "Tethering deaktivieren"
- "Hotspot oder Tethering ist aktiviert"
- "Für das Roaming können zusätzliche Gebühren anfallen"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-el/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-el/strings.xml
deleted file mode 100644
index 5fb497451f6d3..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-el/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο"
- "Δεν είναι δυνατή η σύνδεση των συσκευών"
- "Απενεργοποιήστε τη σύνδεση"
- "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση"
- "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή."
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml
deleted file mode 100644
index 45647f93f2466..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-en-rAU/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering has no Internet"
- "Devices can’t connect"
- "Turn off tethering"
- "Hotspot or tethering is on"
- "Additional charges may apply while roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml
deleted file mode 100644
index 45647f93f2466..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-en-rCA/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering has no Internet"
- "Devices can’t connect"
- "Turn off tethering"
- "Hotspot or tethering is on"
- "Additional charges may apply while roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml
deleted file mode 100644
index 45647f93f2466..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-en-rGB/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering has no Internet"
- "Devices can’t connect"
- "Turn off tethering"
- "Hotspot or tethering is on"
- "Additional charges may apply while roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml
deleted file mode 100644
index 45647f93f2466..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-en-rIN/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering has no Internet"
- "Devices can’t connect"
- "Turn off tethering"
- "Hotspot or tethering is on"
- "Additional charges may apply while roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml
deleted file mode 100644
index 7877074afc665..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-en-rXC/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering has no internet"
- "Devices can’t connect"
- "Turn off tethering"
- "Hotspot or tethering is on"
- "Additional charges may apply while roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml
deleted file mode 100644
index 08edd81a6b041..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-es-rUS/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "La conexión mediante dispositivo móvil no tiene Internet"
- "No se pueden conectar los dispositivos"
- "Desactivar conexión mediante dispositivo móvil"
- "Se activó el hotspot o la conexión mediante dispositivo móvil"
- "Es posible que se apliquen cargos adicionales por roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-es/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-es/strings.xml
deleted file mode 100644
index 79f51d00e2e85..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-es/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "La conexión no se puede compartir, porque no hay acceso a Internet"
- "Los dispositivos no se pueden conectar"
- "Desactivar conexión compartida"
- "Punto de acceso o conexión compartida activados"
- "Puede que se apliquen cargos adicionales en itinerancia"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-et/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-et/strings.xml
deleted file mode 100644
index 2da5f8a6d62a1..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-et/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Jagamisel puudub internetiühendus"
- "Seadmed ei saa ühendust luua"
- "Lülita jagamine välja"
- "Kuumkoht või jagamine on sisse lülitatud"
- "Rändluse kasutamisega võivad kaasneda lisatasud"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-eu/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-eu/strings.xml
deleted file mode 100644
index 2073f2806c187..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-eu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Konexioa partekatzeko aukerak ez du Interneteko konexiorik"
- "Ezin dira konektatu gailuak"
- "Desaktibatu konexioa partekatzeko aukera"
- "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago"
- "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-fa/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-fa/strings.xml
deleted file mode 100644
index e21b2a0852c71..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-fa/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "«اشتراکگذاری اینترنت» به اینترنت دسترسی ندارد"
- "دستگاهها متصل نمیشوند"
- "خاموش کردن «اشتراکگذاری اینترنت»"
- "«نقطه اتصال» یا «اشتراکگذاری اینترنت» روشن است"
- "ممکن است درحین فراگردی تغییرات دیگر اعمال شود"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-fi/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-fi/strings.xml
deleted file mode 100644
index 88b0b13eb4b52..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-fi/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Ei jaettavaa internetyhteyttä"
- "Laitteet eivät voi muodostaa yhteyttä"
- "Laita yhteyden jakaminen pois päältä"
- "Hotspot tai yhteyden jakaminen on päällä"
- "Roaming voi aiheuttaa lisämaksuja"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml
deleted file mode 100644
index 3b781bc8db31d..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-fr-rCA/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Le partage de connexion n\'est pas connecté à Internet"
- "Impossible de connecter les appareils"
- "Désactiver le partage de connexion"
- "Le point d\'accès ou le partage de connexion est activé"
- "En itinérance, des frais supplémentaires peuvent s\'appliquer"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-fr/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-fr/strings.xml
deleted file mode 100644
index 51d7203c3652d..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-fr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Aucune connexion à Internet n\'est disponible pour le partage de connexion"
- "Impossible de connecter les appareils"
- "Désactiver le partage de connexion"
- "Le point d\'accès ou le partage de connexion est activé"
- "En itinérance, des frais supplémentaires peuvent s\'appliquer"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-gl/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-gl/strings.xml
deleted file mode 100644
index 008ccb475d667..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-gl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "A conexión compartida non ten Internet"
- "Non se puideron conectar os dispositivos"
- "Desactivar conexión compartida"
- "Está activada a zona wifi ou a conexión compartida"
- "Pódense aplicar cargos adicionais en itinerancia"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-gu/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-gu/strings.xml
deleted file mode 100644
index f2e3b4df782f5..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-gu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી"
- "ડિવાઇસ કનેક્ટ કરી શકાતા નથી"
- "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો"
- "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે"
- "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-hi/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-hi/strings.xml
deleted file mode 100644
index b11839d760c81..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-hi/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "टेदरिंग से इंटरनेट नहीं चल रहा"
- "डिवाइस कनेक्ट नहीं हो पा रहे"
- "टेदरिंग बंद करें"
- "हॉटस्पॉट या टेदरिंग चालू है"
- "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-hr/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-hr/strings.xml
deleted file mode 100644
index 0a5aca25b1a9e..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-hr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Modemsko povezivanje nema internet"
- "Uređaji se ne mogu povezati"
- "Isključivanje modemskog povezivanja"
- "Uključena je žarišna točka ili modemsko povezivanje"
- "U roamingu su mogući dodatni troškovi"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-hu/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-hu/strings.xml
deleted file mode 100644
index 21c689a44ef8e..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-hu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Nincs internetkapcsolat az internet megosztásához"
- "Az eszközök nem tudnak csatlakozni"
- "Internetmegosztás kikapcsolása"
- "A hotspot vagy az internetmegosztás be van kapcsolva"
- "Roaming során további díjak léphetnek fel"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-hy/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-hy/strings.xml
deleted file mode 100644
index 689d92870e509..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-hy/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Մոդեմի ռեժիմի կապը բացակայում է"
- "Չհաջողվեց միացնել սարքը"
- "Անջատել մոդեմի ռեժիմը"
- "Թեժ կետը կամ մոդեմի ռեժիմը միացված է"
- "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-in/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-in/strings.xml
deleted file mode 100644
index a5f4d19abfe99..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-in/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tidak ada koneksi internet di tethering"
- "Perangkat tidak dapat terhubung"
- "Nonaktifkan tethering"
- "Hotspot atau tethering aktif"
- "Biaya tambahan mungkin berlaku saat roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-is/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-is/strings.xml
deleted file mode 100644
index fc7e8aaf4e425..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-is/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tjóðrun er ekki með internettengingu"
- "Tæki geta ekki tengst"
- "Slökkva á tjóðrun"
- "Kveikt er á heitum reit eða tjóðrun"
- "Viðbótargjöld kunna að eiga við í reiki"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-it/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-it/strings.xml
deleted file mode 100644
index 6456dd1b806a5..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-it/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Nessuna connessione a Internet per il tethering"
- "Impossibile connettere i dispositivi"
- "Disattiva il tethering"
- "Hotspot o tethering attivi"
- "Potrebbero essere applicati costi aggiuntivi durante il roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-iw/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-iw/strings.xml
deleted file mode 100644
index 46b24bd3c508b..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-iw/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט"
- "למכשירים אין אפשרות להתחבר"
- "השבתה של שיתוף האינטרנט בין מכשירים"
- "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת"
- "ייתכנו חיובים נוספים בעת נדידה"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ja/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ja/strings.xml
deleted file mode 100644
index e6eb277b90dd4..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ja/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "テザリングがインターネットに接続されていません"
- "デバイスを接続できません"
- "テザリングを OFF にする"
- "アクセス ポイントまたはテザリングが ON です"
- "ローミング時に追加料金が発生することがあります"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ka/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ka/strings.xml
deleted file mode 100644
index aeddd7101da0e..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ka/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ტეტერინგს არ აქვს ინტერნეტზე წვდომა"
- "მოწყობილობები ვერ ახერხებენ დაკავშირებას"
- "ტეტერინგის გამორთვა"
- "ჩართულია უსადენო ქსელი ან ტეტერინგი"
- "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-kk/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-kk/strings.xml
deleted file mode 100644
index 255f0a276f950..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-kk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Тетеринг режимі интернет байланысынсыз пайдаланылуда"
- "Құрылғыларды байланыстыру мүмкін емес"
- "Тетерингіні өшіру"
- "Хотспот немесе тетеринг қосулы"
- "Роуминг кезінде қосымша ақы алынуы мүмкін."
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-km/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-km/strings.xml
deleted file mode 100644
index 2bceb1cf7788b..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-km/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ការភ្ជាប់មិនមានអ៊ីនធឺណិតទេ"
- "មិនអាចភ្ជាប់ឧបករណ៍បានទេ"
- "បិទការភ្ជាប់"
- "ហតស្ប៉ត ឬការភ្ជាប់ត្រូវបានបើក"
- "អាចមានការគិតថ្លៃបន្ថែម នៅពេលរ៉ូមីង"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-kn/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-kn/strings.xml
deleted file mode 100644
index ed769305a679d..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-kn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ಟೆಥರಿಂಗ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ"
- "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"
- "ಟೆಥರಿಂಗ್ ಆಫ್ ಮಾಡಿ"
- "ಹಾಟ್ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್ ಆನ್ ಆಗಿದೆ"
- "ರೋಮಿಂಗ್ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ko/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ko/strings.xml
deleted file mode 100644
index 6e504941eb8b1..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ko/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "테더링으로 인터넷을 사용할 수 없음"
- "기기에서 연결할 수 없음"
- "테더링 사용 중지"
- "핫스팟 또는 테더링 켜짐"
- "로밍 중에는 추가 요금이 발생할 수 있습니다."
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ky/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ky/strings.xml
deleted file mode 100644
index d68128b9a5544..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ky/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Модем режими Интернети жок колдонулууда"
- "Түзмөктөр туташпай жатат"
- "Модем режимин өчүрүү"
- "Байланыш түйүнү же модем режими күйүк"
- "Роумингде кошумча акы алынышы мүмкүн"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-lo/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-lo/strings.xml
deleted file mode 100644
index 03e134a0fc79f..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-lo/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ"
- "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້"
- "ປິດການປ່ອຍສັນຍານ"
- "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່"
- "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-lt/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-lt/strings.xml
deleted file mode 100644
index 652cedc6e6aef..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-lt/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Nėra įrenginio kaip modemo naudojimo interneto ryšio"
- "Nepavyko susieti įrenginių"
- "Išjungti įrenginio kaip modemo naudojimą"
- "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas"
- "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-lv/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-lv/strings.xml
deleted file mode 100644
index 221972298c183..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-lv/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Piesaistei nav interneta savienojuma"
- "Nevar savienot ierīces"
- "Izslēgt piesaisti"
- "Ir ieslēgts tīklājs vai piesaiste"
- "Viesabonēšanas laikā var tikt piemērota papildu samaksa"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-mk/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-mk/strings.xml
deleted file mode 100644
index 227f9e3466516..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-mk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Нема интернет преку мобилен"
- "Уредите не може да се поврзат"
- "Исклучи интернет преку мобилен"
- "Точката на пристап или интернетот преку мобилен е вклучен"
- "При роаминг може да се наплатат дополнителни трошоци"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ml/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ml/strings.xml
deleted file mode 100644
index ec4388512645a..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ml/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല"
- "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല"
- "ടെതറിംഗ് ഓഫാക്കുക"
- "ഹോട്ട്സ്പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്"
- "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-mn/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-mn/strings.xml
deleted file mode 100644
index e263573799edd..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-mn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Модемд интернэт алга байна"
- "Төхөөрөмжүүд холбогдох боломжгүй байна"
- "Модем болгохыг унтраах"
- "Сүлжээний цэг эсвэл модем болгох асаалттай байна"
- "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-mr/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-mr/strings.xml
deleted file mode 100644
index adf845d078bf0..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-mr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "टेदरिंगला इंटरनेट नाही"
- "डिव्हाइस कनेक्ट होऊ शकत नाहीत"
- "टेदरिंग बंद करा"
- "हॉटस्पॉट किंवा टेदरिंग सुरू आहे"
- "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ms/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ms/strings.xml
deleted file mode 100644
index f65c451e4c21b..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ms/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Penambatan tiada Internet"
- "Peranti tidak dapat disambungkan"
- "Matikan penambatan"
- "Tempat liputan atau penambatan dihidupkan"
- "Caj tambahan mungkin digunakan semasa perayauan"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-my/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-my/strings.xml
deleted file mode 100644
index 4118e775cd843..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-my/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ"
- "စက်များ ချိတ်ဆက်၍ မရပါ"
- "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်"
- "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်"
- "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-nb/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-nb/strings.xml
deleted file mode 100644
index 36853583ce829..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-nb/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Internettdeling har ikke internettilgang"
- "Enhetene kan ikke koble til"
- "Slå av internettdeling"
- "Wi-Fi-sone eller internettdeling er på"
- "Ytterligere kostnader kan påløpe under roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ne/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ne/strings.xml
deleted file mode 100644
index d074f1569933d..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ne/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन"
- "यन्त्रहरू कनेक्ट गर्न सकिएन"
- "टेदरिङ निष्क्रिय पार्नुहोस्"
- "हटस्पट वा टेदरिङ सक्रिय छ"
- "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-nl/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-nl/strings.xml
deleted file mode 100644
index 1d888942f49b9..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-nl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering heeft geen internet"
- "Apparaten kunnen niet worden verbonden"
- "Tethering uitschakelen"
- "Hotspot of tethering is ingeschakeld"
- "Er kunnen extra kosten voor roaming in rekening worden gebracht."
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-or/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-or/strings.xml
deleted file mode 100644
index 8038815fe8042..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-or/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ"
- "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ"
- "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ"
- "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି"
- "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-pa/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-pa/strings.xml
deleted file mode 100644
index 819833eab07f3..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-pa/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"
- "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ"
- "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ"
- "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ"
- "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-pl/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-pl/strings.xml
deleted file mode 100644
index 65e4380e39163..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-pl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering nie ma internetu"
- "Urządzenia nie mogą się połączyć"
- "Wyłącz tethering"
- "Hotspot lub tethering jest włączony"
- "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml
deleted file mode 100644
index d8866170c1914..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-pt-rBR/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "O tethering não tem Internet"
- "Não é possível conectar os dispositivos"
- "Desativar o tethering"
- "Ponto de acesso ou tethering ativado"
- "Pode haver cobranças extras durante o roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml
deleted file mode 100644
index bfd45ca0a3e19..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-pt-rPT/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "A ligação (à Internet) via telemóvel não tem Internet"
- "Não é possível ligar os dispositivos"
- "Desativar ligação (à Internet) via telemóvel"
- "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada"
- "Podem aplicar-se custos adicionais em roaming."
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-pt/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-pt/strings.xml
deleted file mode 100644
index d8866170c1914..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-pt/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "O tethering não tem Internet"
- "Não é possível conectar os dispositivos"
- "Desativar o tethering"
- "Ponto de acesso ou tethering ativado"
- "Pode haver cobranças extras durante o roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ro/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ro/strings.xml
deleted file mode 100644
index 8d87a9e516ad7..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ro/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Procesul de tethering nu are internet"
- "Dispozitivele nu se pot conecta"
- "Dezactivați procesul de tethering"
- "S-a activat hotspotul sau tethering"
- "Se pot aplica taxe suplimentare pentru roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ru/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ru/strings.xml
deleted file mode 100644
index dbdb9ebe49311..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ru/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Режим модема используется без доступа к Интернету"
- "Невозможно подключить устройства."
- "Отключить режим модема"
- "Включены точка доступа или режим модема"
- "За использование услуг связи в роуминге может взиматься дополнительная плата."
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-si/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-si/strings.xml
deleted file mode 100644
index d8301e41c2b2a..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-si/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ටෙදරින් හට අන්තර්ජාලය නැත"
- "උපාංගවලට සම්බන්ධ විය නොහැකිය"
- "ටෙදරින් ක්රියාවිරහිත කරන්න"
- "හොට්ස්පොට් හෝ ටෙදරින් ක්රියාත්මකයි"
- "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-sk/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-sk/strings.xml
deleted file mode 100644
index bef71363f450a..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-sk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering nemá internetové pripojenie"
- "Zariadenia sa nemôžu pripojiť"
- "Vypnúť tethering"
- "Je zapnutý hotspot alebo tethering"
- "Počas roamingu vám môžu byť účtované ďalšie poplatky"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-sl/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-sl/strings.xml
deleted file mode 100644
index 3202c62e8a3a7..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-sl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Internetna povezava prek mobilnega telefona ni vzpostavljena"
- "Napravi se ne moreta povezati"
- "Izklopi internetno povezavo prek mobilnega telefona"
- "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena"
- "Med gostovanjem lahko nastanejo dodatni stroški"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-sq/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-sq/strings.xml
deleted file mode 100644
index 37f6ad2868806..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-sq/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Ndarja e internetit nuk ka internet"
- "Pajisjet nuk mund të lidhen"
- "Çaktivizo ndarjen e internetit"
- "Zona e qasjes për internet ose ndarja e internetit është aktive"
- "Mund të zbatohen tarifime shtesë kur je në roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-sr/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-sr/strings.xml
deleted file mode 100644
index 5566d03ed13a6..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-sr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Привезивање нема приступ интернету"
- "Повезивање уређаја није успело"
- "Искључи привезивање"
- "Укључен је хотспот или привезивање"
- "Можда важе додатни трошкови у ромингу"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-sv/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-sv/strings.xml
deleted file mode 100644
index 9765acd0cf46f..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-sv/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Det finns ingen internetanslutning för internetdelningen"
- "Enheterna kan inte anslutas"
- "Inaktivera internetdelning"
- "Surfzon eller internetdelning har aktiverats"
- "Ytterligare avgifter kan tillkomma vid roaming"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-sw/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-sw/strings.xml
deleted file mode 100644
index cf850c9cd2227..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-sw/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Kipengele cha kusambaza mtandao hakina intaneti"
- "Imeshindwa kuunganisha vifaa"
- "Zima kipengele cha kusambaza mtandao"
- "Umewasha kipengele cha kusambaza mtandao au mtandao pepe"
- "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ta/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ta/strings.xml
deleted file mode 100644
index f4b15aab19b72..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ta/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை"
- "சாதனங்களால் இணைய முடியவில்லை"
- "இணைப்பு முறையை ஆஃப் செய்"
- "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது"
- "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-te/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-te/strings.xml
deleted file mode 100644
index 937d34d520272..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-te/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు"
- "పరికరాలు కనెక్ట్ అవ్వడం లేదు"
- "టెథరింగ్ను ఆఫ్ చేయండి"
- "హాట్స్పాట్ లేదా టెథరింగ్ ఆన్లో ఉంది"
- "రోమింగ్లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-th/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-th/strings.xml
deleted file mode 100644
index f781fae5252e0..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-th/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต"
- "อุปกรณ์เชื่อมต่อไม่ได้"
- "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ"
- "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่"
- "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-tl/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-tl/strings.xml
deleted file mode 100644
index 8d5d465373342..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-tl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Walang internet ang pag-tether"
- "Hindi makakonekta ang mga device"
- "I-off ang pag-tether"
- "Naka-on ang Hotspot o pag-tether"
- "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-tr/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-tr/strings.xml
deleted file mode 100644
index 80cab33ac05e3..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-tr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering\'in internet bağlantısı yok"
- "Cihazlar bağlanamıyor"
- "Tethering\'i kapat"
- "Hotspot veya tethering açık"
- "Dolaşım sırasında ek ücretler uygulanabilir"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-uk/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-uk/strings.xml
deleted file mode 100644
index c05932a5ae7f9..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-uk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Телефон, який використовується як модем, не підключений до Інтернету"
- "Не вдається підключити пристрої"
- "Вимкнути використання телефона як модема"
- "Увімкнено точку доступу або використання телефона як модема"
- "У роумінгу може стягуватися додаткова плата"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-ur/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-ur/strings.xml
deleted file mode 100644
index d820eee8ba3c1..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-ur/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ٹیدرنگ میں انٹرنیٹ نہیں ہے"
- "آلات منسلک نہیں ہو سکتے"
- "ٹیدرنگ آف کریں"
- "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے"
- "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-uz/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-uz/strings.xml
deleted file mode 100644
index 726148aaee5ad..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-uz/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Modem internetga ulanmagan"
- "Qurilmalar ulanmadi"
- "Modem rejimini faolsizlantirish"
- "Hotspot yoki modem rejimi yoniq"
- "Rouming vaqtida qoʻshimcha haq olinishi mumkin"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-vi/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-vi/strings.xml
deleted file mode 100644
index b7cb0456b673b..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-vi/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Không có Internet để chia sẻ kết Internet"
- "Các thiết bị không thể kết nối"
- "Tắt tính năng chia sẻ Internet"
- "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật"
- "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml
deleted file mode 100644
index af91afff9a4c0..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-zh-rCN/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "共享网络未连接到互联网"
- "设备无法连接"
- "关闭网络共享"
- "热点或网络共享已开启"
- "漫游时可能会产生额外的费用"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml
deleted file mode 100644
index 28e6b80c01a9a..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-zh-rHK/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "無法透過網絡共享連線至互聯網"
- "裝置無法連接"
- "關閉網絡共享"
- "熱點或網絡共享已開啟"
- "漫遊時可能需要支付額外費用"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml
deleted file mode 100644
index 528a1e52925c4..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-zh-rTW/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "無法透過網路共用連上網際網路"
- "裝置無法連線"
- "關閉網路共用"
- "無線基地台或網路共用已開啟"
- "使用漫遊服務可能須支付額外費用"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004-zu/strings.xml b/packages/Tethering/res/values-mcc310-mnc004-zu/strings.xml
deleted file mode 100644
index 11eb66621971f..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004-zu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi"
- "Amadivayisi awakwazi ukuxhumeka"
- "Vala ukusebenzisa ifoni njengemodemu"
- "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe"
- "Kungaba nezinkokhelo ezengeziwe uma uzula"
-
diff --git a/packages/Tethering/res/values-mcc310-mnc004/config.xml b/packages/Tethering/res/values-mcc310-mnc004/config.xml
deleted file mode 100644
index 5c5be0466a36d..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004/config.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
- 5000
-
-
- true
-
\ No newline at end of file
diff --git a/packages/Tethering/res/values-mcc310-mnc004/strings.xml b/packages/Tethering/res/values-mcc310-mnc004/strings.xml
deleted file mode 100644
index ce9ff60807178..0000000000000
--- a/packages/Tethering/res/values-mcc310-mnc004/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
- Tethering has no internet
-
- Devices can\u2019t connect
-
- Turn off tethering
-
-
- Hotspot or tethering is on
-
- Additional charges may apply while roaming
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-af/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-af/strings.xml
deleted file mode 100644
index 9bfa5317a9e43..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-af/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Verbinding het nie internet nie"
- "Toestelle kan nie koppel nie"
- "Skakel verbinding af"
- "Warmkol of verbinding is aan"
- "Bykomende heffings kan geld terwyl jy swerf"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-am/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-am/strings.xml
deleted file mode 100644
index 5949dfa776d78..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-am/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ማስተሳሰር ምንም በይነመረብ የለውም"
- "መሣሪያዎችን ማገናኘት አይቻልም"
- "ማስተሳሰርን አጥፋ"
- "መገናኛ ነጥብ ወይም ማስተሳሰር በርቷል"
- "በሚያንዣብብበት ጊዜ ተጨማሪ ክፍያዎች ተፈጻሚ ሊሆኑ ይችላሉ"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ar/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ar/strings.xml
deleted file mode 100644
index 8467f9b1f5cf3..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ar/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ما مِن اتصال بالإنترنت خلال التوصيل"
- "تعذّر اتصال الأجهزة"
- "إيقاف التوصيل"
- "نقطة الاتصال أو التوصيل مفعّلان"
- "قد يتم تطبيق رسوم إضافية أثناء التجوال."
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-as/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-as/strings.xml
deleted file mode 100644
index 9776bd89da485..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-as/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "টে\'ডাৰিঙৰ ইণ্টাৰনেট নাই"
- "ডিভাইচসমূহ সংযোগ কৰিব নোৱাৰি"
- "টে\'ডাৰিং অফ কৰক"
- "হটস্পট অথবা টে\'ডাৰিং অন আছে"
- "ৰ\'মিঙত থাকিলে অতিৰিক্ত মাচুল প্ৰযোজ্য হ’ব পাৰে"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-az/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-az/strings.xml
deleted file mode 100644
index e6d3eaf9f07c3..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-az/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Modemin internetə girişi yoxdur"
- "Cihazları qoşmaq mümkün deyil"
- "Modemi deaktiv edin"
- "Hotspot və ya modem aktivdir"
- "Rouminq zamanı əlavə ödənişlər tətbiq edilə bilər"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml
deleted file mode 100644
index 4c8a1df8eece5..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-b+sr+Latn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Privezivanje nema pristup internetu"
- "Povezivanje uređaja nije uspelo"
- "Isključi privezivanje"
- "Uključen je hotspot ili privezivanje"
- "Možda važe dodatni troškovi u romingu"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-be/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-be/strings.xml
deleted file mode 100644
index edfa41e1ffd35..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-be/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Рэжым мадэма выкарыстоўваецца без доступу да інтэрнэту"
- "Не ўдалося падключыць прылады"
- "Выключыць рэжым мадэма"
- "Хот-спот або рэжым мадэма ўключаны"
- "Пры выкарыстанні роўмінгу можа спаганяцца дадатковая плата"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-bg/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-bg/strings.xml
deleted file mode 100644
index f56398196f514..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-bg/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Тетърингът няма връзка с интернет"
- "Устройствата не могат да установят връзка"
- "Изключване на тетъринга"
- "Точката за достъп или тетърингът са включени"
- "Възможно е да ви бъдат начислени допълнителни такси при роуминг"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-bn/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-bn/strings.xml
deleted file mode 100644
index d8ecd2e988f9c..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-bn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "টিথারিং করার জন্য কোনও ইন্টারনেট কানেকশন নেই"
- "ডিভাইস কানেক্ট করতে পারছে না"
- "টিথারিং বন্ধ করুন"
- "হটস্পট বা টিথারিং চালু আছে"
- "রোমিংয়ের সময় অতিরিক্ত চার্জ করা হতে পারে"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-bs/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-bs/strings.xml
deleted file mode 100644
index b85fd5e285779..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-bs/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Povezivanje putem mobitela nema internet"
- "Uređaji se ne mogu povezati"
- "Isključi povezivanje putem mobitela"
- "Pristupna tačka ili povezivanje putem mobitela je uključeno"
- "Mogu nastati dodatni troškovi u romingu"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ca/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ca/strings.xml
deleted file mode 100644
index a3572151be6bd..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ca/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "La compartició de xarxa no té accés a Internet"
- "No es poden connectar els dispositius"
- "Desactiva la compartició de xarxa"
- "S\'ha activat el punt d\'accés Wi‑Fi o la compartició de xarxa"
- "És possible que s\'apliquin costos addicionals en itinerància"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-cs/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-cs/strings.xml
deleted file mode 100644
index 91196be9e5571..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-cs/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering nemá připojení k internetu"
- "Zařízení se nemůžou připojit"
- "Vypnout tethering"
- "Je zapnutý hotspot nebo tethering"
- "Při roamingu mohou být účtovány dodatečné poplatky"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-da/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-da/strings.xml
deleted file mode 100644
index 196890011d503..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-da/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Netdeling har ingen internetforbindelse"
- "Enheder kan ikke oprette forbindelse"
- "Deaktiver netdeling"
- "Hotspot eller netdeling er aktiveret"
- "Der opkræves muligvis yderligere gebyrer ved roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-de/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-de/strings.xml
deleted file mode 100644
index eb3f8c52c0c5d..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-de/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering hat keinen Internetzugriff"
- "Geräte können sich nicht verbinden"
- "Tethering deaktivieren"
- "Hotspot oder Tethering ist aktiviert"
- "Für das Roaming können zusätzliche Gebühren anfallen"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-el/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-el/strings.xml
deleted file mode 100644
index 56c3d81b634e7..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-el/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Η σύνδεση δεν έχει πρόσβαση στο διαδίκτυο"
- "Δεν είναι δυνατή η σύνδεση των συσκευών"
- "Απενεργοποιήστε τη σύνδεση"
- "Ενεργό σημείο πρόσβασης Wi-Fi ή ενεργή σύνδεση"
- "Ενδέχεται να ισχύουν επιπλέον χρεώσεις κατά την περιαγωγή."
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml
deleted file mode 100644
index dd1a1971cdd8c..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-en-rAU/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering has no Internet"
- "Devices can’t connect"
- "Turn off tethering"
- "Hotspot or tethering is on"
- "Additional charges may apply while roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml
deleted file mode 100644
index dd1a1971cdd8c..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-en-rCA/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering has no Internet"
- "Devices can’t connect"
- "Turn off tethering"
- "Hotspot or tethering is on"
- "Additional charges may apply while roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml
deleted file mode 100644
index dd1a1971cdd8c..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-en-rGB/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering has no Internet"
- "Devices can’t connect"
- "Turn off tethering"
- "Hotspot or tethering is on"
- "Additional charges may apply while roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml
deleted file mode 100644
index dd1a1971cdd8c..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-en-rIN/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering has no Internet"
- "Devices can’t connect"
- "Turn off tethering"
- "Hotspot or tethering is on"
- "Additional charges may apply while roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml
deleted file mode 100644
index d3347aae207d3..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-en-rXC/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering has no internet"
- "Devices can’t connect"
- "Turn off tethering"
- "Hotspot or tethering is on"
- "Additional charges may apply while roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml
deleted file mode 100644
index 2f0504f07de78..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-es-rUS/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "La conexión mediante dispositivo móvil no tiene Internet"
- "No se pueden conectar los dispositivos"
- "Desactivar conexión mediante dispositivo móvil"
- "Se activó el hotspot o la conexión mediante dispositivo móvil"
- "Es posible que se apliquen cargos adicionales por roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-es/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-es/strings.xml
deleted file mode 100644
index 2d8f88242502a..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-es/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "La conexión no se puede compartir, porque no hay acceso a Internet"
- "Los dispositivos no se pueden conectar"
- "Desactivar conexión compartida"
- "Punto de acceso o conexión compartida activados"
- "Puede que se apliquen cargos adicionales en itinerancia"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-et/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-et/strings.xml
deleted file mode 100644
index 8493c470710d8..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-et/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Jagamisel puudub internetiühendus"
- "Seadmed ei saa ühendust luua"
- "Lülita jagamine välja"
- "Kuumkoht või jagamine on sisse lülitatud"
- "Rändluse kasutamisega võivad kaasneda lisatasud"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-eu/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-eu/strings.xml
deleted file mode 100644
index 33bccab3e88c5..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-eu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Konexioa partekatzeko aukerak ez du Interneteko konexiorik"
- "Ezin dira konektatu gailuak"
- "Desaktibatu konexioa partekatzeko aukera"
- "Wifi-gunea edo konexioa partekatzeko aukera aktibatuta dago"
- "Baliteke kostu gehigarriak ordaindu behar izatea ibiltaritzan"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-fa/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-fa/strings.xml
deleted file mode 100644
index cf8a0cc277055..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-fa/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "«اشتراکگذاری اینترنت» به اینترنت دسترسی ندارد"
- "دستگاهها متصل نمیشوند"
- "خاموش کردن «اشتراکگذاری اینترنت»"
- "«نقطه اتصال» یا «اشتراکگذاری اینترنت» روشن است"
- "ممکن است درحین فراگردی تغییرات دیگر اعمال شود"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-fi/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-fi/strings.xml
deleted file mode 100644
index 6a3ab806db988..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-fi/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Ei jaettavaa internetyhteyttä"
- "Laitteet eivät voi muodostaa yhteyttä"
- "Laita yhteyden jakaminen pois päältä"
- "Hotspot tai yhteyden jakaminen on päällä"
- "Roaming voi aiheuttaa lisämaksuja"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml
deleted file mode 100644
index ffb9bf60472e6..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-fr-rCA/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Le partage de connexion n\'est pas connecté à Internet"
- "Impossible de connecter les appareils"
- "Désactiver le partage de connexion"
- "Le point d\'accès ou le partage de connexion est activé"
- "En itinérance, des frais supplémentaires peuvent s\'appliquer"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-fr/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-fr/strings.xml
deleted file mode 100644
index 768bce3f0ab1b..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-fr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Aucune connexion à Internet n\'est disponible pour le partage de connexion"
- "Impossible de connecter les appareils"
- "Désactiver le partage de connexion"
- "Le point d\'accès ou le partage de connexion est activé"
- "En itinérance, des frais supplémentaires peuvent s\'appliquer"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-gl/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-gl/strings.xml
deleted file mode 100644
index 0c4195a7caf37..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-gl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "A conexión compartida non ten Internet"
- "Non se puideron conectar os dispositivos"
- "Desactivar conexión compartida"
- "Está activada a zona wifi ou a conexión compartida"
- "Pódense aplicar cargos adicionais en itinerancia"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-gu/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-gu/strings.xml
deleted file mode 100644
index e9d33a7db2599..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-gu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ઇન્ટરનેટ શેર કરવાની સુવિધામાં ઇન્ટરનેટ નથી"
- "ડિવાઇસ કનેક્ટ કરી શકાતા નથી"
- "ઇન્ટરનેટ શેર કરવાની સુવિધા બંધ કરો"
- "હૉટસ્પૉટ અથવા ઇન્ટરનેટ શેર કરવાની સુવિધા ચાલુ છે"
- "રોમિંગમાં વધારાના શુલ્ક લાગી શકે છે"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-hi/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-hi/strings.xml
deleted file mode 100644
index aa418ac5d3bbd..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-hi/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "टेदरिंग से इंटरनेट नहीं चल रहा"
- "डिवाइस कनेक्ट नहीं हो पा रहे"
- "टेदरिंग बंद करें"
- "हॉटस्पॉट या टेदरिंग चालू है"
- "रोमिंग के दौरान अतिरिक्त शुल्क लग सकता है"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-hr/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-hr/strings.xml
deleted file mode 100644
index 51c524afbc53f..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-hr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Modemsko povezivanje nema internet"
- "Uređaji se ne mogu povezati"
- "Isključivanje modemskog povezivanja"
- "Uključena je žarišna točka ili modemsko povezivanje"
- "U roamingu su mogući dodatni troškovi"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-hu/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-hu/strings.xml
deleted file mode 100644
index 164e45edd1420..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-hu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Nincs internetkapcsolat az internet megosztásához"
- "Az eszközök nem tudnak csatlakozni"
- "Internetmegosztás kikapcsolása"
- "A hotspot vagy az internetmegosztás be van kapcsolva"
- "Roaming során további díjak léphetnek fel"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-hy/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-hy/strings.xml
deleted file mode 100644
index e76c0a4c80d55..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-hy/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Մոդեմի ռեժիմի կապը բացակայում է"
- "Չհաջողվեց միացնել սարքը"
- "Անջատել մոդեմի ռեժիմը"
- "Թեժ կետը կամ մոդեմի ռեժիմը միացված է"
- "Ռոումինգում կարող են լրացուցիչ վճարներ գանձվել"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-in/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-in/strings.xml
deleted file mode 100644
index 2b817f8abd175..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-in/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tidak ada koneksi internet di tethering"
- "Perangkat tidak dapat terhubung"
- "Nonaktifkan tethering"
- "Hotspot atau tethering aktif"
- "Biaya tambahan mungkin berlaku saat roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-is/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-is/strings.xml
deleted file mode 100644
index a338d9c7cab87..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-is/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tjóðrun er ekki með internettengingu"
- "Tæki geta ekki tengst"
- "Slökkva á tjóðrun"
- "Kveikt er á heitum reit eða tjóðrun"
- "Viðbótargjöld kunna að eiga við í reiki"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-it/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-it/strings.xml
deleted file mode 100644
index 77769c2ac56ce..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-it/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Nessuna connessione a Internet per il tethering"
- "Impossibile connettere i dispositivi"
- "Disattiva il tethering"
- "Hotspot o tethering attivi"
- "Potrebbero essere applicati costi aggiuntivi durante il roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-iw/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-iw/strings.xml
deleted file mode 100644
index 5267b5126435f..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-iw/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "אי אפשר להפעיל את תכונת שיתוף האינטרנט בין מכשירים כי אין חיבור לאינטרנט"
- "למכשירים אין אפשרות להתחבר"
- "השבתה של שיתוף האינטרנט בין מכשירים"
- "תכונת הנקודה לשיתוף אינטרנט או תכונת שיתוף האינטרנט בין מכשירים פועלת"
- "ייתכנו חיובים נוספים בעת נדידה"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ja/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ja/strings.xml
deleted file mode 100644
index 66a9a6dd35c20..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ja/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "テザリングがインターネットに接続されていません"
- "デバイスを接続できません"
- "テザリングを OFF にする"
- "アクセス ポイントまたはテザリングが ON です"
- "ローミング時に追加料金が発生することがあります"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ka/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ka/strings.xml
deleted file mode 100644
index d8ad8808498f0..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ka/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ტეტერინგს არ აქვს ინტერნეტზე წვდომა"
- "მოწყობილობები ვერ ახერხებენ დაკავშირებას"
- "ტეტერინგის გამორთვა"
- "ჩართულია უსადენო ქსელი ან ტეტერინგი"
- "როუმინგის გამოყენებისას შეიძლება ჩამოგეჭრათ დამატებითი საფასური"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-kk/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-kk/strings.xml
deleted file mode 100644
index 1ddd6b419b570..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-kk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Тетеринг режимі интернет байланысынсыз пайдаланылуда"
- "Құрылғыларды байланыстыру мүмкін емес"
- "Тетерингіні өшіру"
- "Хотспот немесе тетеринг қосулы"
- "Роуминг кезінде қосымша ақы алынуы мүмкін."
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-km/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-km/strings.xml
deleted file mode 100644
index cf5a1379ccc7d..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-km/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ការភ្ជាប់មិនមានអ៊ីនធឺណិតទេ"
- "មិនអាចភ្ជាប់ឧបករណ៍បានទេ"
- "បិទការភ្ជាប់"
- "ហតស្ប៉ត ឬការភ្ជាប់ត្រូវបានបើក"
- "អាចមានការគិតថ្លៃបន្ថែម នៅពេលរ៉ូមីង"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-kn/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-kn/strings.xml
deleted file mode 100644
index 68ae68bc19987..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-kn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ಟೆಥರಿಂಗ್ ಯಾವುದೇ ಇಂಟರ್ನೆಟ್ ಕನೆಕ್ಷನ್ ಹೊಂದಿಲ್ಲ"
- "ಸಾಧನಗಳನ್ನು ಕನೆಕ್ಟ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"
- "ಟೆಥರಿಂಗ್ ಆಫ್ ಮಾಡಿ"
- "ಹಾಟ್ಸ್ಪಾಟ್ ಅಥವಾ ಟೆಥರಿಂಗ್ ಆನ್ ಆಗಿದೆ"
- "ರೋಮಿಂಗ್ನಲ್ಲಿರುವಾಗ ಹೆಚ್ಚುವರಿ ಶುಲ್ಕಗಳು ಅನ್ವಯವಾಗಬಹುದು"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ko/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ko/strings.xml
deleted file mode 100644
index 17185ba2d063d..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ko/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "테더링으로 인터넷을 사용할 수 없음"
- "기기에서 연결할 수 없음"
- "테더링 사용 중지"
- "핫스팟 또는 테더링 켜짐"
- "로밍 중에는 추가 요금이 발생할 수 있습니다."
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ky/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ky/strings.xml
deleted file mode 100644
index 6a9fb9810cc68..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ky/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Модем режими Интернети жок колдонулууда"
- "Түзмөктөр туташпай жатат"
- "Модем режимин өчүрүү"
- "Байланыш түйүнү же модем режими күйүк"
- "Роумингде кошумча акы алынышы мүмкүн"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-lo/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-lo/strings.xml
deleted file mode 100644
index bcc4b5762678f..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-lo/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ການປ່ອຍສັນຍານບໍ່ມີອິນເຕີເນັດ"
- "ອຸປະກອນບໍ່ສາມາດເຊື່ອມຕໍ່ໄດ້"
- "ປິດການປ່ອຍສັນຍານ"
- "ເປີດໃຊ້ຮັອດສະປອດ ຫຼື ການປ່ອຍສັນຍານຢູ່"
- "ອາດມີຄ່າໃຊ້ຈ່າຍເພີ່ມເຕີມໃນລະຫວ່າງການໂຣມມິງ"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-lt/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-lt/strings.xml
deleted file mode 100644
index 011c2c11fb888..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-lt/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Nėra įrenginio kaip modemo naudojimo interneto ryšio"
- "Nepavyko susieti įrenginių"
- "Išjungti įrenginio kaip modemo naudojimą"
- "Įjungtas viešosios interneto prieigos taškas arba įrenginio kaip modemo naudojimas"
- "Veikiant tarptinkliniam ryšiui gali būti taikomi papildomi mokesčiai"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-lv/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-lv/strings.xml
deleted file mode 100644
index 5cb2f3b7aac86..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-lv/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Piesaistei nav interneta savienojuma"
- "Nevar savienot ierīces"
- "Izslēgt piesaisti"
- "Ir ieslēgts tīklājs vai piesaiste"
- "Viesabonēšanas laikā var tikt piemērota papildu samaksa"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-mk/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-mk/strings.xml
deleted file mode 100644
index 4cbfd887c57e4..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-mk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Нема интернет преку мобилен"
- "Уредите не може да се поврзат"
- "Исклучи интернет преку мобилен"
- "Точката на пристап или интернетот преку мобилен е вклучен"
- "При роаминг може да се наплатат дополнителни трошоци"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ml/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ml/strings.xml
deleted file mode 100644
index 9cf4eaf34a97e..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ml/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ടെതറിംഗിന് ഇന്റർനെറ്റ് ഇല്ല"
- "ഉപകരണങ്ങൾ കണക്റ്റ് ചെയ്യാനാവില്ല"
- "ടെതറിംഗ് ഓഫാക്കുക"
- "ഹോട്ട്സ്പോട്ട് അല്ലെങ്കിൽ ടെതറിംഗ് ഓണാണ്"
- "റോമിംഗ് ചെയ്യുമ്പോൾ അധിക നിരക്കുകൾ ബാധകമായേക്കാം"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-mn/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-mn/strings.xml
deleted file mode 100644
index 47c82c14d9d65..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-mn/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Модемд интернэт алга байна"
- "Төхөөрөмжүүд холбогдох боломжгүй байна"
- "Модем болгохыг унтраах"
- "Сүлжээний цэг эсвэл модем болгох асаалттай байна"
- "Роумингийн үеэр нэмэлт төлбөр нэхэмжилж болзошгүй"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-mr/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-mr/strings.xml
deleted file mode 100644
index ad9e809ab27df..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-mr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "टेदरिंगला इंटरनेट नाही"
- "डिव्हाइस कनेक्ट होऊ शकत नाहीत"
- "टेदरिंग बंद करा"
- "हॉटस्पॉट किंवा टेदरिंग सुरू आहे"
- "रोमिंगदरम्यान अतिरिक्त शुल्क लागू होऊ शकतात"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ms/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ms/strings.xml
deleted file mode 100644
index e708cb8717b3c..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ms/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Penambatan tiada Internet"
- "Peranti tidak dapat disambungkan"
- "Matikan penambatan"
- "Tempat liputan atau penambatan dihidupkan"
- "Caj tambahan mungkin digunakan semasa perayauan"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-my/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-my/strings.xml
deleted file mode 100644
index ba5462250b054..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-my/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းတွင် အင်တာနက် မရှိပါ"
- "စက်များ ချိတ်ဆက်၍ မရပါ"
- "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ပိတ်ရန်"
- "ဟော့စပေါ့ (သို့) မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း ဖွင့်ထားသည်"
- "ပြင်ပကွန်ရက်နှင့် ချိတ်ဆက်သည့်အခါ နောက်ထပ်ကျသင့်မှုများ ရှိနိုင်သည်"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-nb/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-nb/strings.xml
deleted file mode 100644
index 57db484a2543c..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-nb/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Internettdeling har ikke internettilgang"
- "Enhetene kan ikke koble til"
- "Slå av internettdeling"
- "Wi-Fi-sone eller internettdeling er på"
- "Ytterligere kostnader kan påløpe under roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ne/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ne/strings.xml
deleted file mode 100644
index 1503244f50001..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ne/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "टेदरिङमार्फत इन्टरनेट कनेक्सन प्राप्त हुन सकेन"
- "यन्त्रहरू कनेक्ट गर्न सकिएन"
- "टेदरिङ निष्क्रिय पार्नुहोस्"
- "हटस्पट वा टेदरिङ सक्रिय छ"
- "रोमिङ सेवा प्रयोग गर्दा अतिरिक्त शुल्क लाग्न सक्छ"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-nl/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-nl/strings.xml
deleted file mode 100644
index b08133f4e592a..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-nl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering heeft geen internet"
- "Apparaten kunnen niet worden verbonden"
- "Tethering uitschakelen"
- "Hotspot of tethering is ingeschakeld"
- "Er kunnen extra kosten voor roaming in rekening worden gebracht."
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-or/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-or/strings.xml
deleted file mode 100644
index 1ad4ca354ad52..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-or/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ଟିଥରିଂ ପାଇଁ କୌଣସି ଇଣ୍ଟର୍ନେଟ୍ ସଂଯୋଗ ନାହିଁ"
- "ଡିଭାଇସଗୁଡ଼ିକ ସଂଯୋଗ କରାଯାଇପାରିବ ନାହିଁ"
- "ଟିଥରିଂ ବନ୍ଦ କରନ୍ତୁ"
- "ହଟସ୍ପଟ୍ କିମ୍ବା ଟିଥରିଂ ଚାଲୁ ଅଛି"
- "ରୋମିଂରେ ଥିବା ସମୟରେ ଅତିରିକ୍ତ ଶୁଳ୍କ ଲାଗୁ ହୋଇପାରେ"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-pa/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-pa/strings.xml
deleted file mode 100644
index 88def563d85af..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-pa/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ਟੈਦਰਿੰਗ ਕੋਲ ਇੰਟਰਨੈੱਟ ਪਹੁੰਚ ਨਹੀਂ ਹੈ"
- "ਡੀਵਾਈਸ ਕਨੈਕਟ ਨਹੀਂ ਕੀਤੇ ਜਾ ਸਕਦੇ"
- "ਟੈਦਰਿੰਗ ਬੰਦ ਕਰੋ"
- "ਹੌਟਸਪੌਟ ਜਾਂ ਟੈਦਰਿੰਗ ਚਾਲੂ ਹੈ"
- "ਰੋਮਿੰਗ ਦੌਰਾਨ ਵਧੀਕ ਖਰਚੇ ਲਾਗੂ ਹੋ ਸਕਦੇ ਹਨ"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-pl/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-pl/strings.xml
deleted file mode 100644
index f9890abdc26b9..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-pl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering nie ma internetu"
- "Urządzenia nie mogą się połączyć"
- "Wyłącz tethering"
- "Hotspot lub tethering jest włączony"
- "Podczas korzystania z roamingu mogą zostać naliczone dodatkowe opłaty"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml
deleted file mode 100644
index ce3b88479f098..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-pt-rBR/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "O tethering não tem Internet"
- "Não é possível conectar os dispositivos"
- "Desativar o tethering"
- "Ponto de acesso ou tethering ativado"
- "Pode haver cobranças extras durante o roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml
deleted file mode 100644
index 7e883ea576826..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-pt-rPT/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "A ligação (à Internet) via telemóvel não tem Internet"
- "Não é possível ligar os dispositivos"
- "Desativar ligação (à Internet) via telemóvel"
- "A zona Wi-Fi ou a ligação (à Internet) via telemóvel está ativada"
- "Podem aplicar-se custos adicionais em roaming."
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-pt/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-pt/strings.xml
deleted file mode 100644
index ce3b88479f098..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-pt/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "O tethering não tem Internet"
- "Não é possível conectar os dispositivos"
- "Desativar o tethering"
- "Ponto de acesso ou tethering ativado"
- "Pode haver cobranças extras durante o roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ro/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ro/strings.xml
deleted file mode 100644
index 1009417316ede..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ro/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Procesul de tethering nu are internet"
- "Dispozitivele nu se pot conecta"
- "Dezactivați procesul de tethering"
- "S-a activat hotspotul sau tethering"
- "Se pot aplica taxe suplimentare pentru roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ru/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ru/strings.xml
deleted file mode 100644
index 88683bed95b84..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ru/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Режим модема используется без доступа к Интернету"
- "Невозможно подключить устройства."
- "Отключить режим модема"
- "Включены точка доступа или режим модема"
- "За использование услуг связи в роуминге может взиматься дополнительная плата."
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-si/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-si/strings.xml
deleted file mode 100644
index 176bcdb797c63..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-si/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ටෙදරින් හට අන්තර්ජාලය නැත"
- "උපාංගවලට සම්බන්ධ විය නොහැකිය"
- "ටෙදරින් ක්රියාවිරහිත කරන්න"
- "හොට්ස්පොට් හෝ ටෙදරින් ක්රියාත්මකයි"
- "රෝමිං අතරතුර අමතර ගාස්තු අදාළ විය හැකිය"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-sk/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-sk/strings.xml
deleted file mode 100644
index b9e2127fa879d..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-sk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering nemá internetové pripojenie"
- "Zariadenia sa nemôžu pripojiť"
- "Vypnúť tethering"
- "Je zapnutý hotspot alebo tethering"
- "Počas roamingu vám môžu byť účtované ďalšie poplatky"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-sl/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-sl/strings.xml
deleted file mode 100644
index e8140e686a0c9..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-sl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Internetna povezava prek mobilnega telefona ni vzpostavljena"
- "Napravi se ne moreta povezati"
- "Izklopi internetno povezavo prek mobilnega telefona"
- "Dostopna točka ali internetna povezava prek mobilnega telefona je vklopljena"
- "Med gostovanjem lahko nastanejo dodatni stroški"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-sq/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-sq/strings.xml
deleted file mode 100644
index 61e698d6e8ab3..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-sq/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Ndarja e internetit nuk ka internet"
- "Pajisjet nuk mund të lidhen"
- "Çaktivizo ndarjen e internetit"
- "Zona e qasjes për internet ose ndarja e internetit është aktive"
- "Mund të zbatohen tarifime shtesë kur je në roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-sr/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-sr/strings.xml
deleted file mode 100644
index b4c411c35475c..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-sr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Привезивање нема приступ интернету"
- "Повезивање уређаја није успело"
- "Искључи привезивање"
- "Укључен је хотспот или привезивање"
- "Можда важе додатни трошкови у ромингу"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-sv/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-sv/strings.xml
deleted file mode 100644
index 4f543e47b9985..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-sv/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Det finns ingen internetanslutning för internetdelningen"
- "Enheterna kan inte anslutas"
- "Inaktivera internetdelning"
- "Surfzon eller internetdelning har aktiverats"
- "Ytterligare avgifter kan tillkomma vid roaming"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-sw/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-sw/strings.xml
deleted file mode 100644
index ac347ab485e0e..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-sw/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Kipengele cha kusambaza mtandao hakina intaneti"
- "Imeshindwa kuunganisha vifaa"
- "Zima kipengele cha kusambaza mtandao"
- "Umewasha kipengele cha kusambaza mtandao au mtandao pepe"
- "Huenda ukatozwa gharama za ziada ukitumia mitandao ya ng\'ambo"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ta/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ta/strings.xml
deleted file mode 100644
index 2ea2467e58797..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ta/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "இணைப்பு முறைக்கு இணைய இணைப்பு இல்லை"
- "சாதனங்களால் இணைய முடியவில்லை"
- "இணைப்பு முறையை ஆஃப் செய்"
- "ஹாட்ஸ்பாட் அல்லது இணைப்பு முறை ஆன் செய்யப்பட்டுள்ளது"
- "ரோமிங்கின்போது கூடுதல் கட்டணங்கள் விதிக்கப்படக்கூடும்"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-te/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-te/strings.xml
deleted file mode 100644
index 9360297dd8078..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-te/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "టెథరింగ్ చేయడానికి ఇంటర్నెట్ కనెక్షన్ లేదు"
- "పరికరాలు కనెక్ట్ అవ్వడం లేదు"
- "టెథరింగ్ను ఆఫ్ చేయండి"
- "హాట్స్పాట్ లేదా టెథరింగ్ ఆన్లో ఉంది"
- "రోమింగ్లో ఉన్నప్పుడు అదనపు ఛార్జీలు వర్తించవచ్చు"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-th/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-th/strings.xml
deleted file mode 100644
index 9c4d7e08f2b60..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-th/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือไม่มีอินเทอร์เน็ต"
- "อุปกรณ์เชื่อมต่อไม่ได้"
- "ปิดการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ"
- "ฮอตสปอตหรือการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือเปิดอยู่"
- "อาจมีค่าใช้จ่ายเพิ่มเติมขณะโรมมิ่ง"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-tl/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-tl/strings.xml
deleted file mode 100644
index a7c78a5932676..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-tl/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Walang internet ang pag-tether"
- "Hindi makakonekta ang mga device"
- "I-off ang pag-tether"
- "Naka-on ang Hotspot o pag-tether"
- "Posibleng magkaroon ng mga karagdagang singil habang nagro-roam"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-tr/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-tr/strings.xml
deleted file mode 100644
index 93da2c3f79817..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-tr/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Tethering\'in internet bağlantısı yok"
- "Cihazlar bağlanamıyor"
- "Tethering\'i kapat"
- "Hotspot veya tethering açık"
- "Dolaşım sırasında ek ücretler uygulanabilir"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-uk/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-uk/strings.xml
deleted file mode 100644
index ee0dcd2c4b6aa..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-uk/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Телефон, який використовується як модем, не підключений до Інтернету"
- "Не вдається підключити пристрої"
- "Вимкнути використання телефона як модема"
- "Увімкнено точку доступу або використання телефона як модема"
- "У роумінгу може стягуватися додаткова плата"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-ur/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-ur/strings.xml
deleted file mode 100644
index 41cd28eef9bd5..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-ur/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "ٹیدرنگ میں انٹرنیٹ نہیں ہے"
- "آلات منسلک نہیں ہو سکتے"
- "ٹیدرنگ آف کریں"
- "ہاٹ اسپاٹ یا ٹیدرنگ آن ہے"
- "رومنگ کے دوران اضافی چارجز لاگو ہو سکتے ہیں"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-uz/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-uz/strings.xml
deleted file mode 100644
index c847bc943bd4c..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-uz/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Modem internetga ulanmagan"
- "Qurilmalar ulanmadi"
- "Modem rejimini faolsizlantirish"
- "Hotspot yoki modem rejimi yoniq"
- "Rouming vaqtida qoʻshimcha haq olinishi mumkin"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-vi/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-vi/strings.xml
deleted file mode 100644
index a74326f09ec5a..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-vi/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Không có Internet để chia sẻ kết Internet"
- "Các thiết bị không thể kết nối"
- "Tắt tính năng chia sẻ Internet"
- "Điểm phát sóng hoặc tính năng chia sẻ Internet đang bật"
- "Bạn có thể mất thêm phí dữ liệu khi chuyển vùng"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml
deleted file mode 100644
index d7370036e351f..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-zh-rCN/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "共享网络未连接到互联网"
- "设备无法连接"
- "关闭网络共享"
- "热点或网络共享已开启"
- "漫游时可能会产生额外的费用"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml
deleted file mode 100644
index f378a9dc2cfb5..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-zh-rHK/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "無法透過網絡共享連線至互聯網"
- "裝置無法連接"
- "關閉網絡共享"
- "熱點或網絡共享已開啟"
- "漫遊時可能需要支付額外費用"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml
deleted file mode 100644
index cd653df1dac6a..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-zh-rTW/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "無法透過網路共用連上網際網路"
- "裝置無法連線"
- "關閉網路共用"
- "無線基地台或網路共用已開啟"
- "使用漫遊服務可能須支付額外費用"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480-zu/strings.xml b/packages/Tethering/res/values-mcc311-mnc480-zu/strings.xml
deleted file mode 100644
index 32f6df56f1543..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480-zu/strings.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
- "Ukusebenzisa ifoni njengemodemu akunayo i-inthanethi"
- "Amadivayisi awakwazi ukuxhumeka"
- "Vala ukusebenzisa ifoni njengemodemu"
- "I-hotspot noma ukusebenzisa ifoni njengemodemu kuvuliwe"
- "Kungaba nezinkokhelo ezengeziwe uma uzula"
-
diff --git a/packages/Tethering/res/values-mcc311-mnc480/config.xml b/packages/Tethering/res/values-mcc311-mnc480/config.xml
deleted file mode 100644
index 5c5be0466a36d..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480/config.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-
-
-
-
- 5000
-
-
- true
-
\ No newline at end of file
diff --git a/packages/Tethering/res/values-mcc311-mnc480/strings.xml b/packages/Tethering/res/values-mcc311-mnc480/strings.xml
deleted file mode 100644
index ce9ff60807178..0000000000000
--- a/packages/Tethering/res/values-mcc311-mnc480/strings.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
- Tethering has no internet
-
- Devices can\u2019t connect
-
- Turn off tethering
-
-
- Hotspot or tethering is on
-
- Additional charges may apply while roaming
-
diff --git a/packages/Tethering/res/values-mk/strings.xml b/packages/Tethering/res/values-mk/strings.xml
deleted file mode 100644
index 9ad9b9a58935a..0000000000000
--- a/packages/Tethering/res/values-mk/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Активно е врзување или точка на пристап"
- "Допрете за поставување."
- "Врзувањето е оневозможено"
- "Контактирајте со администраторот за детали"
- "Статус на точката на пристап и врзувањето"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ml/strings.xml b/packages/Tethering/res/values-ml/strings.xml
deleted file mode 100644
index 9db79ce220a40..0000000000000
--- a/packages/Tethering/res/values-ml/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "ടെതറിംഗ് അല്ലെങ്കിൽ ഹോട്ട്സ്പോട്ട് സജീവമാണ്"
- "സജ്ജീകരിക്കാൻ ടാപ്പ് ചെയ്യുക."
- "ടെതറിംഗ് പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു"
- "വിശദാംശങ്ങൾക്ക് നിങ്ങളുടെ അഡ്മിനെ ബന്ധപ്പെടുക"
- "ഹോട്ട്സ്പോട്ടിന്റെയും ടെതറിംഗിന്റെയും നില"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-mn/strings.xml b/packages/Tethering/res/values-mn/strings.xml
deleted file mode 100644
index 42d1edbaceb90..0000000000000
--- a/packages/Tethering/res/values-mn/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Модем болгох эсвэл сүлжээний цэг идэвхтэй байна"
- "Тохируулахын тулд товшино уу."
- "Модем болгохыг идэвхгүй болгосон"
- "Дэлгэрэнгүй мэдээлэл авахын тулд админтайгаа холбогдоно уу"
- "Сүлжээний цэг болон модем болгох төлөв"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-mr/strings.xml b/packages/Tethering/res/values-mr/strings.xml
deleted file mode 100644
index 13995b6b8aa5b..0000000000000
--- a/packages/Tethering/res/values-mr/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "टेदरिंग किंवा हॉटस्पॉट अॅक्टिव्ह आहे"
- "सेट करण्यासाठी टॅप करा."
- "टेदरिंग बंद केले आहे"
- "तपशीलांसाठी तुमच्या ॲडमिनशी संपर्क साधा"
- "हॉटस्पॉट आणि टेदरिंगची स्थिती"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ms/strings.xml b/packages/Tethering/res/values-ms/strings.xml
deleted file mode 100644
index d6a67f37b1dea..0000000000000
--- a/packages/Tethering/res/values-ms/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Penambatan atau tempat liputan aktif"
- "Ketik untuk membuat persediaan."
- "Penambatan dilumpuhkan"
- "Hubungi pentadbir anda untuk mendapatkan maklumat lanjut"
- "Status tempat liputan & penambatan"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-my/strings.xml b/packages/Tethering/res/values-my/strings.xml
deleted file mode 100644
index 49f6b88a75148..0000000000000
--- a/packages/Tethering/res/values-my/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း သို့မဟုတ် ဟော့စပေါ့ ဖွင့်ထားသည်"
- "စနစ်ထည့်သွင်းရန် တို့ပါ။"
- "မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်းကို ပိတ်ထားသည်"
- "အသေးစိတ်အတွက် သင့်စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ"
- "ဟော့စပေါ့နှင့် မိုဘိုင်းဖုန်းသုံး ချိတ်ဆက်မျှဝေခြင်း အခြေအနေ"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-nb/strings.xml b/packages/Tethering/res/values-nb/strings.xml
deleted file mode 100644
index 9594e0a70a698..0000000000000
--- a/packages/Tethering/res/values-nb/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Internettdeling eller Wi-Fi-sone er aktiv"
- "Trykk for å konfigurere."
- "Internettdeling er slått av"
- "Ta kontakt med administratoren din for å få mer informasjon"
- "Status for Wi-Fi-sone og internettdeling"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ne/strings.xml b/packages/Tethering/res/values-ne/strings.xml
deleted file mode 100644
index 72ae3a80a9281..0000000000000
--- a/packages/Tethering/res/values-ne/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "टेदरिङ वा हटस्पट सक्रिय छ"
- "सेटअप गर्न ट्याप गर्नुहोस्।"
- "टेदरिङ सुविधा असक्षम पारिएको छ"
- "विवरणहरूका लागि आफ्ना प्रशासकलाई सम्पर्क गर्नुहोस्"
- "हटस्पट तथा टेदरिङको स्थिति"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-nl/strings.xml b/packages/Tethering/res/values-nl/strings.xml
deleted file mode 100644
index 18b2bbfc76703..0000000000000
--- a/packages/Tethering/res/values-nl/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tethering of hotspot actief"
- "Tik om in te stellen."
- "Tethering is uitgeschakeld"
- "Neem contact op met je beheerder voor meer informatie"
- "Status van hotspot en tethering"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-or/strings.xml b/packages/Tethering/res/values-or/strings.xml
deleted file mode 100644
index a15a6db42af68..0000000000000
--- a/packages/Tethering/res/values-or/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "ଟିଥେରିଂ କିମ୍ୱା ହଟସ୍ପଟ୍ ସକ୍ରିୟ ଅଛି"
- "ସେଟ୍ ଅପ୍ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ।"
- "ଟିଥେରିଂ ଅକ୍ଷମ କରାଯାଇଛି"
- "ବିବରଣୀଗୁଡ଼ିକ ପାଇଁ ଆପଣଙ୍କ ଆଡମିନଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ"
- "ହଟସ୍ପଟ୍ ଓ ଟିଥେରିଂ ସ୍ଥିତି"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-pa/strings.xml b/packages/Tethering/res/values-pa/strings.xml
deleted file mode 100644
index a8235e423e479..0000000000000
--- a/packages/Tethering/res/values-pa/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "ਟੈਦਰਿੰਗ ਜਾਂ ਹੌਟਸਪੌਟ ਕਿਰਿਆਸ਼ੀਲ"
- "ਸੈੱਟਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ।"
- "ਟੈਦਰਿੰਗ ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ ਹੈ"
- "ਵੇਰਵਿਆਂ ਲਈ ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ"
- "ਹੌਟਸਪੌਟ ਅਤੇ ਟੈਦਰਿੰਗ ਦੀ ਸਥਿਤੀ"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-pl/strings.xml b/packages/Tethering/res/values-pl/strings.xml
deleted file mode 100644
index ccb017d43fa8a..0000000000000
--- a/packages/Tethering/res/values-pl/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Aktywny tethering lub punkt dostępu"
- "Kliknij, by skonfigurować"
- "Tethering został wyłączony"
- "Aby uzyskać szczegółowe informacje, skontaktuj się z administratorem"
- "Hotspot i tethering – stan"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-pt-rBR/strings.xml b/packages/Tethering/res/values-pt-rBR/strings.xml
deleted file mode 100644
index a0a4745f93946..0000000000000
--- a/packages/Tethering/res/values-pt-rBR/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Ponto de acesso ou tethering ativo"
- "Toque para configurar."
- "Tethering desativado"
- "Fale com seu administrador para saber detalhes"
- "Status de ponto de acesso e tethering"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-pt-rPT/strings.xml b/packages/Tethering/res/values-pt-rPT/strings.xml
deleted file mode 100644
index e3f03fcc6934c..0000000000000
--- a/packages/Tethering/res/values-pt-rPT/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Ligação (à Internet) via telemóvel ou zona Wi-Fi ativas"
- "Toque para configurar."
- "A ligação (à Internet) via telemóvel está desativada."
- "Contacte o administrador para obter detalhes."
- "Estado da zona Wi-Fi e da ligação (à Internet) via telemóvel"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-pt/strings.xml b/packages/Tethering/res/values-pt/strings.xml
deleted file mode 100644
index a0a4745f93946..0000000000000
--- a/packages/Tethering/res/values-pt/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Ponto de acesso ou tethering ativo"
- "Toque para configurar."
- "Tethering desativado"
- "Fale com seu administrador para saber detalhes"
- "Status de ponto de acesso e tethering"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ro/strings.xml b/packages/Tethering/res/values-ro/strings.xml
deleted file mode 100644
index 5706a4a69c793..0000000000000
--- a/packages/Tethering/res/values-ro/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tethering sau hotspot activ"
- "Atingeți ca să configurați."
- "Tetheringul este dezactivat"
- "Contactați administratorul pentru detalii"
- "Starea hotspotului și a tetheringului"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ru/strings.xml b/packages/Tethering/res/values-ru/strings.xml
deleted file mode 100644
index 7cb6f7db3fc87..0000000000000
--- a/packages/Tethering/res/values-ru/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Включен режим модема или точка доступа"
- "Нажмите, чтобы настроить."
- "Использование телефона в качестве модема запрещено"
- "Чтобы узнать подробности, обратитесь к администратору."
- "Статус хот-спота и режима модема"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-si/strings.xml b/packages/Tethering/res/values-si/strings.xml
deleted file mode 100644
index ec34c22de7506..0000000000000
--- a/packages/Tethering/res/values-si/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "ටෙදරින් හෝ හොට්ස්පොට් සක්රීයයි"
- "පිහිටුවීමට තට්ටු කරන්න."
- "ටෙදරින් අබල කර ඇත"
- "විස්තර සඳහා ඔබගේ පරිපාලක අමතන්න"
- "හොට්ස්පොට් & ටෙදරින් තත්ත්වය"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-sk/strings.xml b/packages/Tethering/res/values-sk/strings.xml
deleted file mode 100644
index 43e787c84f870..0000000000000
--- a/packages/Tethering/res/values-sk/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tethering alebo prístupový bod je aktívny"
- "Klepnutím prejdete na nastavenie."
- "Tethering je deaktivovaný"
- "O podrobnosti požiadajte svojho správcu"
- "Stav hotspotu a tetheringu"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-sl/strings.xml b/packages/Tethering/res/values-sl/strings.xml
deleted file mode 100644
index 59433626a1156..0000000000000
--- a/packages/Tethering/res/values-sl/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Povezava z internetom prek mobilnega telefona ali dostopna točka je aktivna"
- "Dotaknite se, če želite nastaviti."
- "Povezava z internetom prek mobilnega telefona je onemogočena"
- "Za podrobnosti se obrnite na skrbnika"
- "Stanje dostopne točke in povezave z internetom prek mobilnega telefona"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-sq/strings.xml b/packages/Tethering/res/values-sq/strings.xml
deleted file mode 100644
index 21e11558bb0b3..0000000000000
--- a/packages/Tethering/res/values-sq/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Ndarja e internetit ose zona e qasjes së internetit është aktive"
- "Trokit për ta konfiguruar."
- "Ndarja e internetit është çaktivizuar"
- "Kontakto me administratorin për detaje"
- "Statusi i zonës së qasjes dhe ndarjes së internetit"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-sr/strings.xml b/packages/Tethering/res/values-sr/strings.xml
deleted file mode 100644
index e2e4dc6361d47..0000000000000
--- a/packages/Tethering/res/values-sr/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Привезивање или хотспот је активан"
- "Додирните да бисте подесили."
- "Привезивање је онемогућено"
- "Потражите детаље од администратора"
- "Статус хотспота и привезивања"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-sv/strings.xml b/packages/Tethering/res/values-sv/strings.xml
deleted file mode 100644
index 72702c28587da..0000000000000
--- a/packages/Tethering/res/values-sv/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Internetdelning eller surfzon har aktiverats"
- "Tryck om du vill konfigurera."
- "Internetdelning har inaktiverats"
- "Kontakta administratören om du vill veta mer"
- "Trådlös surfzon och internetdelning har inaktiverats"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-sw/strings.xml b/packages/Tethering/res/values-sw/strings.xml
deleted file mode 100644
index 65e4aa8cebb08..0000000000000
--- a/packages/Tethering/res/values-sw/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Kusambaza mtandao au mtandaopepe umewashwa"
- "Gusa ili uweke mipangilio."
- "Umezima kipengele cha kusambaza mtandao"
- "Wasiliana na msimamizi wako ili upate maelezo zaidi"
- "Mtandaopepe na hali ya kusambaza mtandao"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ta/strings.xml b/packages/Tethering/res/values-ta/strings.xml
deleted file mode 100644
index 4aba62d4ab462..0000000000000
--- a/packages/Tethering/res/values-ta/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "டெதெரிங் அல்லது ஹாட்ஸ்பாட் இயங்குகிறது"
- "அமைக்க, தட்டவும்."
- "டெதெரிங் முடக்கப்பட்டுள்ளது"
- "விவரங்களுக்கு உங்கள் நிர்வாகியைத் தொடர்புகொள்ளவும்"
- "ஹாட்ஸ்பாட் & டெதெரிங் நிலை"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-te/strings.xml b/packages/Tethering/res/values-te/strings.xml
deleted file mode 100644
index 1f917913416f1..0000000000000
--- a/packages/Tethering/res/values-te/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "టెథరింగ్ లేదా హాట్స్పాట్ యాక్టివ్గా ఉంది"
- "సెటప్ చేయడానికి ట్యాప్ చేయండి."
- "టెథరింగ్ డిజేబుల్ చేయబడింది"
- "వివరాల కోసం మీ అడ్మిన్ని సంప్రదించండి"
- "హాట్స్పాట్ & టెథరింగ్ స్థితి"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-th/strings.xml b/packages/Tethering/res/values-th/strings.xml
deleted file mode 100644
index 44171c0db82f5..0000000000000
--- a/packages/Tethering/res/values-th/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือหรือฮอตสปอตทำงานอยู่"
- "แตะเพื่อตั้งค่า"
- "ปิดใช้การเชื่อมต่ออินเทอร์เน็ตผ่านมือถือแล้ว"
- "ติดต่อผู้ดูแลระบบเพื่อขอรายละเอียด"
- "สถานะฮอตสปอตและการเชื่อมต่ออินเทอร์เน็ตผ่านมือถือ"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-tl/strings.xml b/packages/Tethering/res/values-tl/strings.xml
deleted file mode 100644
index 7347dd3e62549..0000000000000
--- a/packages/Tethering/res/values-tl/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Aktibo ang pag-tether o hotspot"
- "I-tap para i-set up."
- "Naka-disable ang pag-tether"
- "Makipag-ugnayan sa iyong admin para sa mga detalye"
- "Status ng hotspot at pag-tether"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-tr/strings.xml b/packages/Tethering/res/values-tr/strings.xml
deleted file mode 100644
index 32030f1765749..0000000000000
--- a/packages/Tethering/res/values-tr/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tethering veya hotspot etkin"
- "Ayarlamak için dokunun."
- "Tethering devre dışı bırakıldı"
- "Ayrıntılı bilgi için yöneticinize başvurun"
- "Hotspot ve tethering durumu"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-uk/strings.xml b/packages/Tethering/res/values-uk/strings.xml
deleted file mode 100644
index 1ca89b3f7813b..0000000000000
--- a/packages/Tethering/res/values-uk/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Модем чи точка доступу активні"
- "Натисніть, щоб налаштувати."
- "Використання телефона як модема вимкнено"
- "Щоб дізнатися більше, зв\'яжіться з адміністратором"
- "Статус точки доступу та модема"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-ur/strings.xml b/packages/Tethering/res/values-ur/strings.xml
deleted file mode 100644
index d72c7d4195777..0000000000000
--- a/packages/Tethering/res/values-ur/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "ٹیدرنگ یا ہاٹ اسپاٹ فعال"
- "سیٹ اپ کرنے کیلئے تھپتھپائیں۔"
- "ٹیدرنگ غیر فعال ہے"
- "تفصیلات کے لئے اپنے منتظم سے رابطہ کریں"
- "ہاٹ اسپاٹ اور ٹیتھرنگ کا اسٹیٹس"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-uz/strings.xml b/packages/Tethering/res/values-uz/strings.xml
deleted file mode 100644
index af3b2ebb35000..0000000000000
--- a/packages/Tethering/res/values-uz/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Modem rejimi yoki hotspot yoniq"
- "Sozlash uchun bosing."
- "Modem rejimi faolsizlantirildi"
- "Tafsilotlari uchun administratoringizga murojaat qiling"
- "Hotspot va modem rejimi holati"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-vi/strings.xml b/packages/Tethering/res/values-vi/strings.xml
deleted file mode 100644
index 21a0735922c30..0000000000000
--- a/packages/Tethering/res/values-vi/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Tính năng chia sẻ Internet hoặc điểm phát sóng đang hoạt động"
- "Hãy nhấn để thiết lập."
- "Đã tắt tính năng chia sẻ Internet"
- "Hãy liên hệ với quản trị viên của bạn để biết chi tiết"
- "Trạng thái điểm phát sóng và chia sẻ Internet"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-zh-rCN/strings.xml b/packages/Tethering/res/values-zh-rCN/strings.xml
deleted file mode 100644
index 98e3b4b46fdba..0000000000000
--- a/packages/Tethering/res/values-zh-rCN/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "网络共享或热点已启用"
- "点按即可设置。"
- "网络共享已停用"
- "如需了解详情,请与您的管理员联系"
- "热点和网络共享状态"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-zh-rHK/strings.xml b/packages/Tethering/res/values-zh-rHK/strings.xml
deleted file mode 100644
index 9cafd42dd43f8..0000000000000
--- a/packages/Tethering/res/values-zh-rHK/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "網絡共享或熱點已啟用"
- "輕按即可設定。"
- "網絡共享已停用"
- "請聯絡您的管理員以瞭解詳情"
- "熱點和網絡共享狀態"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-zh-rTW/strings.xml b/packages/Tethering/res/values-zh-rTW/strings.xml
deleted file mode 100644
index 50a50bf7a996f..0000000000000
--- a/packages/Tethering/res/values-zh-rTW/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "網路共用或無線基地台已啟用"
- "輕觸即可進行設定。"
- "網路共用已停用"
- "詳情請洽你的管理員"
- "無線基地台與網路共用狀態"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values-zu/strings.xml b/packages/Tethering/res/values-zu/strings.xml
deleted file mode 100644
index f210f8726ee5f..0000000000000
--- a/packages/Tethering/res/values-zu/strings.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
- "Ukusebenzisa njengemodemu noma i-hotspot ephathekayo kuvuliwe"
- "Thepha ukuze usethe."
- "Ukusebenzisa ifoni njengemodemu kukhutshaziwe"
- "Xhumana nomphathi wakho ukuze uthole imininingwane"
- "I-Hotspot nesimo sokusebenzisa ifoni njengemodemu"
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values/config.xml b/packages/Tethering/res/values/config.xml
deleted file mode 100644
index 5f8d2997197fa..0000000000000
--- a/packages/Tethering/res/values/config.xml
+++ /dev/null
@@ -1,194 +0,0 @@
-
-
-
-
-
-
- "usb\\d"
- "rndis\\d"
-
-
-
-
-
-
-
-
- "wlan\\d"
- "softap\\d"
-
-
-
-
- "wigig\\d"
-
-
-
-
- "p2p-p2p\\d-.*"
- "p2p\\d"
-
-
-
-
- "bt-pan"
-
-
-
- true
-
-
- false
-
-
- false
-
-
-
-
-
-
- 5000
-
-
-
-
-
-
- true
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 24
-
-
- com.android.settings/.wifi.tether.TetherService
-
-
-
- -1
-
-
-
- false
-
diff --git a/packages/Tethering/res/values/overlayable.xml b/packages/Tethering/res/values/overlayable.xml
deleted file mode 100644
index 0ee7a992ee206..0000000000000
--- a/packages/Tethering/res/values/overlayable.xml
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/Tethering/res/values/strings.xml b/packages/Tethering/res/values/strings.xml
deleted file mode 100644
index d63c7c5063cc4..0000000000000
--- a/packages/Tethering/res/values/strings.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-
-
-
-
-
- Tethering or hotspot active
-
- Tap to set up.
-
-
-
- Tethering is disabled
-
- Contact your admin for details
-
-
-
- Hotspot & tethering status
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/Tethering/src/android/net/dhcp/DhcpServerCallbacks.java b/packages/Tethering/src/android/net/dhcp/DhcpServerCallbacks.java
deleted file mode 100644
index 9fda1257b4c96..0000000000000
--- a/packages/Tethering/src/android/net/dhcp/DhcpServerCallbacks.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (C) 2018 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 android.net.dhcp;
-
-/**
- * Convenience wrapper around IDhcpServerCallbacks.Stub that implements getInterfaceVersion().
- * @hide
- */
-public abstract class DhcpServerCallbacks extends IDhcpServerCallbacks.Stub {
- /**
- * Get the version of the aidl interface implemented by the callbacks.
- */
- @Override
- public int getInterfaceVersion() {
- return IDhcpServerCallbacks.VERSION;
- }
-
- @Override
- public String getInterfaceHash() {
- return IDhcpServerCallbacks.HASH;
- }
-}
diff --git a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java
deleted file mode 100644
index aaaec17bf9223..0000000000000
--- a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2018 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 android.net.dhcp;
-
-import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH;
-
-import android.net.LinkAddress;
-import android.util.ArraySet;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import java.net.Inet4Address;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Set;
-
-/**
- * Subclass of {@link DhcpServingParamsParcel} with additional utility methods for building.
- *
- *
This utility class does not check for validity of the parameters: invalid parameters are
- * reported by the receiving module when unparceling the parcel.
- *
- * @see DhcpServingParams
- * @hide
- */
-public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel {
- public static final int MTU_UNSET = 0;
-
- /**
- * Set the server address and served prefix for the DHCP server.
- *
- *
This parameter is required.
- */
- public DhcpServingParamsParcelExt setServerAddr(@NonNull LinkAddress serverAddr) {
- this.serverAddr = inet4AddressToIntHTH((Inet4Address) serverAddr.getAddress());
- this.serverAddrPrefixLength = serverAddr.getPrefixLength();
- return this;
- }
-
- /**
- * Set the default routers to be advertised to DHCP clients.
- *
- *
Each router must be inside the served prefix. This may be an empty set, but it must
- * always be set explicitly.
- */
- public DhcpServingParamsParcelExt setDefaultRouters(@NonNull Set defaultRouters) {
- this.defaultRouters = toIntArray(defaultRouters);
- return this;
- }
-
- /**
- * Set the default routers to be advertised to DHCP clients.
- *
- *
Each router must be inside the served prefix. This may be an empty list of routers,
- * but it must always be set explicitly.
- */
- public DhcpServingParamsParcelExt setDefaultRouters(@NonNull Inet4Address... defaultRouters) {
- return setDefaultRouters(newArraySet(defaultRouters));
- }
-
- /**
- * Convenience method to build the parameters with no default router.
- *
- *
Equivalent to calling {@link #setDefaultRouters(Inet4Address...)} with no address.
- */
- public DhcpServingParamsParcelExt setNoDefaultRouter() {
- return setDefaultRouters();
- }
-
- /**
- * Set the DNS servers to be advertised to DHCP clients.
- *
- *
This may be an empty set, but it must always be set explicitly.
- */
- public DhcpServingParamsParcelExt setDnsServers(@NonNull Set dnsServers) {
- this.dnsServers = toIntArray(dnsServers);
- return this;
- }
-
- /**
- * Set the DNS servers to be advertised to DHCP clients.
- *
- *
This may be an empty list of servers, but it must always be set explicitly.
- */
- public DhcpServingParamsParcelExt setDnsServers(@NonNull Inet4Address... dnsServers) {
- return setDnsServers(newArraySet(dnsServers));
- }
-
- /**
- * Convenience method to build the parameters with no DNS server.
- *
- *
Equivalent to calling {@link #setDnsServers(Inet4Address...)} with no address.
- */
- public DhcpServingParamsParcelExt setNoDnsServer() {
- return setDnsServers();
- }
-
- /**
- * Set excluded addresses that the DHCP server is not allowed to assign to clients.
- *
- *
This parameter is optional. DNS servers and default routers are always excluded
- * and do not need to be set here.
- */
- public DhcpServingParamsParcelExt setExcludedAddrs(@NonNull Set excludedAddrs) {
- this.excludedAddrs = toIntArray(excludedAddrs);
- return this;
- }
-
- /**
- * Set excluded addresses that the DHCP server is not allowed to assign to clients.
- *
- *
This parameter is optional. DNS servers and default routers are always excluded
- * and do not need to be set here.
- */
- public DhcpServingParamsParcelExt setExcludedAddrs(@NonNull Inet4Address... excludedAddrs) {
- return setExcludedAddrs(newArraySet(excludedAddrs));
- }
-
- /**
- * Set the lease time for leases assigned by the DHCP server.
- *
- *
This parameter is required.
- */
- public DhcpServingParamsParcelExt setDhcpLeaseTimeSecs(long dhcpLeaseTimeSecs) {
- this.dhcpLeaseTimeSecs = dhcpLeaseTimeSecs;
- return this;
- }
-
- /**
- * Set the link MTU to be advertised to DHCP clients.
- *
- *
If set to {@link #MTU_UNSET}, no MTU will be advertised to clients. This parameter
- * is optional and defaults to {@link #MTU_UNSET}.
- */
- public DhcpServingParamsParcelExt setLinkMtu(int linkMtu) {
- this.linkMtu = linkMtu;
- return this;
- }
-
- /**
- * Set whether the DHCP server should send the ANDROID_METERED vendor-specific option.
- *
- *
If not set, the default value is false.
- */
- public DhcpServingParamsParcelExt setMetered(boolean metered) {
- this.metered = metered;
- return this;
- }
-
- /**
- * Set the client address to tell DHCP server only offer this address.
- * The client's prefix length is the same as server's.
- *
- *
If not set, the default value is null.
- */
- public DhcpServingParamsParcelExt setSingleClientAddr(@Nullable Inet4Address clientAddr) {
- this.singleClientAddr = clientAddr == null ? 0 : inet4AddressToIntHTH(clientAddr);
- return this;
- }
-
- /**
- * Set whether the DHCP server should request a new prefix from IpServer when receiving
- * DHCPDECLINE message in certain particular link (e.g. there is only one downstream USB
- * tethering client). If it's false, process DHCPDECLINE message as RFC2131#4.3.3 suggests.
- *
- *
If not set, the default value is false.
- */
- public DhcpServingParamsParcelExt setChangePrefixOnDecline(boolean changePrefixOnDecline) {
- this.changePrefixOnDecline = changePrefixOnDecline;
- return this;
- }
-
- private static int[] toIntArray(@NonNull Collection addrs) {
- int[] res = new int[addrs.size()];
- int i = 0;
- for (Inet4Address addr : addrs) {
- res[i] = inet4AddressToIntHTH(addr);
- i++;
- }
- return res;
- }
-
- private static ArraySet newArraySet(Inet4Address... addrs) {
- ArraySet addrSet = new ArraySet<>(addrs.length);
- Collections.addAll(addrSet, addrs);
- return addrSet;
- }
-}
diff --git a/packages/Tethering/src/android/net/ip/DadProxy.java b/packages/Tethering/src/android/net/ip/DadProxy.java
deleted file mode 100644
index e2976b78908c5..0000000000000
--- a/packages/Tethering/src/android/net/ip/DadProxy.java
+++ /dev/null
@@ -1,54 +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 android.net.ip;
-
-import android.net.util.InterfaceParams;
-import android.os.Handler;
-
-import androidx.annotation.VisibleForTesting;
-
-/**
- * Basic Duplicate address detection proxy.
- *
- * @hide
- */
-public class DadProxy {
- private static final String TAG = DadProxy.class.getSimpleName();
-
- @VisibleForTesting
- public static NeighborPacketForwarder naForwarder;
- public static NeighborPacketForwarder nsForwarder;
-
- public DadProxy(Handler h, InterfaceParams tetheredIface) {
- naForwarder = new NeighborPacketForwarder(h, tetheredIface,
- NeighborPacketForwarder.ICMPV6_NEIGHBOR_ADVERTISEMENT);
- nsForwarder = new NeighborPacketForwarder(h, tetheredIface,
- NeighborPacketForwarder.ICMPV6_NEIGHBOR_SOLICITATION);
- }
-
- /** Stop NS/NA Forwarders. */
- public void stop() {
- naForwarder.stop();
- nsForwarder.stop();
- }
-
- /** Set upstream iface on both forwarders. */
- public void setUpstreamIface(InterfaceParams upstreamIface) {
- naForwarder.setUpstreamIface(upstreamIface);
- nsForwarder.setUpstreamIface(upstreamIface);
- }
-}
diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java
deleted file mode 100644
index 52d59fcdc19b8..0000000000000
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ /dev/null
@@ -1,1422 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.net.ip;
-
-import static android.net.RouteInfo.RTN_UNICAST;
-import static android.net.TetheringManager.TetheringRequest.checkStaticAddressConfiguration;
-import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
-import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
-import static android.net.util.NetworkConstants.asByte;
-import static android.net.util.PrefixUtils.asIpPrefix;
-import static android.net.util.TetheringMessageBase.BASE_IPSERVER;
-import static android.system.OsConstants.RT_SCOPE_UNIVERSE;
-
-import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
-
-import android.net.INetd;
-import android.net.INetworkStackStatusCallback;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.MacAddress;
-import android.net.RouteInfo;
-import android.net.TetheredClient;
-import android.net.TetheringManager;
-import android.net.TetheringRequestParcel;
-import android.net.dhcp.DhcpLeaseParcelable;
-import android.net.dhcp.DhcpServerCallbacks;
-import android.net.dhcp.DhcpServingParamsParcel;
-import android.net.dhcp.DhcpServingParamsParcelExt;
-import android.net.dhcp.IDhcpEventCallbacks;
-import android.net.dhcp.IDhcpServer;
-import android.net.ip.IpNeighborMonitor.NeighborEvent;
-import android.net.ip.RouterAdvertisementDaemon.RaParams;
-import android.net.shared.NetdUtils;
-import android.net.shared.RouteUtils;
-import android.net.util.InterfaceParams;
-import android.net.util.InterfaceSet;
-import android.net.util.PrefixUtils;
-import android.net.util.SharedLog;
-import android.os.Build;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.util.Log;
-import android.util.SparseArray;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.util.MessageUtils;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-import com.android.networkstack.tethering.BpfCoordinator;
-import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule;
-import com.android.networkstack.tethering.PrivateAddressCoordinator;
-
-import java.io.IOException;
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.NetworkInterface;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Objects;
-import java.util.Random;
-import java.util.Set;
-
-/**
- * Provides the interface to IP-layer serving functionality for a given network
- * interface, e.g. for tethering or "local-only hotspot" mode.
- *
- * @hide
- */
-public class IpServer extends StateMachine {
- public static final int STATE_UNAVAILABLE = 0;
- public static final int STATE_AVAILABLE = 1;
- public static final int STATE_TETHERED = 2;
- public static final int STATE_LOCAL_ONLY = 3;
-
- /** Get string name of |state|.*/
- public static String getStateString(int state) {
- switch (state) {
- case STATE_UNAVAILABLE: return "UNAVAILABLE";
- case STATE_AVAILABLE: return "AVAILABLE";
- case STATE_TETHERED: return "TETHERED";
- case STATE_LOCAL_ONLY: return "LOCAL_ONLY";
- }
- return "UNKNOWN: " + state;
- }
-
- private static final byte DOUG_ADAMS = (byte) 42;
-
- // TODO: have PanService use some visible version of this constant
- private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1/24";
-
- // TODO: have this configurable
- private static final int DHCP_LEASE_TIME_SECS = 3600;
-
- private static final MacAddress NULL_MAC_ADDRESS = MacAddress.fromString("00:00:00:00:00:00");
-
- private static final String TAG = "IpServer";
- private static final boolean DBG = false;
- private static final boolean VDBG = false;
- private static final Class[] sMessageClasses = {
- IpServer.class
- };
- private static final SparseArray sMagicDecoderRing =
- MessageUtils.findMessageNames(sMessageClasses);
-
- /** IpServer callback. */
- public static class Callback {
- /**
- * Notify that |who| has changed its tethering state.
- *
- * @param who the calling instance of IpServer
- * @param state one of STATE_*
- * @param lastError one of TetheringManager.TETHER_ERROR_*
- */
- public void updateInterfaceState(IpServer who, int state, int lastError) { }
-
- /**
- * Notify that |who| has new LinkProperties.
- *
- * @param who the calling instance of IpServer
- * @param newLp the new LinkProperties to report
- */
- public void updateLinkProperties(IpServer who, LinkProperties newLp) { }
-
- /**
- * Notify that the DHCP leases changed in one of the IpServers.
- */
- public void dhcpLeasesChanged() { }
-
- /**
- * Request Tethering change.
- *
- * @param tetheringType the downstream type of this IpServer.
- * @param enabled enable or disable tethering.
- */
- public void requestEnableTethering(int tetheringType, boolean enabled) { }
- }
-
- /** Capture IpServer dependencies, for injection. */
- public abstract static class Dependencies {
- /**
- * Create a DadProxy instance to be used by IpServer.
- * To support multiple tethered interfaces concurrently DAD Proxy
- * needs to be supported per IpServer instead of per upstream.
- */
- public DadProxy getDadProxy(Handler handler, InterfaceParams ifParams) {
- return new DadProxy(handler, ifParams);
- }
-
- /** Create an IpNeighborMonitor to be used by this IpServer */
- public IpNeighborMonitor getIpNeighborMonitor(Handler handler, SharedLog log,
- IpNeighborMonitor.NeighborEventConsumer consumer) {
- return new IpNeighborMonitor(handler, log, consumer);
- }
-
- /** Create a RouterAdvertisementDaemon instance to be used by IpServer.*/
- public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
- return new RouterAdvertisementDaemon(ifParams);
- }
-
- /** Get |ifName|'s interface information.*/
- public InterfaceParams getInterfaceParams(String ifName) {
- return InterfaceParams.getByName(ifName);
- }
-
- /** Get |ifName|'s interface index. */
- public int getIfindex(String ifName) {
- try {
- return NetworkInterface.getByName(ifName).getIndex();
- } catch (IOException | NullPointerException e) {
- Log.e(TAG, "Can't determine interface index for interface " + ifName);
- return 0;
- }
- }
-
- /** Create a DhcpServer instance to be used by IpServer. */
- public abstract void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
- DhcpServerCallbacks cb);
- }
-
- // request from the user that it wants to tether
- public static final int CMD_TETHER_REQUESTED = BASE_IPSERVER + 1;
- // request from the user that it wants to untether
- public static final int CMD_TETHER_UNREQUESTED = BASE_IPSERVER + 2;
- // notification that this interface is down
- public static final int CMD_INTERFACE_DOWN = BASE_IPSERVER + 3;
- // notification from the {@link Tethering.TetherMainSM} that it had trouble enabling IP
- // Forwarding
- public static final int CMD_IP_FORWARDING_ENABLE_ERROR = BASE_IPSERVER + 4;
- // notification from the {@link Tethering.TetherMainSM} SM that it had trouble disabling IP
- // Forwarding
- public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IPSERVER + 5;
- // notification from the {@link Tethering.TetherMainSM} SM that it had trouble starting
- // tethering
- public static final int CMD_START_TETHERING_ERROR = BASE_IPSERVER + 6;
- // notification from the {@link Tethering.TetherMainSM} that it had trouble stopping tethering
- public static final int CMD_STOP_TETHERING_ERROR = BASE_IPSERVER + 7;
- // notification from the {@link Tethering.TetherMainSM} that it had trouble setting the DNS
- // forwarders
- public static final int CMD_SET_DNS_FORWARDERS_ERROR = BASE_IPSERVER + 8;
- // the upstream connection has changed
- public static final int CMD_TETHER_CONNECTION_CHANGED = BASE_IPSERVER + 9;
- // new IPv6 tethering parameters need to be processed
- public static final int CMD_IPV6_TETHER_UPDATE = BASE_IPSERVER + 10;
- // new neighbor cache entry on our interface
- public static final int CMD_NEIGHBOR_EVENT = BASE_IPSERVER + 11;
- // request from DHCP server that it wants to have a new prefix
- public static final int CMD_NEW_PREFIX_REQUEST = BASE_IPSERVER + 12;
- // request from PrivateAddressCoordinator to restart tethering.
- public static final int CMD_NOTIFY_PREFIX_CONFLICT = BASE_IPSERVER + 13;
-
- private final State mInitialState;
- private final State mLocalHotspotState;
- private final State mTetheredState;
- private final State mUnavailableState;
- private final State mWaitingForRestartState;
-
- private final SharedLog mLog;
- private final INetd mNetd;
- @NonNull
- private final BpfCoordinator mBpfCoordinator;
- private final Callback mCallback;
- private final InterfaceController mInterfaceCtrl;
- private final PrivateAddressCoordinator mPrivateAddressCoordinator;
-
- private final String mIfaceName;
- private final int mInterfaceType;
- private final LinkProperties mLinkProperties;
- private final boolean mUsingLegacyDhcp;
- private final boolean mUsingBpfOffload;
-
- private final Dependencies mDeps;
-
- private int mLastError;
- private int mServingMode;
- private InterfaceSet mUpstreamIfaceSet; // may change over time
- private InterfaceParams mInterfaceParams;
- // TODO: De-duplicate this with mLinkProperties above. Currently, these link
- // properties are those selected by the IPv6TetheringCoordinator and relayed
- // to us. By comparison, mLinkProperties contains the addresses and directly
- // connected routes that have been formed from these properties iff. we have
- // succeeded in configuring them and are able to announce them within Router
- // Advertisements (otherwise, we do not add them to mLinkProperties at all).
- private LinkProperties mLastIPv6LinkProperties;
- private RouterAdvertisementDaemon mRaDaemon;
- private DadProxy mDadProxy;
-
- // To be accessed only on the handler thread
- private int mDhcpServerStartIndex = 0;
- private IDhcpServer mDhcpServer;
- private RaParams mLastRaParams;
-
- private LinkAddress mStaticIpv4ServerAddr;
- private LinkAddress mStaticIpv4ClientAddr;
-
- @NonNull
- private List mDhcpLeases = Collections.emptyList();
-
- private int mLastIPv6UpstreamIfindex = 0;
-
- private class MyNeighborEventConsumer implements IpNeighborMonitor.NeighborEventConsumer {
- public void accept(NeighborEvent e) {
- sendMessage(CMD_NEIGHBOR_EVENT, e);
- }
- }
-
- private final IpNeighborMonitor mIpNeighborMonitor;
-
- private LinkAddress mIpv4Address;
-
- // TODO: Add a dependency object to pass the data members or variables from the tethering
- // object. It helps to reduce the arguments of the constructor.
- public IpServer(
- String ifaceName, Looper looper, int interfaceType, SharedLog log,
- INetd netd, @NonNull BpfCoordinator coordinator, Callback callback,
- boolean usingLegacyDhcp, boolean usingBpfOffload,
- PrivateAddressCoordinator addressCoordinator, Dependencies deps) {
- super(ifaceName, looper);
- mLog = log.forSubComponent(ifaceName);
- mNetd = netd;
- mBpfCoordinator = coordinator;
- mCallback = callback;
- mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog);
- mIfaceName = ifaceName;
- mInterfaceType = interfaceType;
- mLinkProperties = new LinkProperties();
- mUsingLegacyDhcp = usingLegacyDhcp;
- mUsingBpfOffload = usingBpfOffload;
- mPrivateAddressCoordinator = addressCoordinator;
- mDeps = deps;
- resetLinkProperties();
- mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
- mServingMode = STATE_AVAILABLE;
-
- mIpNeighborMonitor = mDeps.getIpNeighborMonitor(getHandler(), mLog,
- new MyNeighborEventConsumer());
-
- // IP neighbor monitor monitors the neighbor events for adding/removing offload
- // forwarding rules per client. If BPF offload is not supported, don't start listening
- // for neighbor events. See updateIpv6ForwardingRules, addIpv6ForwardingRule,
- // removeIpv6ForwardingRule.
- if (mUsingBpfOffload && !mIpNeighborMonitor.start()) {
- mLog.e("Failed to create IpNeighborMonitor on " + mIfaceName);
- }
-
- mInitialState = new InitialState();
- mLocalHotspotState = new LocalHotspotState();
- mTetheredState = new TetheredState();
- mUnavailableState = new UnavailableState();
- mWaitingForRestartState = new WaitingForRestartState();
- addState(mInitialState);
- addState(mLocalHotspotState);
- addState(mTetheredState);
- addState(mWaitingForRestartState, mTetheredState);
- addState(mUnavailableState);
-
- setInitialState(mInitialState);
- }
-
- /** Interface name which IpServer served.*/
- public String interfaceName() {
- return mIfaceName;
- }
-
- /**
- * Tethering downstream type. It would be one of TetheringManager#TETHERING_*.
- */
- public int interfaceType() {
- return mInterfaceType;
- }
-
- /** Last error from this IpServer. */
- public int lastError() {
- return mLastError;
- }
-
- /** Serving mode is the current state of IpServer state machine. */
- public int servingMode() {
- return mServingMode;
- }
-
- /** The properties of the network link which IpServer is serving. */
- public LinkProperties linkProperties() {
- return new LinkProperties(mLinkProperties);
- }
-
- /** The address which IpServer is using. */
- public LinkAddress getAddress() {
- return mIpv4Address;
- }
-
- /**
- * Get the latest list of DHCP leases that was reported. Must be called on the IpServer looper
- * thread.
- */
- public List getAllLeases() {
- return Collections.unmodifiableList(mDhcpLeases);
- }
-
- /** Stop this IpServer. After this is called this IpServer should not be used any more. */
- public void stop() {
- sendMessage(CMD_INTERFACE_DOWN);
- }
-
- /**
- * Tethering is canceled. IpServer state machine will be available and wait for
- * next tethering request.
- */
- public void unwanted() {
- sendMessage(CMD_TETHER_UNREQUESTED);
- }
-
- /** Internals. */
-
- private boolean startIPv4() {
- return configureIPv4(true);
- }
-
- /**
- * Convenience wrapper around INetworkStackStatusCallback to run callbacks on the IpServer
- * handler.
- *
- *
Different instances of this class can be created for each call to IDhcpServer methods,
- * with different implementations of the callback, to differentiate handling of success/error in
- * each call.
- */
- private abstract class OnHandlerStatusCallback extends INetworkStackStatusCallback.Stub {
- @Override
- public void onStatusAvailable(int statusCode) {
- getHandler().post(() -> callback(statusCode));
- }
-
- public abstract void callback(int statusCode);
-
- @Override
- public int getInterfaceVersion() {
- return this.VERSION;
- }
-
- @Override
- public String getInterfaceHash() {
- return this.HASH;
- }
- }
-
- private class DhcpServerCallbacksImpl extends DhcpServerCallbacks {
- private final int mStartIndex;
-
- private DhcpServerCallbacksImpl(int startIndex) {
- mStartIndex = startIndex;
- }
-
- @Override
- public void onDhcpServerCreated(int statusCode, IDhcpServer server) throws RemoteException {
- getHandler().post(() -> {
- // We are on the handler thread: mDhcpServerStartIndex can be read safely.
- if (mStartIndex != mDhcpServerStartIndex) {
- // This start request is obsolete. Explicitly stop the DHCP server to shut
- // down its thread. When the |server| binder token goes out of scope, the
- // garbage collector will finalize it, which causes the network stack process
- // garbage collector to collect the server itself.
- try {
- server.stop(null);
- } catch (RemoteException e) { }
- return;
- }
-
- if (statusCode != STATUS_SUCCESS) {
- mLog.e("Error obtaining DHCP server: " + statusCode);
- handleError();
- return;
- }
-
- mDhcpServer = server;
- try {
- mDhcpServer.startWithCallbacks(new OnHandlerStatusCallback() {
- @Override
- public void callback(int startStatusCode) {
- if (startStatusCode != STATUS_SUCCESS) {
- mLog.e("Error starting DHCP server: " + startStatusCode);
- handleError();
- }
- }
- }, new DhcpEventCallback());
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
- });
- }
-
- private void handleError() {
- mLastError = TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR;
- transitionTo(mInitialState);
- }
- }
-
- private class DhcpEventCallback extends IDhcpEventCallbacks.Stub {
- @Override
- public void onLeasesChanged(List leaseParcelables) {
- final ArrayList leases = new ArrayList<>();
- for (DhcpLeaseParcelable lease : leaseParcelables) {
- final LinkAddress address = new LinkAddress(
- intToInet4AddressHTH(lease.netAddr), lease.prefixLength,
- 0 /* flags */, RT_SCOPE_UNIVERSE /* as per RFC6724#3.2 */,
- lease.expTime /* deprecationTime */, lease.expTime /* expirationTime */);
-
- final MacAddress macAddress;
- try {
- macAddress = MacAddress.fromBytes(lease.hwAddr);
- } catch (IllegalArgumentException e) {
- Log.wtf(TAG, "Invalid address received from DhcpServer: "
- + Arrays.toString(lease.hwAddr));
- return;
- }
-
- final TetheredClient.AddressInfo addressInfo = new TetheredClient.AddressInfo(
- address, lease.hostname);
- leases.add(new TetheredClient(
- macAddress,
- Collections.singletonList(addressInfo),
- mInterfaceType));
- }
-
- getHandler().post(() -> {
- mDhcpLeases = leases;
- mCallback.dhcpLeasesChanged();
- });
- }
-
- @Override
- public void onNewPrefixRequest(@NonNull final IpPrefix currentPrefix) {
- Objects.requireNonNull(currentPrefix);
- sendMessage(CMD_NEW_PREFIX_REQUEST, currentPrefix);
- }
-
- @Override
- public int getInterfaceVersion() {
- return this.VERSION;
- }
-
- @Override
- public String getInterfaceHash() throws RemoteException {
- return this.HASH;
- }
- }
-
- private RouteInfo getDirectConnectedRoute(@NonNull final LinkAddress ipv4Address) {
- Objects.requireNonNull(ipv4Address);
- return new RouteInfo(PrefixUtils.asIpPrefix(ipv4Address), null, mIfaceName, RTN_UNICAST);
- }
-
- private DhcpServingParamsParcel makeServingParams(@NonNull final Inet4Address defaultRouter,
- @NonNull final Inet4Address dnsServer, @NonNull LinkAddress serverAddr,
- @Nullable Inet4Address clientAddr) {
- final boolean changePrefixOnDecline =
- (mInterfaceType == TetheringManager.TETHERING_NCM && clientAddr == null);
- return new DhcpServingParamsParcelExt()
- .setDefaultRouters(defaultRouter)
- .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
- .setDnsServers(dnsServer)
- .setServerAddr(serverAddr)
- .setMetered(true)
- .setSingleClientAddr(clientAddr)
- .setChangePrefixOnDecline(changePrefixOnDecline);
- // TODO: also advertise link MTU
- }
-
- private boolean startDhcp(final LinkAddress serverLinkAddr, final LinkAddress clientLinkAddr) {
- if (mUsingLegacyDhcp) {
- return true;
- }
-
- final Inet4Address addr = (Inet4Address) serverLinkAddr.getAddress();
- final Inet4Address clientAddr = clientLinkAddr == null ? null :
- (Inet4Address) clientLinkAddr.getAddress();
-
- final DhcpServingParamsParcel params = makeServingParams(addr /* defaultRouter */,
- addr /* dnsServer */, serverLinkAddr, clientAddr);
- mDhcpServerStartIndex++;
- mDeps.makeDhcpServer(
- mIfaceName, params, new DhcpServerCallbacksImpl(mDhcpServerStartIndex));
- return true;
- }
-
- private void stopDhcp() {
- // Make all previous start requests obsolete so servers are not started later
- mDhcpServerStartIndex++;
-
- if (mDhcpServer != null) {
- try {
- mDhcpServer.stop(new OnHandlerStatusCallback() {
- @Override
- public void callback(int statusCode) {
- if (statusCode != STATUS_SUCCESS) {
- mLog.e("Error stopping DHCP server: " + statusCode);
- mLastError = TetheringManager.TETHER_ERROR_DHCPSERVER_ERROR;
- // Not much more we can do here
- }
- mDhcpLeases.clear();
- getHandler().post(mCallback::dhcpLeasesChanged);
- }
- });
- mDhcpServer = null;
- } catch (RemoteException e) {
- mLog.e("Error stopping DHCP server", e);
- // Not much more we can do here
- }
- }
- }
-
- private boolean configureDhcp(boolean enable, final LinkAddress serverAddr,
- final LinkAddress clientAddr) {
- if (enable) {
- return startDhcp(serverAddr, clientAddr);
- } else {
- stopDhcp();
- return true;
- }
- }
-
- private void stopIPv4() {
- configureIPv4(false);
- // NOTE: All of configureIPv4() will be refactored out of existence
- // into calls to InterfaceController, shared with startIPv4().
- mInterfaceCtrl.clearIPv4Address();
- mPrivateAddressCoordinator.releaseDownstream(this);
- mIpv4Address = null;
- mStaticIpv4ServerAddr = null;
- mStaticIpv4ClientAddr = null;
- }
-
- private boolean configureIPv4(boolean enabled) {
- if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
-
- if (enabled) {
- mIpv4Address = requestIpv4Address(true /* useLastAddress */);
- }
-
- if (mIpv4Address == null) {
- mLog.e("No available ipv4 address");
- return false;
- }
-
- if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) {
- // BT configures the interface elsewhere: only start DHCP.
- // TODO: make all tethering types behave the same way, and delete the bluetooth
- // code that calls into NetworkManagementService directly.
- return configureDhcp(enabled, mIpv4Address, null /* clientAddress */);
- }
-
- final IpPrefix ipv4Prefix = asIpPrefix(mIpv4Address);
-
- final Boolean setIfaceUp;
- if (mInterfaceType == TetheringManager.TETHERING_WIFI
- || mInterfaceType == TetheringManager.TETHERING_WIFI_P2P
- || mInterfaceType == TetheringManager.TETHERING_ETHERNET
- || mInterfaceType == TetheringManager.TETHERING_WIGIG) {
- // The WiFi and Ethernet stack has ownership of the interface up/down state.
- // It is unclear whether the Bluetooth or USB stacks will manage their own
- // state.
- setIfaceUp = null;
- } else {
- setIfaceUp = enabled;
- }
- if (!mInterfaceCtrl.setInterfaceConfiguration(mIpv4Address, setIfaceUp)) {
- mLog.e("Error configuring interface");
- if (!enabled) stopDhcp();
- return false;
- }
-
- if (enabled) {
- mLinkProperties.addLinkAddress(mIpv4Address);
- mLinkProperties.addRoute(getDirectConnectedRoute(mIpv4Address));
- } else {
- mLinkProperties.removeLinkAddress(mIpv4Address);
- mLinkProperties.removeRoute(getDirectConnectedRoute(mIpv4Address));
- }
- return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr);
- }
-
- private LinkAddress requestIpv4Address(final boolean useLastAddress) {
- if (mStaticIpv4ServerAddr != null) return mStaticIpv4ServerAddr;
-
- if (mInterfaceType == TetheringManager.TETHERING_BLUETOOTH) {
- return new LinkAddress(BLUETOOTH_IFACE_ADDR);
- }
-
- return mPrivateAddressCoordinator.requestDownstreamAddress(this, useLastAddress);
- }
-
- private boolean startIPv6() {
- mInterfaceParams = mDeps.getInterfaceParams(mIfaceName);
- if (mInterfaceParams == null) {
- mLog.e("Failed to find InterfaceParams");
- stopIPv6();
- return false;
- }
-
- mRaDaemon = mDeps.getRouterAdvertisementDaemon(mInterfaceParams);
- if (!mRaDaemon.start()) {
- stopIPv6();
- return false;
- }
-
- // TODO: use ShimUtils instead of explicitly checking the version here.
- if (Build.VERSION.SDK_INT > Build.VERSION_CODES.R || "S".equals(Build.VERSION.CODENAME)
- || "T".equals(Build.VERSION.CODENAME)) {
- // DAD Proxy starts forwarding packets after IPv6 upstream is present.
- mDadProxy = mDeps.getDadProxy(getHandler(), mInterfaceParams);
- }
-
- return true;
- }
-
- private void stopIPv6() {
- mInterfaceParams = null;
- setRaParams(null);
-
- if (mRaDaemon != null) {
- mRaDaemon.stop();
- mRaDaemon = null;
- }
-
- if (mDadProxy != null) {
- mDadProxy.stop();
- mDadProxy = null;
- }
- }
-
- // IPv6TetheringCoordinator sends updates with carefully curated IPv6-only
- // LinkProperties. These have extraneous data filtered out and only the
- // necessary prefixes included (per its prefix distribution policy).
- //
- // TODO: Evaluate using a data structure than is more directly suited to
- // communicating only the relevant information.
- private void updateUpstreamIPv6LinkProperties(LinkProperties v6only, int ttlAdjustment) {
- if (mRaDaemon == null) return;
-
- // Avoid unnecessary work on spurious updates.
- if (Objects.equals(mLastIPv6LinkProperties, v6only)) {
- return;
- }
-
- RaParams params = null;
- String upstreamIface = null;
- InterfaceParams upstreamIfaceParams = null;
- int upstreamIfIndex = 0;
-
- if (v6only != null) {
- upstreamIface = v6only.getInterfaceName();
- upstreamIfaceParams = mDeps.getInterfaceParams(upstreamIface);
- if (upstreamIfaceParams != null) {
- upstreamIfIndex = upstreamIfaceParams.index;
- }
- params = new RaParams();
- params.mtu = v6only.getMtu();
- params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
-
- if (params.hasDefaultRoute) params.hopLimit = getHopLimit(upstreamIface, ttlAdjustment);
-
- for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
- if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
-
- final IpPrefix prefix = new IpPrefix(
- linkAddr.getAddress(), linkAddr.getPrefixLength());
- params.prefixes.add(prefix);
-
- final Inet6Address dnsServer = getLocalDnsIpFor(prefix);
- if (dnsServer != null) {
- params.dnses.add(dnsServer);
- }
- }
-
- // Add upstream index to name mapping for the tether stats usage in the coordinator.
- // Although this mapping could be added by both class Tethering and IpServer, adding
- // mapping from IpServer guarantees that the mapping is added before the adding
- // forwarding rules. That is because there are different state machines in both
- // classes. It is hard to guarantee the link property update order between multiple
- // state machines.
- mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfIndex, upstreamIface);
- }
-
- // If v6only is null, we pass in null to setRaParams(), which handles
- // deprecation of any existing RA data.
-
- setRaParams(params);
- mLastIPv6LinkProperties = v6only;
-
- updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, upstreamIfIndex, null);
- mLastIPv6UpstreamIfindex = upstreamIfIndex;
- if (mDadProxy != null) {
- mDadProxy.setUpstreamIface(upstreamIfaceParams);
- }
- }
-
- private void removeRoutesFromLocalNetwork(@NonNull final List toBeRemoved) {
- final int removalFailures = RouteUtils.removeRoutesFromLocalNetwork(
- mNetd, toBeRemoved);
- if (removalFailures > 0) {
- mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
- removalFailures));
- }
-
- for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route);
- }
-
- private void addRoutesToLocalNetwork(@NonNull final List toBeAdded) {
- try {
- // It's safe to call networkAddInterface() even if
- // the interface is already in the local_network.
- mNetd.networkAddInterface(INetd.LOCAL_NET_ID, mIfaceName);
- try {
- // Add routes from local network. Note that adding routes that
- // already exist does not cause an error (EEXIST is silently ignored).
- RouteUtils.addRoutesToLocalNetwork(mNetd, mIfaceName, toBeAdded);
- } catch (IllegalStateException e) {
- mLog.e("Failed to add IPv4/v6 routes to local table: " + e);
- return;
- }
- } catch (ServiceSpecificException | RemoteException e) {
- mLog.e("Failed to add " + mIfaceName + " to local table: ", e);
- return;
- }
-
- for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route);
- }
-
- private void configureLocalIPv6Routes(
- HashSet deprecatedPrefixes, HashSet newPrefixes) {
- // [1] Remove the routes that are deprecated.
- if (!deprecatedPrefixes.isEmpty()) {
- removeRoutesFromLocalNetwork(getLocalRoutesFor(mIfaceName, deprecatedPrefixes));
- }
-
- // [2] Add only the routes that have not previously been added.
- if (newPrefixes != null && !newPrefixes.isEmpty()) {
- HashSet addedPrefixes = (HashSet) newPrefixes.clone();
- if (mLastRaParams != null) {
- addedPrefixes.removeAll(mLastRaParams.prefixes);
- }
-
- if (!addedPrefixes.isEmpty()) {
- addRoutesToLocalNetwork(getLocalRoutesFor(mIfaceName, addedPrefixes));
- }
- }
- }
-
- private void configureLocalIPv6Dns(
- HashSet deprecatedDnses, HashSet newDnses) {
- // TODO: Is this really necessary? Can we not fail earlier if INetd cannot be located?
- if (mNetd == null) {
- if (newDnses != null) newDnses.clear();
- mLog.e("No netd service instance available; not setting local IPv6 addresses");
- return;
- }
-
- // [1] Remove deprecated local DNS IP addresses.
- if (!deprecatedDnses.isEmpty()) {
- for (Inet6Address dns : deprecatedDnses) {
- if (!mInterfaceCtrl.removeAddress(dns, RFC7421_PREFIX_LENGTH)) {
- mLog.e("Failed to remove local dns IP " + dns);
- }
-
- mLinkProperties.removeLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
- }
- }
-
- // [2] Add only the local DNS IP addresses that have not previously been added.
- if (newDnses != null && !newDnses.isEmpty()) {
- final HashSet addedDnses = (HashSet) newDnses.clone();
- if (mLastRaParams != null) {
- addedDnses.removeAll(mLastRaParams.dnses);
- }
-
- for (Inet6Address dns : addedDnses) {
- if (!mInterfaceCtrl.addAddress(dns, RFC7421_PREFIX_LENGTH)) {
- mLog.e("Failed to add local dns IP " + dns);
- newDnses.remove(dns);
- }
-
- mLinkProperties.addLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
- }
- }
-
- try {
- mNetd.tetherApplyDnsInterfaces();
- } catch (ServiceSpecificException | RemoteException e) {
- mLog.e("Failed to update local DNS caching server");
- if (newDnses != null) newDnses.clear();
- }
- }
-
- private void addIpv6ForwardingRule(Ipv6ForwardingRule rule) {
- // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF
- // offload is disabled. Add this check just in case.
- // TODO: Perhaps remove this protection check.
- if (!mUsingBpfOffload) return;
-
- mBpfCoordinator.tetherOffloadRuleAdd(this, rule);
- }
-
- private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule) {
- // TODO: Perhaps remove this protection check.
- // See the related comment in #addIpv6ForwardingRule.
- if (!mUsingBpfOffload) return;
-
- mBpfCoordinator.tetherOffloadRuleRemove(this, rule);
- }
-
- private void clearIpv6ForwardingRules() {
- if (!mUsingBpfOffload) return;
-
- mBpfCoordinator.tetherOffloadRuleClear(this);
- }
-
- private void updateIpv6ForwardingRule(int newIfindex) {
- // TODO: Perhaps remove this protection check.
- // See the related comment in #addIpv6ForwardingRule.
- if (!mUsingBpfOffload) return;
-
- mBpfCoordinator.tetherOffloadRuleUpdate(this, newIfindex);
- }
-
- // Handles all updates to IPv6 forwarding rules. These can currently change only if the upstream
- // changes or if a neighbor event is received.
- private void updateIpv6ForwardingRules(int prevUpstreamIfindex, int upstreamIfindex,
- NeighborEvent e) {
- // If we no longer have an upstream, clear forwarding rules and do nothing else.
- if (upstreamIfindex == 0) {
- clearIpv6ForwardingRules();
- return;
- }
-
- // If the upstream interface has changed, remove all rules and re-add them with the new
- // upstream interface.
- if (prevUpstreamIfindex != upstreamIfindex) {
- updateIpv6ForwardingRule(upstreamIfindex);
- }
-
- // If we're here to process a NeighborEvent, do so now.
- // mInterfaceParams must be non-null or the event would not have arrived.
- if (e == null) return;
- if (!(e.ip instanceof Inet6Address) || e.ip.isMulticastAddress()
- || e.ip.isLoopbackAddress() || e.ip.isLinkLocalAddress()) {
- return;
- }
-
- // When deleting rules, we still need to pass a non-null MAC, even though it's ignored.
- // Do this here instead of in the Ipv6ForwardingRule constructor to ensure that we never
- // add rules with a null MAC, only delete them.
- MacAddress dstMac = e.isValid() ? e.macAddr : NULL_MAC_ADDRESS;
- Ipv6ForwardingRule rule = new Ipv6ForwardingRule(upstreamIfindex,
- mInterfaceParams.index, (Inet6Address) e.ip, mInterfaceParams.macAddr, dstMac);
- if (e.isValid()) {
- addIpv6ForwardingRule(rule);
- } else {
- removeIpv6ForwardingRule(rule);
- }
- }
-
- private void handleNeighborEvent(NeighborEvent e) {
- if (mInterfaceParams != null
- && mInterfaceParams.index == e.ifindex
- && mInterfaceParams.hasMacAddress) {
- updateIpv6ForwardingRules(mLastIPv6UpstreamIfindex, mLastIPv6UpstreamIfindex, e);
- }
- }
-
- private void handleNewPrefixRequest(@NonNull final IpPrefix currentPrefix) {
- if (!currentPrefix.contains(mIpv4Address.getAddress())
- || currentPrefix.getPrefixLength() != mIpv4Address.getPrefixLength()) {
- Log.e(TAG, "Invalid prefix: " + currentPrefix);
- return;
- }
-
- final LinkAddress deprecatedLinkAddress = mIpv4Address;
- mIpv4Address = requestIpv4Address(false);
- if (mIpv4Address == null) {
- mLog.e("Fail to request a new downstream prefix");
- return;
- }
- final Inet4Address srvAddr = (Inet4Address) mIpv4Address.getAddress();
-
- // Add new IPv4 address on the interface.
- if (!mInterfaceCtrl.addAddress(srvAddr, currentPrefix.getPrefixLength())) {
- mLog.e("Failed to add new IP " + srvAddr);
- return;
- }
-
- // Remove deprecated routes from local network.
- removeRoutesFromLocalNetwork(
- Collections.singletonList(getDirectConnectedRoute(deprecatedLinkAddress)));
- mLinkProperties.removeLinkAddress(deprecatedLinkAddress);
-
- // Add new routes to local network.
- addRoutesToLocalNetwork(
- Collections.singletonList(getDirectConnectedRoute(mIpv4Address)));
- mLinkProperties.addLinkAddress(mIpv4Address);
-
- // Update local DNS caching server with new IPv4 address, otherwise, dnsmasq doesn't
- // listen on the interface configured with new IPv4 address, that results DNS validation
- // failure of downstream client even if appropriate routes have been configured.
- try {
- mNetd.tetherApplyDnsInterfaces();
- } catch (ServiceSpecificException | RemoteException e) {
- mLog.e("Failed to update local DNS caching server");
- return;
- }
- sendLinkProperties();
-
- // Notify DHCP server that new prefix/route has been applied on IpServer.
- final Inet4Address clientAddr = mStaticIpv4ClientAddr == null ? null :
- (Inet4Address) mStaticIpv4ClientAddr.getAddress();
- final DhcpServingParamsParcel params = makeServingParams(srvAddr /* defaultRouter */,
- srvAddr /* dnsServer */, mIpv4Address /* serverLinkAddress */, clientAddr);
- try {
- mDhcpServer.updateParams(params, new OnHandlerStatusCallback() {
- @Override
- public void callback(int statusCode) {
- if (statusCode != STATUS_SUCCESS) {
- mLog.e("Error updating DHCP serving params: " + statusCode);
- }
- }
- });
- } catch (RemoteException e) {
- mLog.e("Error updating DHCP serving params", e);
- }
- }
-
- private byte getHopLimit(String upstreamIface, int adjustTTL) {
- try {
- int upstreamHopLimit = Integer.parseUnsignedInt(
- mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, upstreamIface, "hop_limit"));
- upstreamHopLimit = upstreamHopLimit + adjustTTL;
- // Cap the hop limit to 255.
- return (byte) Integer.min(upstreamHopLimit, 255);
- } catch (Exception e) {
- mLog.e("Failed to find upstream interface hop limit", e);
- }
- return RaParams.DEFAULT_HOPLIMIT;
- }
-
- private void setRaParams(RaParams newParams) {
- if (mRaDaemon != null) {
- final RaParams deprecatedParams =
- RaParams.getDeprecatedRaParams(mLastRaParams, newParams);
-
- configureLocalIPv6Routes(deprecatedParams.prefixes,
- (newParams != null) ? newParams.prefixes : null);
-
- configureLocalIPv6Dns(deprecatedParams.dnses,
- (newParams != null) ? newParams.dnses : null);
-
- mRaDaemon.buildNewRa(deprecatedParams, newParams);
- }
-
- mLastRaParams = newParams;
- }
-
- private void logMessage(State state, int what) {
- mLog.log(state.getName() + " got " + sMagicDecoderRing.get(what, Integer.toString(what)));
- }
-
- private void sendInterfaceState(int newInterfaceState) {
- mServingMode = newInterfaceState;
- mCallback.updateInterfaceState(this, newInterfaceState, mLastError);
- sendLinkProperties();
- }
-
- private void sendLinkProperties() {
- mCallback.updateLinkProperties(this, new LinkProperties(mLinkProperties));
- }
-
- private void resetLinkProperties() {
- mLinkProperties.clear();
- mLinkProperties.setInterfaceName(mIfaceName);
- }
-
- private void maybeConfigureStaticIp(final TetheringRequestParcel request) {
- // Ignore static address configuration if they are invalid or null. In theory, static
- // addresses should not be invalid here because TetheringManager do not allow caller to
- // specify invalid static address configuration.
- if (request == null || request.localIPv4Address == null
- || request.staticClientAddress == null || !checkStaticAddressConfiguration(
- request.localIPv4Address, request.staticClientAddress)) {
- return;
- }
-
- mStaticIpv4ServerAddr = request.localIPv4Address;
- mStaticIpv4ClientAddr = request.staticClientAddress;
- }
-
- class InitialState extends State {
- @Override
- public void enter() {
- sendInterfaceState(STATE_AVAILABLE);
- }
-
- @Override
- public boolean processMessage(Message message) {
- logMessage(this, message.what);
- switch (message.what) {
- case CMD_TETHER_REQUESTED:
- mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
- switch (message.arg1) {
- case STATE_LOCAL_ONLY:
- maybeConfigureStaticIp((TetheringRequestParcel) message.obj);
- transitionTo(mLocalHotspotState);
- break;
- case STATE_TETHERED:
- maybeConfigureStaticIp((TetheringRequestParcel) message.obj);
- transitionTo(mTetheredState);
- break;
- default:
- mLog.e("Invalid tethering interface serving state specified.");
- }
- break;
- case CMD_INTERFACE_DOWN:
- transitionTo(mUnavailableState);
- break;
- case CMD_IPV6_TETHER_UPDATE:
- updateUpstreamIPv6LinkProperties((LinkProperties) message.obj, message.arg1);
- break;
- default:
- return NOT_HANDLED;
- }
- return HANDLED;
- }
- }
-
- class BaseServingState extends State {
- @Override
- public void enter() {
- if (!startIPv4()) {
- mLastError = TetheringManager.TETHER_ERROR_IFACE_CFG_ERROR;
- return;
- }
-
- try {
- NetdUtils.tetherInterface(mNetd, mIfaceName, asIpPrefix(mIpv4Address));
- } catch (RemoteException | ServiceSpecificException | IllegalStateException e) {
- mLog.e("Error Tethering", e);
- mLastError = TetheringManager.TETHER_ERROR_TETHER_IFACE_ERROR;
- return;
- }
-
- if (!startIPv6()) {
- mLog.e("Failed to startIPv6");
- // TODO: Make this a fatal error once Bluetooth IPv6 is sorted.
- return;
- }
- }
-
- @Override
- public void exit() {
- // Note that at this point, we're leaving the tethered state. We can fail any
- // of these operations, but it doesn't really change that we have to try them
- // all in sequence.
- stopIPv6();
-
- try {
- NetdUtils.untetherInterface(mNetd, mIfaceName);
- } catch (RemoteException | ServiceSpecificException e) {
- mLastError = TetheringManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
- mLog.e("Failed to untether interface: " + e);
- }
-
- stopIPv4();
-
- resetLinkProperties();
- }
-
- @Override
- public boolean processMessage(Message message) {
- logMessage(this, message.what);
- switch (message.what) {
- case CMD_TETHER_UNREQUESTED:
- transitionTo(mInitialState);
- if (DBG) Log.d(TAG, "Untethered (unrequested)" + mIfaceName);
- break;
- case CMD_INTERFACE_DOWN:
- transitionTo(mUnavailableState);
- if (DBG) Log.d(TAG, "Untethered (ifdown)" + mIfaceName);
- break;
- case CMD_IPV6_TETHER_UPDATE:
- updateUpstreamIPv6LinkProperties((LinkProperties) message.obj, message.arg1);
- sendLinkProperties();
- break;
- case CMD_IP_FORWARDING_ENABLE_ERROR:
- case CMD_IP_FORWARDING_DISABLE_ERROR:
- case CMD_START_TETHERING_ERROR:
- case CMD_STOP_TETHERING_ERROR:
- case CMD_SET_DNS_FORWARDERS_ERROR:
- mLastError = TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
- transitionTo(mInitialState);
- break;
- case CMD_NEW_PREFIX_REQUEST:
- handleNewPrefixRequest((IpPrefix) message.obj);
- break;
- case CMD_NOTIFY_PREFIX_CONFLICT:
- mLog.i("restart tethering: " + mInterfaceType);
- mCallback.requestEnableTethering(mInterfaceType, false /* enabled */);
- transitionTo(mWaitingForRestartState);
- break;
- default:
- return false;
- }
- return true;
- }
- }
-
- // Handling errors in BaseServingState.enter() by transitioning is
- // problematic because transitioning during a multi-state jump yields
- // a Log.wtf(). Ultimately, there should be only one ServingState,
- // and forwarding and NAT rules should be handled by a coordinating
- // functional element outside of IpServer.
- class LocalHotspotState extends BaseServingState {
- @Override
- public void enter() {
- super.enter();
- if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) {
- transitionTo(mInitialState);
- }
-
- if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
- sendInterfaceState(STATE_LOCAL_ONLY);
- }
-
- @Override
- public boolean processMessage(Message message) {
- if (super.processMessage(message)) return true;
-
- logMessage(this, message.what);
- switch (message.what) {
- case CMD_TETHER_REQUESTED:
- mLog.e("CMD_TETHER_REQUESTED while in local-only hotspot mode.");
- break;
- case CMD_TETHER_CONNECTION_CHANGED:
- // Ignored in local hotspot state.
- break;
- default:
- return false;
- }
- return true;
- }
- }
-
- // Handling errors in BaseServingState.enter() by transitioning is
- // problematic because transitioning during a multi-state jump yields
- // a Log.wtf(). Ultimately, there should be only one ServingState,
- // and forwarding and NAT rules should be handled by a coordinating
- // functional element outside of IpServer.
- class TetheredState extends BaseServingState {
- @Override
- public void enter() {
- super.enter();
- if (mLastError != TetheringManager.TETHER_ERROR_NO_ERROR) {
- transitionTo(mInitialState);
- }
-
- if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
- sendInterfaceState(STATE_TETHERED);
- }
-
- @Override
- public void exit() {
- cleanupUpstream();
- super.exit();
- }
-
- private void cleanupUpstream() {
- if (mUpstreamIfaceSet == null) return;
-
- for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
- mUpstreamIfaceSet = null;
- clearIpv6ForwardingRules();
- }
-
- private void cleanupUpstreamInterface(String upstreamIface) {
- // Note that we don't care about errors here.
- // Sometimes interfaces are gone before we get
- // to remove their rules, which generates errors.
- // Just do the best we can.
- try {
- mNetd.ipfwdRemoveInterfaceForward(mIfaceName, upstreamIface);
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e("Exception in ipfwdRemoveInterfaceForward: " + e.toString());
- }
- try {
- mNetd.tetherRemoveForward(mIfaceName, upstreamIface);
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e("Exception in disableNat: " + e.toString());
- }
- }
-
- @Override
- public boolean processMessage(Message message) {
- if (super.processMessage(message)) return true;
-
- logMessage(this, message.what);
- switch (message.what) {
- case CMD_TETHER_REQUESTED:
- mLog.e("CMD_TETHER_REQUESTED while already tethering.");
- break;
- case CMD_TETHER_CONNECTION_CHANGED:
- final InterfaceSet newUpstreamIfaceSet = (InterfaceSet) message.obj;
- if (noChangeInUpstreamIfaceSet(newUpstreamIfaceSet)) {
- if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
- break;
- }
-
- if (newUpstreamIfaceSet == null) {
- cleanupUpstream();
- break;
- }
-
- for (String removed : upstreamInterfacesRemoved(newUpstreamIfaceSet)) {
- cleanupUpstreamInterface(removed);
- }
-
- final Set added = upstreamInterfacesAdd(newUpstreamIfaceSet);
- // This makes the call to cleanupUpstream() in the error
- // path for any interface neatly cleanup all the interfaces.
- mUpstreamIfaceSet = newUpstreamIfaceSet;
-
- for (String ifname : added) {
- try {
- mNetd.tetherAddForward(mIfaceName, ifname);
- mNetd.ipfwdAddInterfaceForward(mIfaceName, ifname);
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e("Exception enabling NAT: " + e.toString());
- cleanupUpstream();
- mLastError = TetheringManager.TETHER_ERROR_ENABLE_FORWARDING_ERROR;
- transitionTo(mInitialState);
- return true;
- }
- }
- break;
- case CMD_NEIGHBOR_EVENT:
- handleNeighborEvent((NeighborEvent) message.obj);
- break;
- default:
- return false;
- }
- return true;
- }
-
- private boolean noChangeInUpstreamIfaceSet(InterfaceSet newIfaces) {
- if (mUpstreamIfaceSet == null && newIfaces == null) return true;
- if (mUpstreamIfaceSet != null && newIfaces != null) {
- return mUpstreamIfaceSet.equals(newIfaces);
- }
- return false;
- }
-
- private Set upstreamInterfacesRemoved(InterfaceSet newIfaces) {
- if (mUpstreamIfaceSet == null) return new HashSet<>();
-
- final HashSet removed = new HashSet<>(mUpstreamIfaceSet.ifnames);
- removed.removeAll(newIfaces.ifnames);
- return removed;
- }
-
- private Set upstreamInterfacesAdd(InterfaceSet newIfaces) {
- final HashSet added = new HashSet<>(newIfaces.ifnames);
- if (mUpstreamIfaceSet != null) added.removeAll(mUpstreamIfaceSet.ifnames);
- return added;
- }
- }
-
- /**
- * This state is terminal for the per interface state machine. At this
- * point, the tethering main state machine should have removed this interface
- * specific state machine from its list of possible recipients of
- * tethering requests. The state machine itself will hang around until
- * the garbage collector finds it.
- */
- class UnavailableState extends State {
- @Override
- public void enter() {
- mIpNeighborMonitor.stop();
- mLastError = TetheringManager.TETHER_ERROR_NO_ERROR;
- sendInterfaceState(STATE_UNAVAILABLE);
- }
- }
-
- class WaitingForRestartState extends State {
- @Override
- public boolean processMessage(Message message) {
- logMessage(this, message.what);
- switch (message.what) {
- case CMD_TETHER_UNREQUESTED:
- transitionTo(mInitialState);
- mLog.i("Untethered (unrequested) and restarting " + mIfaceName);
- mCallback.requestEnableTethering(mInterfaceType, true /* enabled */);
- break;
- case CMD_INTERFACE_DOWN:
- transitionTo(mUnavailableState);
- mLog.i("Untethered (interface down) and restarting" + mIfaceName);
- mCallback.requestEnableTethering(mInterfaceType, true /* enabled */);
- break;
- default:
- return false;
- }
- return true;
- }
- }
-
- // Accumulate routes representing "prefixes to be assigned to the local
- // interface", for subsequent modification of local_network routing.
- private static ArrayList getLocalRoutesFor(
- String ifname, HashSet prefixes) {
- final ArrayList localRoutes = new ArrayList();
- for (IpPrefix ipp : prefixes) {
- localRoutes.add(new RouteInfo(ipp, null, ifname, RTN_UNICAST));
- }
- return localRoutes;
- }
-
- // Given a prefix like 2001:db8::/64 return an address like 2001:db8::1.
- private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) {
- final byte[] dnsBytes = localPrefix.getRawAddress();
- dnsBytes[dnsBytes.length - 1] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1));
- try {
- return Inet6Address.getByAddress(null, dnsBytes, 0);
- } catch (UnknownHostException e) {
- Log.wtf(TAG, "Failed to construct Inet6Address from: " + localPrefix);
- return null;
- }
- }
-
- private static byte getRandomSanitizedByte(byte dflt, byte... excluded) {
- final byte random = (byte) (new Random()).nextInt();
- for (int value : excluded) {
- if (random == value) return dflt;
- }
- return random;
- }
-}
diff --git a/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java b/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
deleted file mode 100644
index 73fc833fabf50..0000000000000
--- a/packages/Tethering/src/android/net/ip/NeighborPacketForwarder.java
+++ /dev/null
@@ -1,180 +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 android.net.ip;
-
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.AF_PACKET;
-import static android.system.OsConstants.ETH_P_IPV6;
-import static android.system.OsConstants.IPPROTO_RAW;
-import static android.system.OsConstants.SOCK_DGRAM;
-import static android.system.OsConstants.SOCK_NONBLOCK;
-import static android.system.OsConstants.SOCK_RAW;
-
-import android.net.util.InterfaceParams;
-import android.net.util.PacketReader;
-import android.net.util.SocketUtils;
-import android.net.util.TetheringUtils;
-import android.os.Handler;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.util.Log;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.Inet6Address;
-import java.net.InetSocketAddress;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-
-/**
- * Basic IPv6 Neighbor Advertisement Forwarder.
- *
- * Forward NA packets from upstream iface to tethered iface
- * and NS packets from tethered iface to upstream iface.
- *
- * @hide
- */
-public class NeighborPacketForwarder extends PacketReader {
- private final String mTag;
-
- private FileDescriptor mFd;
-
- // TODO: get these from NetworkStackConstants.
- private static final int IPV6_ADDR_LEN = 16;
- private static final int IPV6_DST_ADDR_OFFSET = 24;
- private static final int IPV6_HEADER_LEN = 40;
- private static final int ETH_HEADER_LEN = 14;
-
- private InterfaceParams mListenIfaceParams, mSendIfaceParams;
-
- private final int mType;
- public static final int ICMPV6_NEIGHBOR_ADVERTISEMENT = 136;
- public static final int ICMPV6_NEIGHBOR_SOLICITATION = 135;
-
- public NeighborPacketForwarder(Handler h, InterfaceParams tetheredInterface, int type) {
- super(h);
- mTag = NeighborPacketForwarder.class.getSimpleName() + "-"
- + tetheredInterface.name + "-" + type;
- mType = type;
-
- if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
- mSendIfaceParams = tetheredInterface;
- } else {
- mListenIfaceParams = tetheredInterface;
- }
- }
-
- /** Set new upstream iface and start/stop based on new params. */
- public void setUpstreamIface(InterfaceParams upstreamParams) {
- final InterfaceParams oldUpstreamParams;
-
- if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
- oldUpstreamParams = mListenIfaceParams;
- mListenIfaceParams = upstreamParams;
- } else {
- oldUpstreamParams = mSendIfaceParams;
- mSendIfaceParams = upstreamParams;
- }
-
- if (oldUpstreamParams == null && upstreamParams != null) {
- start();
- } else if (oldUpstreamParams != null && upstreamParams == null) {
- stop();
- } else if (oldUpstreamParams != null && upstreamParams != null
- && oldUpstreamParams.index != upstreamParams.index) {
- stop();
- start();
- }
- }
-
- // TODO: move NetworkStackUtils.closeSocketQuietly to
- // frameworks/libs/net/common/device/com/android/net/module/util/[someclass].
- private void closeSocketQuietly(FileDescriptor fd) {
- try {
- SocketUtils.closeSocket(fd);
- } catch (IOException ignored) {
- }
- }
-
- @Override
- protected FileDescriptor createFd() {
- try {
- // ICMPv6 packets from modem do not have eth header, so RAW socket cannot be used.
- // To keep uniformity in both directions PACKET socket can be used.
- mFd = Os.socket(AF_PACKET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
-
- // TODO: convert setup*Socket to setupICMPv6BpfFilter with filter type?
- if (mType == ICMPV6_NEIGHBOR_ADVERTISEMENT) {
- TetheringUtils.setupNaSocket(mFd);
- } else if (mType == ICMPV6_NEIGHBOR_SOLICITATION) {
- TetheringUtils.setupNsSocket(mFd);
- }
-
- SocketAddress bindAddress = SocketUtils.makePacketSocketAddress(
- ETH_P_IPV6, mListenIfaceParams.index);
- Os.bind(mFd, bindAddress);
- } catch (ErrnoException | SocketException e) {
- Log.wtf(mTag, "Failed to create socket", e);
- closeSocketQuietly(mFd);
- return null;
- }
-
- return mFd;
- }
-
- private Inet6Address getIpv6DestinationAddress(byte[] recvbuf) {
- Inet6Address dstAddr;
- try {
- dstAddr = (Inet6Address) Inet6Address.getByAddress(Arrays.copyOfRange(recvbuf,
- IPV6_DST_ADDR_OFFSET, IPV6_DST_ADDR_OFFSET + IPV6_ADDR_LEN));
- } catch (UnknownHostException | ClassCastException impossible) {
- throw new AssertionError("16-byte array not valid IPv6 address?");
- }
- return dstAddr;
- }
-
- @Override
- protected void handlePacket(byte[] recvbuf, int length) {
- if (mSendIfaceParams == null) {
- return;
- }
-
- // The BPF filter should already have checked the length of the packet, but...
- if (length < IPV6_HEADER_LEN) {
- return;
- }
- Inet6Address destv6 = getIpv6DestinationAddress(recvbuf);
- if (!destv6.isMulticastAddress()) {
- return;
- }
- InetSocketAddress dest = new InetSocketAddress(destv6, 0);
-
- FileDescriptor fd = null;
- try {
- fd = Os.socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_RAW);
- SocketUtils.bindSocketToInterface(fd, mSendIfaceParams.name);
-
- int ret = Os.sendto(fd, recvbuf, 0, length, 0, dest);
- } catch (ErrnoException | SocketException e) {
- Log.e(mTag, "handlePacket error: " + e);
- } finally {
- closeSocketQuietly(fd);
- }
- }
-}
diff --git a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
deleted file mode 100644
index 7c0b7cc7515c2..0000000000000
--- a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java
+++ /dev/null
@@ -1,744 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.net.ip;
-
-import static android.net.util.NetworkConstants.IPV6_MIN_MTU;
-import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
-import static android.net.util.TetheringUtils.getAllNodesForScopeId;
-import static android.system.OsConstants.AF_INET6;
-import static android.system.OsConstants.IPPROTO_ICMPV6;
-import static android.system.OsConstants.SOCK_RAW;
-import static android.system.OsConstants.SOL_SOCKET;
-import static android.system.OsConstants.SO_SNDTIMEO;
-
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.TrafficStats;
-import android.net.util.InterfaceParams;
-import android.net.util.SocketUtils;
-import android.net.util.TetheringUtils;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.StructTimeval;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.TrafficStatsConstants;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.InetSocketAddress;
-import java.net.SocketException;
-import java.nio.BufferOverflowException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Random;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicInteger;
-
-
-/**
- * Basic IPv6 Router Advertisement Daemon.
- *
- * TODO:
- *
- * - Rewrite using Handler (and friends) so that AlarmManager can deliver
- * "kick" messages when it's time to send a multicast RA.
- *
- * @hide
- */
-public class RouterAdvertisementDaemon {
- private static final String TAG = RouterAdvertisementDaemon.class.getSimpleName();
- private static final byte ICMPV6_ND_ROUTER_SOLICIT = asByte(133);
- private static final byte ICMPV6_ND_ROUTER_ADVERT = asByte(134);
- private static final int MIN_RA_HEADER_SIZE = 16;
-
- // Summary of various timers and lifetimes.
- private static final int MIN_RTR_ADV_INTERVAL_SEC = 300;
- private static final int MAX_RTR_ADV_INTERVAL_SEC = 600;
- // In general, router, prefix, and DNS lifetimes are all advised to be
- // greater than or equal to 3 * MAX_RTR_ADV_INTERVAL. Here, we double
- // that to allow for multicast packet loss.
- //
- // This MAX_RTR_ADV_INTERVAL_SEC and DEFAULT_LIFETIME are also consistent
- // with the https://tools.ietf.org/html/rfc7772#section-4 discussion of
- // "approximately 7 RAs per hour".
- private static final int DEFAULT_LIFETIME = 6 * MAX_RTR_ADV_INTERVAL_SEC;
- // From https://tools.ietf.org/html/rfc4861#section-10 .
- private static final int MIN_DELAY_BETWEEN_RAS_SEC = 3;
- // Both initial and final RAs, but also for changes in RA contents.
- // From https://tools.ietf.org/html/rfc4861#section-10 .
- private static final int MAX_URGENT_RTR_ADVERTISEMENTS = 5;
-
- private static final int DAY_IN_SECONDS = 86_400;
-
- private final InterfaceParams mInterface;
- private final InetSocketAddress mAllNodes;
-
- // This lock is to protect the RA from being updated while being
- // transmitted on another thread (multicast or unicast).
- //
- // TODO: This should be handled with a more RCU-like approach.
- private final Object mLock = new Object();
- @GuardedBy("mLock")
- private final byte[] mRA = new byte[IPV6_MIN_MTU];
- @GuardedBy("mLock")
- private int mRaLength;
- @GuardedBy("mLock")
- private final DeprecatedInfoTracker mDeprecatedInfoTracker;
- @GuardedBy("mLock")
- private RaParams mRaParams;
-
- private volatile FileDescriptor mSocket;
- private volatile MulticastTransmitter mMulticastTransmitter;
- private volatile UnicastResponder mUnicastResponder;
-
- /** Encapsulate the RA parameters for RouterAdvertisementDaemon.*/
- public static class RaParams {
- // Tethered traffic will have the hop limit properly decremented.
- // Consequently, set the hoplimit greater by one than the upstream
- // unicast hop limit.
- //
- // TODO: Dynamically pass down the IPV6_UNICAST_HOPS value from the
- // upstream interface for more correct behaviour.
- static final byte DEFAULT_HOPLIMIT = 65;
-
- public boolean hasDefaultRoute;
- public byte hopLimit;
- public int mtu;
- public HashSet prefixes;
- public HashSet dnses;
-
- public RaParams() {
- hasDefaultRoute = false;
- hopLimit = DEFAULT_HOPLIMIT;
- mtu = IPV6_MIN_MTU;
- prefixes = new HashSet();
- dnses = new HashSet();
- }
-
- public RaParams(RaParams other) {
- hasDefaultRoute = other.hasDefaultRoute;
- hopLimit = other.hopLimit;
- mtu = other.mtu;
- prefixes = (HashSet) other.prefixes.clone();
- dnses = (HashSet) other.dnses.clone();
- }
-
- /**
- * Returns the subset of RA parameters that become deprecated when
- * moving from announcing oldRa to announcing newRa.
- *
- * Currently only tracks differences in |prefixes| and |dnses|.
- */
- public static RaParams getDeprecatedRaParams(RaParams oldRa, RaParams newRa) {
- RaParams newlyDeprecated = new RaParams();
-
- if (oldRa != null) {
- for (IpPrefix ipp : oldRa.prefixes) {
- if (newRa == null || !newRa.prefixes.contains(ipp)) {
- newlyDeprecated.prefixes.add(ipp);
- }
- }
-
- for (Inet6Address dns : oldRa.dnses) {
- if (newRa == null || !newRa.dnses.contains(dns)) {
- newlyDeprecated.dnses.add(dns);
- }
- }
- }
-
- return newlyDeprecated;
- }
- }
-
- private static class DeprecatedInfoTracker {
- private final HashMap mPrefixes = new HashMap<>();
- private final HashMap mDnses = new HashMap<>();
-
- Set getPrefixes() {
- return mPrefixes.keySet();
- }
-
- void putPrefixes(Set prefixes) {
- for (IpPrefix ipp : prefixes) {
- mPrefixes.put(ipp, MAX_URGENT_RTR_ADVERTISEMENTS);
- }
- }
-
- void removePrefixes(Set prefixes) {
- for (IpPrefix ipp : prefixes) {
- mPrefixes.remove(ipp);
- }
- }
-
- Set getDnses() {
- return mDnses.keySet();
- }
-
- void putDnses(Set dnses) {
- for (Inet6Address dns : dnses) {
- mDnses.put(dns, MAX_URGENT_RTR_ADVERTISEMENTS);
- }
- }
-
- void removeDnses(Set dnses) {
- for (Inet6Address dns : dnses) {
- mDnses.remove(dns);
- }
- }
-
- boolean isEmpty() {
- return mPrefixes.isEmpty() && mDnses.isEmpty();
- }
-
- private boolean decrementCounters() {
- boolean removed = decrementCounter(mPrefixes);
- removed |= decrementCounter(mDnses);
- return removed;
- }
-
- private boolean decrementCounter(HashMap map) {
- boolean removed = false;
-
- for (Iterator> it = map.entrySet().iterator();
- it.hasNext();) {
- Map.Entry kv = it.next();
- if (kv.getValue() == 0) {
- it.remove();
- removed = true;
- } else {
- kv.setValue(kv.getValue() - 1);
- }
- }
-
- return removed;
- }
- }
-
- public RouterAdvertisementDaemon(InterfaceParams ifParams) {
- mInterface = ifParams;
- mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0);
- mDeprecatedInfoTracker = new DeprecatedInfoTracker();
- }
-
- /** Build new RA.*/
- public void buildNewRa(RaParams deprecatedParams, RaParams newParams) {
- synchronized (mLock) {
- if (deprecatedParams != null) {
- mDeprecatedInfoTracker.putPrefixes(deprecatedParams.prefixes);
- mDeprecatedInfoTracker.putDnses(deprecatedParams.dnses);
- }
-
- if (newParams != null) {
- // Process information that is no longer deprecated.
- mDeprecatedInfoTracker.removePrefixes(newParams.prefixes);
- mDeprecatedInfoTracker.removeDnses(newParams.dnses);
- }
-
- mRaParams = newParams;
- assembleRaLocked();
- }
-
- maybeNotifyMulticastTransmitter();
- }
-
- /** Start router advertisement daemon. */
- public boolean start() {
- if (!createSocket()) {
- return false;
- }
-
- mMulticastTransmitter = new MulticastTransmitter();
- mMulticastTransmitter.start();
-
- mUnicastResponder = new UnicastResponder();
- mUnicastResponder.start();
-
- return true;
- }
-
- /** Stop router advertisement daemon. */
- public void stop() {
- closeSocket();
- // Wake up mMulticastTransmitter thread to interrupt a potential 1 day sleep before
- // the thread's termination.
- maybeNotifyMulticastTransmitter();
- mMulticastTransmitter = null;
- mUnicastResponder = null;
- }
-
- @GuardedBy("mLock")
- private void assembleRaLocked() {
- final ByteBuffer ra = ByteBuffer.wrap(mRA);
- ra.order(ByteOrder.BIG_ENDIAN);
-
- final boolean haveRaParams = (mRaParams != null);
- boolean shouldSendRA = false;
-
- try {
- putHeader(ra, haveRaParams && mRaParams.hasDefaultRoute,
- haveRaParams ? mRaParams.hopLimit : RaParams.DEFAULT_HOPLIMIT);
- putSlla(ra, mInterface.macAddr.toByteArray());
- mRaLength = ra.position();
-
- // https://tools.ietf.org/html/rfc5175#section-4 says:
- //
- // "MUST NOT be added to a Router Advertisement message
- // if no flags in the option are set."
- //
- // putExpandedFlagsOption(ra);
-
- if (haveRaParams) {
- putMtu(ra, mRaParams.mtu);
- mRaLength = ra.position();
-
- for (IpPrefix ipp : mRaParams.prefixes) {
- putPio(ra, ipp, DEFAULT_LIFETIME, DEFAULT_LIFETIME);
- mRaLength = ra.position();
- shouldSendRA = true;
- }
-
- if (mRaParams.dnses.size() > 0) {
- putRdnss(ra, mRaParams.dnses, DEFAULT_LIFETIME);
- mRaLength = ra.position();
- shouldSendRA = true;
- }
- }
-
- for (IpPrefix ipp : mDeprecatedInfoTracker.getPrefixes()) {
- putPio(ra, ipp, 0, 0);
- mRaLength = ra.position();
- shouldSendRA = true;
- }
-
- final Set deprecatedDnses = mDeprecatedInfoTracker.getDnses();
- if (!deprecatedDnses.isEmpty()) {
- putRdnss(ra, deprecatedDnses, 0);
- mRaLength = ra.position();
- shouldSendRA = true;
- }
- } catch (BufferOverflowException e) {
- // The packet up to mRaLength is valid, since it has been updated
- // progressively as the RA was built. Log an error, and continue
- // on as best as possible.
- Log.e(TAG, "Could not construct new RA: " + e);
- }
-
- // We have nothing worth announcing; indicate as much to maybeSendRA().
- if (!shouldSendRA) {
- mRaLength = 0;
- }
- }
-
- private void maybeNotifyMulticastTransmitter() {
- final MulticastTransmitter m = mMulticastTransmitter;
- if (m != null) {
- m.hup();
- }
- }
-
- private static byte asByte(int value) {
- return (byte) value;
- }
- private static short asShort(int value) {
- return (short) value;
- }
-
- private static void putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit) {
- /**
- Router Advertisement Message Format
-
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Type | Code | Checksum |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Cur Hop Limit |M|O|H|Prf|P|R|R| Router Lifetime |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Reachable Time |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Retrans Timer |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Options ...
- +-+-+-+-+-+-+-+-+-+-+-+-
- */
- ra.put(ICMPV6_ND_ROUTER_ADVERT)
- .put(asByte(0))
- .putShort(asShort(0))
- .put(hopLimit)
- // RFC 4191 "high" preference, iff. advertising a default route.
- .put(hasDefaultRoute ? asByte(0x08) : asByte(0))
- .putShort(hasDefaultRoute ? asShort(DEFAULT_LIFETIME) : asShort(0))
- .putInt(0)
- .putInt(0);
- }
-
- private static void putSlla(ByteBuffer ra, byte[] slla) {
- /**
- Source/Target Link-layer Address
-
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Type | Length | Link-Layer Address ...
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- if (slla == null || slla.length != 6) {
- // Only IEEE 802.3 6-byte addresses are supported.
- return;
- }
-
- final byte nd_option_slla = 1;
- final byte slla_num_8octets = 1;
- ra.put(nd_option_slla)
- .put(slla_num_8octets)
- .put(slla);
- }
-
- private static void putExpandedFlagsOption(ByteBuffer ra) {
- /**
- Router Advertisement Expanded Flags Option
-
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Type | Length | Bit fields available ..
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- ... for assignment |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
-
- final byte nd_option__efo = 26;
- final byte efo_num_8octets = 1;
-
- ra.put(nd_option__efo)
- .put(efo_num_8octets)
- .putShort(asShort(0))
- .putInt(0);
- }
-
- private static void putMtu(ByteBuffer ra, int mtu) {
- /**
- MTU
-
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Type | Length | Reserved |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | MTU |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- final byte nd_option_mtu = 5;
- final byte mtu_num_8octs = 1;
- ra.put(nd_option_mtu)
- .put(mtu_num_8octs)
- .putShort(asShort(0))
- .putInt((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu);
- }
-
- private static void putPio(ByteBuffer ra, IpPrefix ipp,
- int validTime, int preferredTime) {
- /**
- Prefix Information
-
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Type | Length | Prefix Length |L|A| Reserved1 |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Valid Lifetime |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Preferred Lifetime |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Reserved2 |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | |
- + +
- | |
- + Prefix +
- | |
- + +
- | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- final int prefixLength = ipp.getPrefixLength();
- if (prefixLength != 64) {
- return;
- }
- final byte nd_option_pio = 3;
- final byte pio_num_8octets = 4;
-
- if (validTime < 0) validTime = 0;
- if (preferredTime < 0) preferredTime = 0;
- if (preferredTime > validTime) preferredTime = validTime;
-
- final byte[] addr = ipp.getAddress().getAddress();
- ra.put(nd_option_pio)
- .put(pio_num_8octets)
- .put(asByte(prefixLength))
- .put(asByte(0xc0)) /* L & A set */
- .putInt(validTime)
- .putInt(preferredTime)
- .putInt(0)
- .put(addr);
- }
-
- private static void putRio(ByteBuffer ra, IpPrefix ipp) {
- /**
- Route Information Option
-
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Type | Length | Prefix Length |Resvd|Prf|Resvd|
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Route Lifetime |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Prefix (Variable Length) |
- . .
- . .
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
- final int prefixLength = ipp.getPrefixLength();
- if (prefixLength > 64) {
- return;
- }
- final byte nd_option_rio = 24;
- final byte rio_num_8octets = asByte(
- (prefixLength == 0) ? 1 : (prefixLength <= 8) ? 2 : 3);
-
- final byte[] addr = ipp.getAddress().getAddress();
- ra.put(nd_option_rio)
- .put(rio_num_8octets)
- .put(asByte(prefixLength))
- .put(asByte(0x18))
- .putInt(DEFAULT_LIFETIME);
-
- // Rely upon an IpPrefix's address being properly zeroed.
- if (prefixLength > 0) {
- ra.put(addr, 0, (prefixLength <= 64) ? 8 : 16);
- }
- }
-
- private static void putRdnss(ByteBuffer ra, Set dnses, int lifetime) {
- /**
- Recursive DNS Server (RDNSS) Option
-
- 0 1 2 3
- 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Type | Length | Reserved |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | Lifetime |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- | |
- : Addresses of IPv6 Recursive DNS Servers :
- | |
- +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- */
-
- final HashSet filteredDnses = new HashSet<>();
- for (Inet6Address dns : dnses) {
- if ((new LinkAddress(dns, RFC7421_PREFIX_LENGTH)).isGlobalPreferred()) {
- filteredDnses.add(dns);
- }
- }
- if (filteredDnses.isEmpty()) return;
-
- final byte nd_option_rdnss = 25;
- final byte rdnss_num_8octets = asByte(dnses.size() * 2 + 1);
- ra.put(nd_option_rdnss)
- .put(rdnss_num_8octets)
- .putShort(asShort(0))
- .putInt(lifetime);
-
- for (Inet6Address dns : filteredDnses) {
- // NOTE: If the full of list DNS servers doesn't fit in the packet,
- // this code will cause a buffer overflow and the RA won't include
- // this instance of the option at all.
- //
- // TODO: Consider looking at ra.remaining() to determine how many
- // DNS servers will fit, and adding only those.
- ra.put(dns.getAddress());
- }
- }
-
- private boolean createSocket() {
- final int send_timout_ms = 300;
-
- final int oldTag = TrafficStats.getAndSetThreadStatsTag(
- TrafficStatsConstants.TAG_SYSTEM_NEIGHBOR);
- try {
- mSocket = Os.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
- // Setting SNDTIMEO is purely for defensive purposes.
- Os.setsockoptTimeval(
- mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(send_timout_ms));
- SocketUtils.bindSocketToInterface(mSocket, mInterface.name);
- TetheringUtils.setupRaSocket(mSocket, mInterface.index);
- } catch (ErrnoException | IOException e) {
- Log.e(TAG, "Failed to create RA daemon socket: " + e);
- return false;
- } finally {
- TrafficStats.setThreadStatsTag(oldTag);
- }
-
- return true;
- }
-
- private void closeSocket() {
- if (mSocket != null) {
- try {
- SocketUtils.closeSocket(mSocket);
- } catch (IOException ignored) { }
- }
- mSocket = null;
- }
-
- private boolean isSocketValid() {
- final FileDescriptor s = mSocket;
- return (s != null) && s.valid();
- }
-
- private boolean isSuitableDestination(InetSocketAddress dest) {
- if (mAllNodes.equals(dest)) {
- return true;
- }
-
- final InetAddress destip = dest.getAddress();
- return (destip instanceof Inet6Address)
- && destip.isLinkLocalAddress()
- && (((Inet6Address) destip).getScopeId() == mInterface.index);
- }
-
- private void maybeSendRA(InetSocketAddress dest) {
- if (dest == null || !isSuitableDestination(dest)) {
- dest = mAllNodes;
- }
-
- try {
- synchronized (mLock) {
- if (mRaLength < MIN_RA_HEADER_SIZE) {
- // No actual RA to send.
- return;
- }
- Os.sendto(mSocket, mRA, 0, mRaLength, 0, dest);
- }
- Log.d(TAG, "RA sendto " + dest.getAddress().getHostAddress());
- } catch (ErrnoException | SocketException e) {
- if (isSocketValid()) {
- Log.e(TAG, "sendto error: " + e);
- }
- }
- }
-
- private final class UnicastResponder extends Thread {
- private final InetSocketAddress mSolicitor = new InetSocketAddress(0);
- // The recycled buffer for receiving Router Solicitations from clients.
- // If the RS is larger than IPV6_MIN_MTU the packets are truncated.
- // This is fine since currently only byte 0 is examined anyway.
- private final byte[] mSolicitation = new byte[IPV6_MIN_MTU];
-
- @Override
- public void run() {
- while (isSocketValid()) {
- try {
- // Blocking receive.
- final int rval = Os.recvfrom(
- mSocket, mSolicitation, 0, mSolicitation.length, 0, mSolicitor);
- // Do the least possible amount of validation.
- if (rval < 1 || mSolicitation[0] != ICMPV6_ND_ROUTER_SOLICIT) {
- continue;
- }
- } catch (ErrnoException | SocketException e) {
- if (isSocketValid()) {
- Log.e(TAG, "recvfrom error: " + e);
- }
- continue;
- }
-
- maybeSendRA(mSolicitor);
- }
- }
- }
-
- // TODO: Consider moving this to run on a provided Looper as a Handler,
- // with WakeupMessage-style messages providing the timer driven input.
- private final class MulticastTransmitter extends Thread {
- private final Random mRandom = new Random();
- private final AtomicInteger mUrgentAnnouncements = new AtomicInteger(0);
-
- @Override
- public void run() {
- while (isSocketValid()) {
- try {
- Thread.sleep(getNextMulticastTransmitDelayMs());
- } catch (InterruptedException ignored) {
- // Stop sleeping, immediately send an RA, and continue.
- }
-
- maybeSendRA(mAllNodes);
- synchronized (mLock) {
- if (mDeprecatedInfoTracker.decrementCounters()) {
- // At least one deprecated PIO has been removed;
- // reassemble the RA.
- assembleRaLocked();
- }
- }
- }
- }
-
- public void hup() {
- // Set to one fewer that the desired number, because as soon as
- // the thread interrupt is processed we immediately send an RA
- // and mUrgentAnnouncements is not examined until the subsequent
- // sleep interval computation (i.e. this way we send 3 and not 4).
- mUrgentAnnouncements.set(MAX_URGENT_RTR_ADVERTISEMENTS - 1);
- interrupt();
- }
-
- private int getNextMulticastTransmitDelaySec() {
- boolean deprecationInProgress = false;
- synchronized (mLock) {
- if (mRaLength < MIN_RA_HEADER_SIZE) {
- // No actual RA to send; just sleep for 1 day.
- return DAY_IN_SECONDS;
- }
- deprecationInProgress = !mDeprecatedInfoTracker.isEmpty();
- }
-
- final int urgentPending = mUrgentAnnouncements.getAndDecrement();
- if ((urgentPending > 0) || deprecationInProgress) {
- return MIN_DELAY_BETWEEN_RAS_SEC;
- }
-
- return MIN_RTR_ADV_INTERVAL_SEC + mRandom.nextInt(
- MAX_RTR_ADV_INTERVAL_SEC - MIN_RTR_ADV_INTERVAL_SEC);
- }
-
- private long getNextMulticastTransmitDelayMs() {
- return 1000 * (long) getNextMulticastTransmitDelaySec();
- }
- }
-}
diff --git a/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java b/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java
deleted file mode 100644
index b1ffdb01f5f30..0000000000000
--- a/packages/Tethering/src/android/net/util/BaseNetdUnsolicitedEventListener.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.util;
-
-import android.net.INetdUnsolicitedEventListener;
-
-import androidx.annotation.NonNull;
-
-/**
- * Base {@link INetdUnsolicitedEventListener} that provides no-op implementations which can be
- * overridden.
- */
-public class BaseNetdUnsolicitedEventListener extends INetdUnsolicitedEventListener.Stub {
-
- @Override
- public void onInterfaceClassActivityChanged(boolean isActive, int timerLabel, long timestampNs,
- int uid) { }
-
- @Override
- public void onQuotaLimitReached(@NonNull String alertName, @NonNull String ifName) { }
-
- @Override
- public void onInterfaceDnsServerInfo(@NonNull String ifName, long lifetimeS,
- @NonNull String[] servers) { }
-
- @Override
- public void onInterfaceAddressUpdated(@NonNull String addr, String ifName, int flags,
- int scope) { }
-
- @Override
- public void onInterfaceAddressRemoved(@NonNull String addr, @NonNull String ifName, int flags,
- int scope) { }
-
- @Override
- public void onInterfaceAdded(@NonNull String ifName) { }
-
- @Override
- public void onInterfaceRemoved(@NonNull String ifName) { }
-
- @Override
- public void onInterfaceChanged(@NonNull String ifName, boolean up) { }
-
- @Override
- public void onInterfaceLinkStateChanged(@NonNull String ifName, boolean up) { }
-
- @Override
- public void onRouteChanged(boolean updated, @NonNull String route, @NonNull String gateway,
- @NonNull String ifName) { }
-
- @Override
- public void onStrictCleartextDetected(int uid, @NonNull String hex) { }
-
- @Override
- public int getInterfaceVersion() {
- return INetdUnsolicitedEventListener.VERSION;
- }
-
- @Override
- public String getInterfaceHash() {
- return INetdUnsolicitedEventListener.HASH;
- }
-}
diff --git a/packages/Tethering/src/android/net/util/InterfaceSet.java b/packages/Tethering/src/android/net/util/InterfaceSet.java
deleted file mode 100644
index 758978711bd47..0000000000000
--- a/packages/Tethering/src/android/net/util/InterfaceSet.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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 android.net.util;
-
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-import java.util.StringJoiner;
-
-
-/**
- * @hide
- */
-public class InterfaceSet {
- public final Set ifnames;
-
- public InterfaceSet(String... names) {
- final Set nameSet = new HashSet<>();
- for (String name : names) {
- if (name != null) nameSet.add(name);
- }
- ifnames = Collections.unmodifiableSet(nameSet);
- }
-
- @Override
- public String toString() {
- final StringJoiner sj = new StringJoiner(",", "[", "]");
- for (String ifname : ifnames) sj.add(ifname);
- return sj.toString();
- }
-
- @Override
- public boolean equals(Object obj) {
- return obj != null
- && obj instanceof InterfaceSet
- && ifnames.equals(((InterfaceSet) obj).ifnames);
- }
-}
diff --git a/packages/Tethering/src/android/net/util/PrefixUtils.java b/packages/Tethering/src/android/net/util/PrefixUtils.java
deleted file mode 100644
index f203e9995f3d9..0000000000000
--- a/packages/Tethering/src/android/net/util/PrefixUtils.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2017 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 android.net.util;
-
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Set;
-
-
-/**
- * @hide
- */
-public class PrefixUtils {
- private static final IpPrefix[] MIN_NON_FORWARDABLE_PREFIXES = {
- pfx("127.0.0.0/8"), // IPv4 loopback
- pfx("169.254.0.0/16"), // IPv4 link-local, RFC3927#section-8
- pfx("::/3"),
- pfx("fe80::/64"), // IPv6 link-local
- pfx("fc00::/7"), // IPv6 ULA
- pfx("ff02::/8"), // IPv6 link-local multicast
- };
-
- public static final IpPrefix DEFAULT_WIFI_P2P_PREFIX = pfx("192.168.49.0/24");
-
- /** Get non forwardable prefixes. */
- public static Set getNonForwardablePrefixes() {
- final HashSet prefixes = new HashSet<>();
- addNonForwardablePrefixes(prefixes);
- return prefixes;
- }
-
- /** Add non forwardable prefixes. */
- public static void addNonForwardablePrefixes(Set prefixes) {
- Collections.addAll(prefixes, MIN_NON_FORWARDABLE_PREFIXES);
- }
-
- /** Get local prefixes from |lp|. */
- public static Set localPrefixesFrom(LinkProperties lp) {
- final HashSet localPrefixes = new HashSet<>();
- if (lp == null) return localPrefixes;
-
- for (LinkAddress addr : lp.getAllLinkAddresses()) {
- if (addr.getAddress().isLinkLocalAddress()) continue;
- localPrefixes.add(asIpPrefix(addr));
- }
- // TODO: Add directly-connected routes as well (ones from which we did
- // not also form a LinkAddress)?
-
- return localPrefixes;
- }
-
- /** Convert LinkAddress |addr| to IpPrefix. */
- public static IpPrefix asIpPrefix(LinkAddress addr) {
- return new IpPrefix(addr.getAddress(), addr.getPrefixLength());
- }
-
- /** Convert InetAddress |ip| to IpPrefix. */
- public static IpPrefix ipAddressAsPrefix(InetAddress ip) {
- final int bitLength = (ip instanceof Inet4Address)
- ? NetworkConstants.IPV4_ADDR_BITS
- : NetworkConstants.IPV6_ADDR_BITS;
- return new IpPrefix(ip, bitLength);
- }
-
- private static IpPrefix pfx(String prefixStr) {
- return new IpPrefix(prefixStr);
- }
-}
diff --git a/packages/Tethering/src/android/net/util/TetheringMessageBase.java b/packages/Tethering/src/android/net/util/TetheringMessageBase.java
deleted file mode 100644
index 29c0a817b6f4a..0000000000000
--- a/packages/Tethering/src/android/net/util/TetheringMessageBase.java
+++ /dev/null
@@ -1,25 +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 android.net.util;
-
-/**
- * This class defines Message.what base addresses for various state machine.
- */
-public class TetheringMessageBase {
- public static final int BASE_MAIN_SM = 0;
- public static final int BASE_IPSERVER = 100;
-
-}
diff --git a/packages/Tethering/src/android/net/util/TetheringUtils.java b/packages/Tethering/src/android/net/util/TetheringUtils.java
deleted file mode 100644
index 53b54f7de05de..0000000000000
--- a/packages/Tethering/src/android/net/util/TetheringUtils.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.util;
-
-import android.net.TetherStatsParcel;
-import android.net.TetheringRequestParcel;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-
-import java.io.FileDescriptor;
-import java.net.Inet6Address;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.util.Arrays;
-import java.util.Objects;
-
-/**
- * The classes and the methods for tethering utilization.
- *
- * {@hide}
- */
-public class TetheringUtils {
- public static final byte[] ALL_NODES = new byte[] {
- (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
- };
-
- /**
- * Configures a socket for receiving and sending ICMPv6 neighbor advertisments.
- * @param fd the socket's {@link FileDescriptor}.
- */
- public static native void setupNaSocket(FileDescriptor fd)
- throws SocketException;
-
- /**
- * Configures a socket for receiving and sending ICMPv6 neighbor solicitations.
- * @param fd the socket's {@link FileDescriptor}.
- */
- public static native void setupNsSocket(FileDescriptor fd)
- throws SocketException;
-
- /**
- * The object which records offload Tx/Rx forwarded bytes/packets.
- * TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with
- * this class as well.
- */
- public static class ForwardedStats {
- public final long rxBytes;
- public final long rxPackets;
- public final long txBytes;
- public final long txPackets;
-
- public ForwardedStats() {
- rxBytes = 0;
- rxPackets = 0;
- txBytes = 0;
- txPackets = 0;
- }
-
- public ForwardedStats(long rxBytes, long txBytes) {
- this.rxBytes = rxBytes;
- this.rxPackets = 0;
- this.txBytes = txBytes;
- this.txPackets = 0;
- }
-
- public ForwardedStats(long rxBytes, long rxPackets, long txBytes, long txPackets) {
- this.rxBytes = rxBytes;
- this.rxPackets = rxPackets;
- this.txBytes = txBytes;
- this.txPackets = txPackets;
- }
-
- public ForwardedStats(@NonNull TetherStatsParcel tetherStats) {
- rxBytes = tetherStats.rxBytes;
- rxPackets = tetherStats.rxPackets;
- txBytes = tetherStats.txBytes;
- txPackets = tetherStats.txPackets;
- }
-
- public ForwardedStats(@NonNull ForwardedStats other) {
- rxBytes = other.rxBytes;
- rxPackets = other.rxPackets;
- txBytes = other.txBytes;
- txPackets = other.txPackets;
- }
-
- /** Add Tx/Rx bytes/packets and return the result as a new object. */
- @NonNull
- public ForwardedStats add(@NonNull ForwardedStats other) {
- return new ForwardedStats(rxBytes + other.rxBytes, rxPackets + other.rxPackets,
- txBytes + other.txBytes, txPackets + other.txPackets);
- }
-
- /** Subtract Tx/Rx bytes/packets and return the result as a new object. */
- @NonNull
- public ForwardedStats subtract(@NonNull ForwardedStats other) {
- // TODO: Perhaps throw an exception if any negative difference value just in case.
- final long rxBytesDiff = Math.max(rxBytes - other.rxBytes, 0);
- final long rxPacketsDiff = Math.max(rxPackets - other.rxPackets, 0);
- final long txBytesDiff = Math.max(txBytes - other.txBytes, 0);
- final long txPacketsDiff = Math.max(txPackets - other.txPackets, 0);
- return new ForwardedStats(rxBytesDiff, rxPacketsDiff, txBytesDiff, txPacketsDiff);
- }
-
- /** Returns the string representation of this object. */
- @NonNull
- public String toString() {
- return String.format("ForwardedStats(rxb: %d, rxp: %d, txb: %d, txp: %d)", rxBytes,
- rxPackets, txBytes, txPackets);
- }
- }
-
- /**
- * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements.
- * @param fd the socket's {@link FileDescriptor}.
- * @param ifIndex the interface index.
- */
- public static native void setupRaSocket(FileDescriptor fd, int ifIndex)
- throws SocketException;
-
- /**
- * Read s as an unsigned 16-bit integer.
- */
- public static int uint16(short s) {
- return s & 0xffff;
- }
-
- /** Check whether two TetheringRequestParcels are the same. */
- public static boolean isTetheringRequestEquals(final TetheringRequestParcel request,
- final TetheringRequestParcel otherRequest) {
- if (request == otherRequest) return true;
-
- return request != null && otherRequest != null
- && request.tetheringType == otherRequest.tetheringType
- && Objects.equals(request.localIPv4Address, otherRequest.localIPv4Address)
- && Objects.equals(request.staticClientAddress, otherRequest.staticClientAddress)
- && request.exemptFromEntitlementCheck == otherRequest.exemptFromEntitlementCheck
- && request.showProvisioningUi == otherRequest.showProvisioningUi;
- }
-
- /** Get inet6 address for all nodes given scope ID. */
- public static Inet6Address getAllNodesForScopeId(int scopeId) {
- try {
- return Inet6Address.getByAddress("ff02::1", ALL_NODES, scopeId);
- } catch (UnknownHostException uhe) {
- Log.wtf("TetheringUtils", "Failed to construct Inet6Address from "
- + Arrays.toString(ALL_NODES) + " and scopedId " + scopeId);
- return null;
- }
- }
-}
diff --git a/packages/Tethering/src/android/net/util/VersionedBroadcastListener.java b/packages/Tethering/src/android/net/util/VersionedBroadcastListener.java
deleted file mode 100644
index e2804abd752bb..0000000000000
--- a/packages/Tethering/src/android/net/util/VersionedBroadcastListener.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2017 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 android.net.util;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Handler;
-import android.util.Log;
-
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.Consumer;
-
-
-/**
- * A utility class that runs the provided callback on the provided handler when
- * intents matching the provided filter arrive. Intents received by a stale
- * receiver are safely ignored.
- *
- * Calls to startListening() and stopListening() must happen on the same thread.
- *
- * @hide
- */
-public class VersionedBroadcastListener {
- private static final boolean DBG = false;
-
- private final String mTag;
- private final Context mContext;
- private final Handler mHandler;
- private final IntentFilter mFilter;
- private final Consumer mCallback;
- private final AtomicInteger mGenerationNumber;
- private BroadcastReceiver mReceiver;
-
- public VersionedBroadcastListener(String tag, Context ctx, Handler handler,
- IntentFilter filter, Consumer callback) {
- mTag = tag;
- mContext = ctx;
- mHandler = handler;
- mFilter = filter;
- mCallback = callback;
- mGenerationNumber = new AtomicInteger(0);
- }
-
- /** Start listening to intent broadcast. */
- public void startListening() {
- if (DBG) Log.d(mTag, "startListening");
- if (mReceiver != null) return;
-
- mReceiver = new Receiver(mTag, mGenerationNumber, mCallback);
- mContext.registerReceiver(mReceiver, mFilter, null, mHandler);
- }
-
- /** Stop listening to intent broadcast. */
- public void stopListening() {
- if (DBG) Log.d(mTag, "stopListening");
- if (mReceiver == null) return;
-
- mGenerationNumber.incrementAndGet();
- mContext.unregisterReceiver(mReceiver);
- mReceiver = null;
- }
-
- private static class Receiver extends BroadcastReceiver {
- public final String tag;
- public final AtomicInteger atomicGenerationNumber;
- public final Consumer callback;
- // Used to verify this receiver is still current.
- public final int generationNumber;
-
- Receiver(String tag, AtomicInteger atomicGenerationNumber, Consumer callback) {
- this.tag = tag;
- this.atomicGenerationNumber = atomicGenerationNumber;
- this.callback = callback;
- generationNumber = atomicGenerationNumber.incrementAndGet();
- }
-
- @Override
- public void onReceive(Context context, Intent intent) {
- final int currentGenerationNumber = atomicGenerationNumber.get();
-
- if (DBG) {
- Log.d(tag, "receiver generationNumber=" + generationNumber
- + ", current generationNumber=" + currentGenerationNumber);
- }
- if (generationNumber != currentGenerationNumber) return;
-
- callback.accept(intent);
- }
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
deleted file mode 100644
index 20f30ea7a460c..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ /dev/null
@@ -1,778 +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 static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkStats.UID_TETHERING;
-import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
-
-import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
-
-import android.app.usage.NetworkStatsManager;
-import android.net.INetd;
-import android.net.MacAddress;
-import android.net.NetworkStats;
-import android.net.NetworkStats.Entry;
-import android.net.TetherOffloadRuleParcel;
-import android.net.TetherStatsParcel;
-import android.net.ip.IpServer;
-import android.net.netstats.provider.NetworkStatsProvider;
-import android.net.util.SharedLog;
-import android.net.util.TetheringUtils.ForwardedStats;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.RemoteException;
-import android.os.ServiceSpecificException;
-import android.text.TextUtils;
-import android.util.Log;
-import android.util.SparseArray;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.net.Inet6Address;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Objects;
-
-/**
- * This coordinator is responsible for providing BPF offload relevant functionality.
- * - Get tethering stats.
- * - Set data limit.
- * - Set global alert.
- * - Add/remove forwarding rules.
- *
- * @hide
- */
-public class BpfCoordinator {
- private static final String TAG = BpfCoordinator.class.getSimpleName();
- private static final int DUMP_TIMEOUT_MS = 10_000;
-
- @VisibleForTesting
- enum StatsType {
- STATS_PER_IFACE,
- STATS_PER_UID,
- }
-
- @NonNull
- private final Handler mHandler;
- @NonNull
- private final INetd mNetd;
- @NonNull
- private final SharedLog mLog;
- @NonNull
- private final Dependencies mDeps;
- @Nullable
- private final BpfTetherStatsProvider mStatsProvider;
-
- // True if BPF offload is supported, false otherwise. The BPF offload could be disabled by
- // a runtime resource overlay package or device configuration. This flag is only initialized
- // in the constructor because it is hard to unwind all existing change once device
- // configuration is changed. Especially the forwarding rules. Keep the same setting
- // to make it simpler. See also TetheringConfiguration.
- private final boolean mIsBpfEnabled;
-
- // Tracks whether BPF tethering is started or not. This is set by tethering before it
- // starts the first IpServer and is cleared by tethering shortly before the last IpServer
- // is stopped. Note that rule updates (especially deletions, but sometimes additions as
- // well) may arrive when this is false. If they do, they must be communicated to netd.
- // Changes in data limits may also arrive when this is false, and if they do, they must
- // also be communicated to netd.
- private boolean mPollingStarted = false;
-
- // Tracking remaining alert quota. Unlike limit quota is subject to interface, the alert
- // quota is interface independent and global for tether offload.
- private long mRemainingAlertQuota = QUOTA_UNLIMITED;
-
- // Maps upstream interface index to offloaded traffic statistics.
- // Always contains the latest total bytes/packets, since each upstream was started, received
- // from the BPF maps for each interface.
- private final SparseArray mStats = new SparseArray<>();
-
- // Maps upstream interface names to interface quotas.
- // Always contains the latest value received from the framework for each interface, regardless
- // of whether offload is currently running (or is even supported) on that interface. Only
- // includes interfaces that have a quota set. Note that this map is used for storing the quota
- // which is set from the service. Because the service uses the interface name to present the
- // interface, this map uses the interface name to be the mapping index.
- private final HashMap mInterfaceQuotas = new HashMap<>();
-
- // Maps upstream interface index to interface names.
- // Store all interface name since boot. Used for lookup what interface name it is from the
- // tether stats got from netd because netd reports interface index to present an interface.
- // TODO: Remove the unused interface name.
- private final SparseArray mInterfaceNames = new SparseArray<>();
-
- // Map of downstream rule maps. Each of these maps represents the IPv6 forwarding rules for a
- // given downstream. Each map:
- // - Is owned by the IpServer that is responsible for that downstream.
- // - Must only be modified by that IpServer.
- // - Is created when the IpServer adds its first rule, and deleted when the IpServer deletes
- // its last rule (or clears its rules).
- // TODO: Perhaps seal the map and rule operations which communicates with netd into a class.
- // TODO: Does this need to be a LinkedHashMap or can it just be a HashMap? Also, could it be
- // a ConcurrentHashMap, in order to avoid the copies in tetherOffloadRuleClear
- // and tetherOffloadRuleUpdate?
- // TODO: Perhaps use one-dimensional map and access specific downstream rules via downstream
- // index. For doing that, IpServer must guarantee that it always has a valid IPv6 downstream
- // interface index while calling function to clear all rules. IpServer may be calling clear
- // rules function without a valid IPv6 downstream interface index even if it may have one
- // before. IpServer would need to call getInterfaceParams() in the constructor instead of when
- // startIpv6() is called, and make mInterfaceParams final.
- private final HashMap>
- mIpv6ForwardingRules = new LinkedHashMap<>();
-
- // Runnable that used by scheduling next polling of stats.
- private final Runnable mScheduledPollingTask = () -> {
- updateForwardedStatsFromNetd();
- maybeSchedulePollingStats();
- };
-
- @VisibleForTesting
- public abstract static class Dependencies {
- /** Get handler. */
- @NonNull public abstract Handler getHandler();
-
- /** Get netd. */
- @NonNull public abstract INetd getNetd();
-
- /** Get network stats manager. */
- @NonNull public abstract NetworkStatsManager getNetworkStatsManager();
-
- /** Get shared log. */
- @NonNull public abstract SharedLog getSharedLog();
-
- /** Get tethering configuration. */
- @Nullable public abstract TetheringConfiguration getTetherConfig();
- }
-
- @VisibleForTesting
- public BpfCoordinator(@NonNull Dependencies deps) {
- mDeps = deps;
- mHandler = mDeps.getHandler();
- mNetd = mDeps.getNetd();
- mLog = mDeps.getSharedLog().forSubComponent(TAG);
- mIsBpfEnabled = isBpfEnabled();
- BpfTetherStatsProvider provider = new BpfTetherStatsProvider();
- try {
- mDeps.getNetworkStatsManager().registerNetworkStatsProvider(
- getClass().getSimpleName(), provider);
- } catch (RuntimeException e) {
- // TODO: Perhaps not allow to use BPF offload because the reregistration failure
- // implied that no data limit could be applies on a metered upstream if any.
- Log.wtf(TAG, "Cannot register offload stats provider: " + e);
- provider = null;
- }
- mStatsProvider = provider;
- }
-
- /**
- * Start BPF tethering offload stats polling when the first upstream is started.
- * Note that this can be only called on handler thread.
- * TODO: Perhaps check BPF support before starting.
- * TODO: Start the stats polling only if there is any client on the downstream.
- */
- public void startPolling() {
- if (mPollingStarted) return;
-
- if (!mIsBpfEnabled) {
- mLog.i("Offload disabled");
- return;
- }
-
- mPollingStarted = true;
- maybeSchedulePollingStats();
-
- mLog.i("Polling started");
- }
-
- /**
- * Stop BPF tethering offload stats polling.
- * The data limit cleanup and the tether stats maps cleanup are not implemented here.
- * These cleanups rely on all IpServers calling #tetherOffloadRuleRemove. After the
- * last rule is removed from the upstream, #tetherOffloadRuleRemove does the cleanup
- * functionality.
- * Note that this can be only called on handler thread.
- */
- public void stopPolling() {
- if (!mPollingStarted) return;
-
- // Stop scheduled polling tasks and poll the latest stats from BPF maps.
- if (mHandler.hasCallbacks(mScheduledPollingTask)) {
- mHandler.removeCallbacks(mScheduledPollingTask);
- }
- updateForwardedStatsFromNetd();
- mPollingStarted = false;
-
- mLog.i("Polling stopped");
- }
-
- /**
- * Add forwarding rule. After adding the first rule on a given upstream, must add the data
- * limit on the given upstream.
- * Note that this can be only called on handler thread.
- */
- public void tetherOffloadRuleAdd(
- @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) {
- if (!mIsBpfEnabled) return;
-
- try {
- // TODO: Perhaps avoid to add a duplicate rule.
- mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel());
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e("Could not add IPv6 forwarding rule: ", e);
- return;
- }
-
- if (!mIpv6ForwardingRules.containsKey(ipServer)) {
- mIpv6ForwardingRules.put(ipServer, new LinkedHashMap());
- }
- LinkedHashMap rules = mIpv6ForwardingRules.get(ipServer);
-
- // Setup the data limit on the given upstream if the first rule is added.
- final int upstreamIfindex = rule.upstreamIfindex;
- if (!isAnyRuleOnUpstream(upstreamIfindex)) {
- // If failed to set a data limit, probably should not use this upstream, because
- // the upstream may not want to blow through the data limit that was told to apply.
- // TODO: Perhaps stop the coordinator.
- boolean success = updateDataLimit(upstreamIfindex);
- if (!success) {
- final String iface = mInterfaceNames.get(upstreamIfindex);
- mLog.e("Setting data limit for " + iface + " failed.");
- }
- }
-
- // Must update the adding rule after calling #isAnyRuleOnUpstream because it needs to
- // check if it is about adding a first rule for a given upstream.
- rules.put(rule.address, rule);
- }
-
- /**
- * Remove forwarding rule. After removing the last rule on a given upstream, must clear
- * data limit, update the last tether stats and remove the tether stats in the BPF maps.
- * Note that this can be only called on handler thread.
- */
- public void tetherOffloadRuleRemove(
- @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) {
- if (!mIsBpfEnabled) return;
-
- try {
- // TODO: Perhaps avoid to remove a non-existent rule.
- mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel());
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e("Could not remove IPv6 forwarding rule: ", e);
- return;
- }
-
- LinkedHashMap rules = mIpv6ForwardingRules.get(ipServer);
- if (rules == null) return;
-
- // Must remove rules before calling #isAnyRuleOnUpstream because it needs to check if
- // the last rule is removed for a given upstream. If no rule is removed, return early.
- // Avoid unnecessary work on a non-existent rule which may have never been added or
- // removed already.
- if (rules.remove(rule.address) == null) return;
-
- // Remove the downstream entry if it has no more rule.
- if (rules.isEmpty()) {
- mIpv6ForwardingRules.remove(ipServer);
- }
-
- // Do cleanup functionality if there is no more rule on the given upstream.
- final int upstreamIfindex = rule.upstreamIfindex;
- if (!isAnyRuleOnUpstream(upstreamIfindex)) {
- try {
- final TetherStatsParcel stats =
- mNetd.tetherOffloadGetAndClearStats(upstreamIfindex);
- // Update the last stats delta and delete the local cache for a given upstream.
- updateQuotaAndStatsFromSnapshot(new TetherStatsParcel[] {stats});
- mStats.remove(upstreamIfindex);
- } catch (RemoteException | ServiceSpecificException e) {
- Log.wtf(TAG, "Exception when cleanup tether stats for upstream index "
- + upstreamIfindex + ": ", e);
- }
- }
- }
-
- /**
- * Clear all forwarding rules for a given downstream.
- * Note that this can be only called on handler thread.
- */
- public void tetherOffloadRuleClear(@NonNull final IpServer ipServer) {
- if (!mIsBpfEnabled) return;
-
- final LinkedHashMap rules = mIpv6ForwardingRules.get(
- ipServer);
- if (rules == null) return;
-
- // Need to build a rule list because the rule map may be changed in the iteration.
- for (final Ipv6ForwardingRule rule : new ArrayList(rules.values())) {
- tetherOffloadRuleRemove(ipServer, rule);
- }
- }
-
- /**
- * Update existing forwarding rules to new upstream for a given downstream.
- * Note that this can be only called on handler thread.
- */
- public void tetherOffloadRuleUpdate(@NonNull final IpServer ipServer, int newUpstreamIfindex) {
- if (!mIsBpfEnabled) return;
-
- final LinkedHashMap rules = mIpv6ForwardingRules.get(
- ipServer);
- if (rules == null) return;
-
- // Need to build a rule list because the rule map may be changed in the iteration.
- for (final Ipv6ForwardingRule rule : new ArrayList(rules.values())) {
- // Remove the old rule before adding the new one because the map uses the same key for
- // both rules. Reversing the processing order causes that the new rule is removed as
- // unexpected.
- // TODO: Add new rule first to reduce the latency which has no rule.
- tetherOffloadRuleRemove(ipServer, rule);
- tetherOffloadRuleAdd(ipServer, rule.onNewUpstream(newUpstreamIfindex));
- }
- }
-
- /**
- * Add upstream name to lookup table. The lookup table is used for tether stats interface name
- * lookup because the netd only reports interface index in BPF tether stats but the service
- * expects the interface name in NetworkStats object.
- * Note that this can be only called on handler thread.
- */
- public void addUpstreamNameToLookupTable(int upstreamIfindex, @NonNull String upstreamIface) {
- if (!mIsBpfEnabled) return;
-
- if (upstreamIfindex == 0 || TextUtils.isEmpty(upstreamIface)) return;
-
- // The same interface index to name mapping may be added by different IpServer objects or
- // re-added by reconnection on the same upstream interface. Ignore the duplicate one.
- final String iface = mInterfaceNames.get(upstreamIfindex);
- if (iface == null) {
- mInterfaceNames.put(upstreamIfindex, upstreamIface);
- } else if (!TextUtils.equals(iface, upstreamIface)) {
- Log.wtf(TAG, "The upstream interface name " + upstreamIface
- + " is different from the existing interface name "
- + iface + " for index " + upstreamIfindex);
- }
- }
-
- /**
- * Dump information.
- * Block the function until all the data are dumped on the handler thread or timed-out. The
- * reason is that dumpsys invokes this function on the thread of caller and the data may only
- * be allowed to be accessed on the handler thread.
- */
- public void dump(@NonNull IndentingPrintWriter pw) {
- final ConditionVariable dumpDone = new ConditionVariable();
- mHandler.post(() -> {
- pw.println("mIsBpfEnabled: " + mIsBpfEnabled);
- pw.println("Polling " + (mPollingStarted ? "started" : "not started"));
- pw.println("Stats provider " + (mStatsProvider != null
- ? "registered" : "not registered"));
- pw.println("Upstream quota: " + mInterfaceQuotas.toString());
- pw.println("Polling interval: " + getPollingInterval() + " ms");
-
- pw.println("Forwarding stats:");
- pw.increaseIndent();
- if (mStats.size() == 0) {
- pw.println("");
- } else {
- dumpStats(pw);
- }
- pw.decreaseIndent();
-
- pw.println("Forwarding rules:");
- pw.increaseIndent();
- if (mIpv6ForwardingRules.size() == 0) {
- pw.println("");
- } else {
- dumpIpv6ForwardingRules(pw);
- }
- pw.decreaseIndent();
-
- dumpDone.open();
- });
- if (!dumpDone.block(DUMP_TIMEOUT_MS)) {
- pw.println("... dump timed-out after " + DUMP_TIMEOUT_MS + "ms");
- }
- }
-
- private void dumpStats(@NonNull IndentingPrintWriter pw) {
- for (int i = 0; i < mStats.size(); i++) {
- final int upstreamIfindex = mStats.keyAt(i);
- final ForwardedStats stats = mStats.get(upstreamIfindex);
- pw.println(String.format("%d(%s) - %s", upstreamIfindex, mInterfaceNames.get(
- upstreamIfindex), stats.toString()));
- }
- }
-
- private void dumpIpv6ForwardingRules(@NonNull IndentingPrintWriter pw) {
- for (Map.Entry> entry :
- mIpv6ForwardingRules.entrySet()) {
- IpServer ipServer = entry.getKey();
- // The rule downstream interface index is paired with the interface name from
- // IpServer#interfaceName. See #startIPv6, #updateIpv6ForwardingRules in IpServer.
- final String downstreamIface = ipServer.interfaceName();
- pw.println("[" + downstreamIface + "]: iif(iface) oif(iface) v6addr srcmac dstmac");
-
- pw.increaseIndent();
- LinkedHashMap rules = entry.getValue();
- for (Ipv6ForwardingRule rule : rules.values()) {
- final int upstreamIfindex = rule.upstreamIfindex;
- pw.println(String.format("%d(%s) %d(%s) %s %s %s", upstreamIfindex,
- mInterfaceNames.get(upstreamIfindex), rule.downstreamIfindex,
- downstreamIface, rule.address, rule.srcMac, rule.dstMac));
- }
- pw.decreaseIndent();
- }
- }
-
- /** IPv6 forwarding rule class. */
- public static class Ipv6ForwardingRule {
- public final int upstreamIfindex;
- public final int downstreamIfindex;
-
- @NonNull
- public final Inet6Address address;
- @NonNull
- public final MacAddress srcMac;
- @NonNull
- public final MacAddress dstMac;
-
- public Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex,
- @NonNull Inet6Address address, @NonNull MacAddress srcMac,
- @NonNull MacAddress dstMac) {
- this.upstreamIfindex = upstreamIfindex;
- this.downstreamIfindex = downstreamIfIndex;
- this.address = address;
- this.srcMac = srcMac;
- this.dstMac = dstMac;
- }
-
- /** Return a new rule object which updates with new upstream index. */
- @NonNull
- public Ipv6ForwardingRule onNewUpstream(int newUpstreamIfindex) {
- return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac,
- dstMac);
- }
-
- /**
- * Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream()
- * would be error-prone due to generated stable AIDL classes not having a copy constructor.
- */
- @NonNull
- public TetherOffloadRuleParcel toTetherOffloadRuleParcel() {
- final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel();
- parcel.inputInterfaceIndex = upstreamIfindex;
- parcel.outputInterfaceIndex = downstreamIfindex;
- parcel.destination = address.getAddress();
- parcel.prefixLength = 128;
- parcel.srcL2Address = srcMac.toByteArray();
- parcel.dstL2Address = dstMac.toByteArray();
- return parcel;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof Ipv6ForwardingRule)) return false;
- Ipv6ForwardingRule that = (Ipv6ForwardingRule) o;
- return this.upstreamIfindex == that.upstreamIfindex
- && this.downstreamIfindex == that.downstreamIfindex
- && Objects.equals(this.address, that.address)
- && Objects.equals(this.srcMac, that.srcMac)
- && Objects.equals(this.dstMac, that.dstMac);
- }
-
- @Override
- public int hashCode() {
- // TODO: if this is ever used in production code, don't pass ifindices
- // to Objects.hash() to avoid autoboxing overhead.
- return Objects.hash(upstreamIfindex, downstreamIfindex, address, srcMac, dstMac);
- }
- }
-
- /**
- * A BPF tethering stats provider to provide network statistics to the system.
- * Note that this class' data may only be accessed on the handler thread.
- */
- @VisibleForTesting
- class BpfTetherStatsProvider extends NetworkStatsProvider {
- // The offloaded traffic statistics per interface that has not been reported since the
- // last call to pushTetherStats. Only the interfaces that were ever tethering upstreams
- // and has pending tether stats delta are included in this NetworkStats object.
- private NetworkStats mIfaceStats = new NetworkStats(0L, 0);
-
- // The same stats as above, but counts network stats per uid.
- private NetworkStats mUidStats = new NetworkStats(0L, 0);
-
- @Override
- public void onRequestStatsUpdate(int token) {
- mHandler.post(() -> pushTetherStats());
- }
-
- @Override
- public void onSetAlert(long quotaBytes) {
- mHandler.post(() -> updateAlertQuota(quotaBytes));
- }
-
- @Override
- public void onSetLimit(@NonNull String iface, long quotaBytes) {
- if (quotaBytes < QUOTA_UNLIMITED) {
- throw new IllegalArgumentException("invalid quota value " + quotaBytes);
- }
-
- mHandler.post(() -> {
- final Long curIfaceQuota = mInterfaceQuotas.get(iface);
-
- if (null == curIfaceQuota && QUOTA_UNLIMITED == quotaBytes) return;
-
- if (quotaBytes == QUOTA_UNLIMITED) {
- mInterfaceQuotas.remove(iface);
- } else {
- mInterfaceQuotas.put(iface, quotaBytes);
- }
- maybeUpdateDataLimit(iface);
- });
- }
-
- @VisibleForTesting
- void pushTetherStats() {
- try {
- // The token is not used for now. See b/153606961.
- notifyStatsUpdated(0 /* token */, mIfaceStats, mUidStats);
-
- // Clear the accumulated tether stats delta after reported. Note that create a new
- // empty object because NetworkStats#clear is @hide.
- mIfaceStats = new NetworkStats(0L, 0);
- mUidStats = new NetworkStats(0L, 0);
- } catch (RuntimeException e) {
- mLog.e("Cannot report network stats: ", e);
- }
- }
-
- private void accumulateDiff(@NonNull NetworkStats ifaceDiff,
- @NonNull NetworkStats uidDiff) {
- mIfaceStats = mIfaceStats.add(ifaceDiff);
- mUidStats = mUidStats.add(uidDiff);
- }
- }
-
- private boolean isBpfEnabled() {
- final TetheringConfiguration config = mDeps.getTetherConfig();
- return (config != null) ? config.isBpfOffloadEnabled() : true /* default value */;
- }
-
- private int getInterfaceIndexFromRules(@NonNull String ifName) {
- for (LinkedHashMap rules : mIpv6ForwardingRules
- .values()) {
- for (Ipv6ForwardingRule rule : rules.values()) {
- final int upstreamIfindex = rule.upstreamIfindex;
- if (TextUtils.equals(ifName, mInterfaceNames.get(upstreamIfindex))) {
- return upstreamIfindex;
- }
- }
- }
- return 0;
- }
-
- private long getQuotaBytes(@NonNull String iface) {
- final Long limit = mInterfaceQuotas.get(iface);
- final long quotaBytes = (limit != null) ? limit : QUOTA_UNLIMITED;
-
- return quotaBytes;
- }
-
- private boolean sendDataLimitToNetd(int ifIndex, long quotaBytes) {
- if (ifIndex == 0) {
- Log.wtf(TAG, "Invalid interface index.");
- return false;
- }
-
- try {
- mNetd.tetherOffloadSetInterfaceQuota(ifIndex, quotaBytes);
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e("Exception when updating quota " + quotaBytes + ": ", e);
- return false;
- }
-
- return true;
- }
-
- // Handle the data limit update from the service which is the stats provider registered for.
- private void maybeUpdateDataLimit(@NonNull String iface) {
- // Set data limit only on a given upstream which has at least one rule. If we can't get
- // an interface index for a given interface name, it means either there is no rule for
- // a given upstream or the interface name is not an upstream which is monitored by the
- // coordinator.
- final int ifIndex = getInterfaceIndexFromRules(iface);
- if (ifIndex == 0) return;
-
- final long quotaBytes = getQuotaBytes(iface);
- sendDataLimitToNetd(ifIndex, quotaBytes);
- }
-
- // Handle the data limit update while adding forwarding rules.
- private boolean updateDataLimit(int ifIndex) {
- final String iface = mInterfaceNames.get(ifIndex);
- if (iface == null) {
- mLog.e("Fail to get the interface name for index " + ifIndex);
- return false;
- }
- final long quotaBytes = getQuotaBytes(iface);
- return sendDataLimitToNetd(ifIndex, quotaBytes);
- }
-
- private boolean isAnyRuleOnUpstream(int upstreamIfindex) {
- for (LinkedHashMap rules : mIpv6ForwardingRules
- .values()) {
- for (Ipv6ForwardingRule rule : rules.values()) {
- if (upstreamIfindex == rule.upstreamIfindex) return true;
- }
- }
- return false;
- }
-
- @NonNull
- private NetworkStats buildNetworkStats(@NonNull StatsType type, int ifIndex,
- @NonNull final ForwardedStats diff) {
- NetworkStats stats = new NetworkStats(0L, 0);
- final String iface = mInterfaceNames.get(ifIndex);
- if (iface == null) {
- // TODO: Use Log.wtf once the coordinator owns full control of tether stats from netd.
- // For now, netd may add the empty stats for the upstream which is not monitored by
- // the coordinator. Silently ignore it.
- return stats;
- }
- final int uid = (type == StatsType.STATS_PER_UID) ? UID_TETHERING : UID_ALL;
- // Note that the argument 'metered', 'roaming' and 'defaultNetwork' are not recorded for
- // network stats snapshot. See NetworkStatsRecorder#recordSnapshotLocked.
- return stats.addEntry(new Entry(iface, uid, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, diff.rxBytes, diff.rxPackets,
- diff.txBytes, diff.txPackets, 0L /* operations */));
- }
-
- private void updateAlertQuota(long newQuota) {
- if (newQuota < QUOTA_UNLIMITED) {
- throw new IllegalArgumentException("invalid quota value " + newQuota);
- }
- if (mRemainingAlertQuota == newQuota) return;
-
- mRemainingAlertQuota = newQuota;
- if (mRemainingAlertQuota == 0) {
- mLog.i("onAlertReached");
- if (mStatsProvider != null) mStatsProvider.notifyAlertReached();
- }
- }
-
- private void updateQuotaAndStatsFromSnapshot(
- @NonNull final TetherStatsParcel[] tetherStatsList) {
- long usedAlertQuota = 0;
- for (TetherStatsParcel tetherStats : tetherStatsList) {
- final Integer ifIndex = tetherStats.ifIndex;
- final ForwardedStats curr = new ForwardedStats(tetherStats);
- final ForwardedStats base = mStats.get(ifIndex);
- final ForwardedStats diff = (base != null) ? curr.subtract(base) : curr;
- usedAlertQuota += diff.rxBytes + diff.txBytes;
-
- // Update the local cache for counting tether stats delta.
- mStats.put(ifIndex, curr);
-
- // Update the accumulated tether stats delta to the stats provider for the service
- // querying.
- if (mStatsProvider != null) {
- try {
- mStatsProvider.accumulateDiff(
- buildNetworkStats(StatsType.STATS_PER_IFACE, ifIndex, diff),
- buildNetworkStats(StatsType.STATS_PER_UID, ifIndex, diff));
- } catch (ArrayIndexOutOfBoundsException e) {
- Log.wtf(TAG, "Fail to update the accumulated stats delta for interface index "
- + ifIndex + " : ", e);
- }
- }
- }
-
- if (mRemainingAlertQuota > 0 && usedAlertQuota > 0) {
- // Trim to zero if overshoot.
- final long newQuota = Math.max(mRemainingAlertQuota - usedAlertQuota, 0);
- updateAlertQuota(newQuota);
- }
-
- // TODO: Count the used limit quota for notifying data limit reached.
- }
-
- private void updateForwardedStatsFromNetd() {
- final TetherStatsParcel[] tetherStatsList;
- try {
- // The reported tether stats are total data usage for all currently-active upstream
- // interfaces since tethering start.
- tetherStatsList = mNetd.tetherOffloadGetStats();
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e("Problem fetching tethering stats: ", e);
- return;
- }
- updateQuotaAndStatsFromSnapshot(tetherStatsList);
- }
-
- @VisibleForTesting
- int getPollingInterval() {
- // The valid range of interval is DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS..max_long.
- // Ignore the config value is less than the minimum polling interval. Note that the
- // minimum interval definition is invoked as OffloadController#isPollingStatsNeeded does.
- // TODO: Perhaps define a minimum polling interval constant.
- final TetheringConfiguration config = mDeps.getTetherConfig();
- final int configInterval = (config != null) ? config.getOffloadPollInterval() : 0;
- return Math.max(DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS, configInterval);
- }
-
- private void maybeSchedulePollingStats() {
- if (!mPollingStarted) return;
-
- if (mHandler.hasCallbacks(mScheduledPollingTask)) {
- mHandler.removeCallbacks(mScheduledPollingTask);
- }
-
- mHandler.postDelayed(mScheduledPollingTask, getPollingInterval());
- }
-
- // Return forwarding rule map. This is used for testing only.
- // Note that this can be only called on handler thread.
- @NonNull
- @VisibleForTesting
- final HashMap>
- getForwardingRulesForTesting() {
- return mIpv6ForwardingRules;
- }
-
- // Return upstream interface name map. This is used for testing only.
- // Note that this can be only called on handler thread.
- @NonNull
- @VisibleForTesting
- final SparseArray getInterfaceNamesForTesting() {
- return mInterfaceNames;
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java b/packages/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java
deleted file mode 100644
index 8a96988ae1d1d..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/ConnectedClientsTracker.java
+++ /dev/null
@@ -1,183 +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 static android.net.TetheringManager.TETHERING_WIFI;
-
-import android.net.MacAddress;
-import android.net.TetheredClient;
-import android.net.TetheredClient.AddressInfo;
-import android.net.ip.IpServer;
-import android.net.wifi.WifiClient;
-import android.os.SystemClock;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Tracker for clients connected to downstreams.
- *
- *
This class is not thread safe, it is intended to be used only from the tethering handler
- * thread.
- */
-public class ConnectedClientsTracker {
- private final Clock mClock;
-
- @NonNull
- private List mLastWifiClients = Collections.emptyList();
- @NonNull
- private List mLastTetheredClients = Collections.emptyList();
-
- @VisibleForTesting
- static class Clock {
- public long elapsedRealtime() {
- return SystemClock.elapsedRealtime();
- }
- }
-
- public ConnectedClientsTracker() {
- this(new Clock());
- }
-
- @VisibleForTesting
- ConnectedClientsTracker(Clock clock) {
- mClock = clock;
- }
-
- /**
- * Update the tracker with new connected clients.
- *
- *
The new list can be obtained through {@link #getLastTetheredClients()}.
- * @param ipServers The IpServers used to assign addresses to clients.
- * @param wifiClients The list of L2-connected WiFi clients. Null for no change since last
- * update.
- * @return True if the list of clients changed since the last calculation.
- */
- public boolean updateConnectedClients(
- Iterable ipServers, @Nullable List wifiClients) {
- final long now = mClock.elapsedRealtime();
-
- if (wifiClients != null) {
- mLastWifiClients = wifiClients;
- }
- final Set wifiClientMacs = getClientMacs(mLastWifiClients);
-
- // Build the list of non-expired leases from all IpServers, grouped by mac address
- final Map clientsMap = new HashMap<>();
- for (IpServer server : ipServers) {
- for (TetheredClient client : server.getAllLeases()) {
- if (client.getTetheringType() == TETHERING_WIFI
- && !wifiClientMacs.contains(client.getMacAddress())) {
- // Skip leases of WiFi clients that are not (or no longer) L2-connected
- continue;
- }
- final TetheredClient prunedClient = pruneExpired(client, now);
- if (prunedClient == null) continue; // All addresses expired
-
- addLease(clientsMap, prunedClient);
- }
- }
-
- // TODO: add IPv6 addresses from netlink
-
- // Add connected WiFi clients that do not have any known address
- for (MacAddress client : wifiClientMacs) {
- if (clientsMap.containsKey(client)) continue;
- clientsMap.put(client, new TetheredClient(
- client, Collections.emptyList() /* addresses */, TETHERING_WIFI));
- }
-
- final HashSet clients = new HashSet<>(clientsMap.values());
- final boolean clientsChanged = clients.size() != mLastTetheredClients.size()
- || !clients.containsAll(mLastTetheredClients);
- mLastTetheredClients = Collections.unmodifiableList(new ArrayList<>(clients));
- return clientsChanged;
- }
-
- private static void addLease(Map clientsMap, TetheredClient lease) {
- final TetheredClient aggregateClient = clientsMap.getOrDefault(
- lease.getMacAddress(), lease);
- if (aggregateClient == lease) {
- // This is the first lease with this mac address
- clientsMap.put(lease.getMacAddress(), lease);
- return;
- }
-
- // Only add the address info; this assumes that the tethering type is the same when the mac
- // address is the same. If a client is connected through different tethering types with the
- // same mac address, connected clients callbacks will report all of its addresses under only
- // one of these tethering types. This keeps the API simple considering that such a scenario
- // would really be a rare edge case.
- clientsMap.put(lease.getMacAddress(), aggregateClient.addAddresses(lease));
- }
-
- /**
- * Get the last list of tethered clients, as calculated in {@link #updateConnectedClients}.
- *
- *
The returned list is immutable.
- */
- @NonNull
- public List getLastTetheredClients() {
- return mLastTetheredClients;
- }
-
- private static boolean hasExpiredAddress(List addresses, long now) {
- for (AddressInfo info : addresses) {
- if (info.getExpirationTime() <= now) {
- return true;
- }
- }
- return false;
- }
-
- @Nullable
- private static TetheredClient pruneExpired(TetheredClient client, long now) {
- final List addresses = client.getAddresses();
- if (addresses.size() == 0) return null;
- if (!hasExpiredAddress(addresses, now)) return client;
-
- final ArrayList newAddrs = new ArrayList<>(addresses.size() - 1);
- for (AddressInfo info : addresses) {
- if (info.getExpirationTime() > now) {
- newAddrs.add(info);
- }
- }
-
- if (newAddrs.size() == 0) {
- return null;
- }
- return new TetheredClient(client.getMacAddress(), newAddrs, client.getTetheringType());
- }
-
- @NonNull
- private static Set getClientMacs(@NonNull List clients) {
- final Set macs = new HashSet<>(clients.size());
- for (WifiClient c : clients) {
- macs.add(c.getMacAddress());
- }
- return macs;
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java b/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
deleted file mode 100644
index bb7322f2a0d2a..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/EntitlementManager.java
+++ /dev/null
@@ -1,646 +0,0 @@
-/*
- * Copyright (C) 2018 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 static android.net.TetheringConstants.EXTRA_ADD_TETHER_TYPE;
-import static android.net.TetheringConstants.EXTRA_PROVISION_CALLBACK;
-import static android.net.TetheringConstants.EXTRA_RUN_PROVISION;
-import static android.net.TetheringConstants.EXTRA_TETHER_PROVISIONING_RESPONSE;
-import static android.net.TetheringConstants.EXTRA_TETHER_SILENT_PROVISIONING_ACTION;
-import static android.net.TetheringConstants.EXTRA_TETHER_SUBID;
-import static android.net.TetheringConstants.EXTRA_TETHER_UI_PROVISIONING_APP_NAME;
-import static android.net.TetheringManager.TETHERING_BLUETOOTH;
-import static android.net.TetheringManager.TETHERING_ETHERNET;
-import static android.net.TetheringManager.TETHERING_INVALID;
-import static android.net.TetheringManager.TETHERING_USB;
-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 android.app.AlarmManager;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.net.util.SharedLog;
-import android.os.Bundle;
-import android.os.ConditionVariable;
-import android.os.Handler;
-import android.os.Parcel;
-import android.os.PersistableBundle;
-import android.os.ResultReceiver;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.provider.Settings;
-import android.telephony.CarrierConfigManager;
-import android.util.SparseIntArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.PrintWriter;
-import java.util.BitSet;
-
-/**
- * Re-check tethering provisioning for enabled downstream tether types.
- * Reference TetheringManager.TETHERING_{@code *} for each tether type.
- *
- * All methods of this class must be accessed from the thread of tethering
- * state machine.
- * @hide
- */
-public class EntitlementManager {
- private static final String TAG = EntitlementManager.class.getSimpleName();
- private static final boolean DBG = false;
-
- @VisibleForTesting
- protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
- private static final String ACTION_PROVISIONING_ALARM =
- "com.android.networkstack.tethering.PROVISIONING_RECHECK_ALARM";
-
- private final ComponentName mSilentProvisioningService;
- private static final int MS_PER_HOUR = 60 * 60 * 1000;
- private static final int DUMP_TIMEOUT = 10_000;
-
- // The BitSet is the bit map of each enabled downstream types, ex:
- // {@link TetheringManager.TETHERING_WIFI}
- // {@link TetheringManager.TETHERING_USB}
- // {@link TetheringManager.TETHERING_BLUETOOTH}
- private final BitSet mCurrentDownstreams;
- private final BitSet mExemptedDownstreams;
- private final Context mContext;
- private final SharedLog mLog;
- private final SparseIntArray mEntitlementCacheValue;
- private final Handler mHandler;
- // Key: TetheringManager.TETHERING_*(downstream).
- // Value: TetheringManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result).
- private final SparseIntArray mCurrentEntitlementResults;
- private final Runnable mPermissionChangeCallback;
- private PendingIntent mProvisioningRecheckAlarm;
- private boolean mLastCellularUpstreamPermitted = true;
- private boolean mUsingCellularAsUpstream = false;
- private boolean mNeedReRunProvisioningUi = false;
- private OnUiEntitlementFailedListener mListener;
- private TetheringConfigurationFetcher mFetcher;
-
- public EntitlementManager(Context ctx, Handler h, SharedLog log,
- Runnable callback) {
- mContext = ctx;
- mLog = log.forSubComponent(TAG);
- mCurrentDownstreams = new BitSet();
- mExemptedDownstreams = new BitSet();
- mCurrentEntitlementResults = new SparseIntArray();
- mEntitlementCacheValue = new SparseIntArray();
- mPermissionChangeCallback = callback;
- mHandler = h;
- mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM),
- null, mHandler);
- mSilentProvisioningService = ComponentName.unflattenFromString(
- mContext.getResources().getString(R.string.config_wifi_tether_enable));
- }
-
- public void setOnUiEntitlementFailedListener(final OnUiEntitlementFailedListener listener) {
- mListener = listener;
- }
-
- /** Callback fired when UI entitlement failed. */
- public interface OnUiEntitlementFailedListener {
- /**
- * Ui entitlement check fails in |downstream|.
- *
- * @param downstream tethering type from TetheringManager.TETHERING_{@code *}.
- */
- void onUiEntitlementFailed(int downstream);
- }
-
- public void setTetheringConfigurationFetcher(final TetheringConfigurationFetcher fetcher) {
- mFetcher = fetcher;
- }
-
- /** Interface to fetch TetheringConfiguration. */
- public interface TetheringConfigurationFetcher {
- /**
- * Fetch current tethering configuration. This will be called to ensure whether entitlement
- * check is needed.
- * @return TetheringConfiguration instance.
- */
- TetheringConfiguration fetchTetheringConfiguration();
- }
-
- /**
- * Check if cellular upstream is permitted.
- */
- public boolean isCellularUpstreamPermitted() {
- final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
-
- return isCellularUpstreamPermitted(config);
- }
-
- private boolean isCellularUpstreamPermitted(final TetheringConfiguration config) {
- if (!isTetherProvisioningRequired(config)) return true;
-
- // If provisioning is required and EntitlementManager doesn't know any downstreams, cellular
- // upstream should not be enabled. Enable cellular upstream for exempted downstreams only
- // when there is no non-exempted downstream.
- if (mCurrentDownstreams.isEmpty()) return !mExemptedDownstreams.isEmpty();
-
- return mCurrentEntitlementResults.indexOfValue(TETHER_ERROR_NO_ERROR) > -1;
- }
-
- /**
- * Set exempted downstream type. If there is only exempted downstream type active,
- * corresponding entitlement check will not be run and cellular upstream will be permitted
- * by default. If a privileged app enables tethering without a provisioning check, and then
- * another app enables tethering of the same type but does not disable the provisioning check,
- * then the downstream immediately loses exempt status and a provisioning check is run.
- * If any non-exempted downstream type is active, the cellular upstream will be gated by the
- * result of entitlement check from non-exempted downstreams. If entitlement check is still
- * in progress on non-exempt downstreams, ceullar upstream would default be disabled. When any
- * non-exempted downstream gets positive entitlement result, ceullar upstream will be enabled.
- */
- public void setExemptedDownstreamType(final int type) {
- mExemptedDownstreams.set(type, true);
- }
-
- /**
- * This is called when tethering starts.
- * Launch provisioning app if upstream is cellular.
- *
- * @param downstreamType tethering type from TetheringManager.TETHERING_{@code *}
- * @param showProvisioningUi a boolean indicating whether to show the
- * provisioning app UI if there is one.
- */
- public void startProvisioningIfNeeded(int downstreamType, boolean showProvisioningUi) {
- if (!isValidDownstreamType(downstreamType)) return;
-
- mCurrentDownstreams.set(downstreamType, true);
-
- mExemptedDownstreams.set(downstreamType, false);
-
- final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
- if (!isTetherProvisioningRequired(config)) return;
-
- // If upstream is not cellular, provisioning app would not be launched
- // till upstream change to cellular.
- if (mUsingCellularAsUpstream) {
- if (showProvisioningUi) {
- runUiTetherProvisioning(downstreamType, config);
- } else {
- runSilentTetherProvisioning(downstreamType, config);
- }
- mNeedReRunProvisioningUi = false;
- } else {
- mNeedReRunProvisioningUi |= showProvisioningUi;
- }
- }
-
- /**
- * Tell EntitlementManager that a given type of tethering has been disabled
- *
- * @param type tethering type from TetheringManager.TETHERING_{@code *}
- */
- public void stopProvisioningIfNeeded(int downstreamType) {
- if (!isValidDownstreamType(downstreamType)) return;
-
- mCurrentDownstreams.set(downstreamType, false);
- // There are lurking bugs where the notion of "provisioning required" or
- // "tethering supported" may change without without tethering being notified properly.
- // Remove the mapping all the time no matter provisioning is required or not.
- removeDownstreamMapping(downstreamType);
- mExemptedDownstreams.set(downstreamType, false);
- }
-
- /**
- * Notify EntitlementManager if upstream is cellular or not.
- *
- * @param isCellular whether tethering upstream is cellular.
- */
- public void notifyUpstream(boolean isCellular) {
- if (DBG) {
- mLog.i("notifyUpstream: " + isCellular
- + ", mLastCellularUpstreamPermitted: " + mLastCellularUpstreamPermitted
- + ", mNeedReRunProvisioningUi: " + mNeedReRunProvisioningUi);
- }
- mUsingCellularAsUpstream = isCellular;
-
- if (mUsingCellularAsUpstream) {
- final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
- maybeRunProvisioning(config);
- }
- }
-
- /** Run provisioning if needed */
- public void maybeRunProvisioning() {
- final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
- maybeRunProvisioning(config);
- }
-
- private void maybeRunProvisioning(final TetheringConfiguration config) {
- if (mCurrentDownstreams.isEmpty() || !isTetherProvisioningRequired(config)) {
- return;
- }
-
- // Whenever any entitlement value changes, all downstreams will re-evaluate whether they
- // are allowed. Therefore even if the silent check here ends in a failure and the UI later
- // yields success, then the downstream that got a failure will re-evaluate as a result of
- // the change and get the new correct value.
- for (int downstream = mCurrentDownstreams.nextSetBit(0); downstream >= 0;
- downstream = mCurrentDownstreams.nextSetBit(downstream + 1)) {
- if (mCurrentEntitlementResults.indexOfKey(downstream) < 0) {
- if (mNeedReRunProvisioningUi) {
- mNeedReRunProvisioningUi = false;
- runUiTetherProvisioning(downstream, config);
- } else {
- runSilentTetherProvisioning(downstream, config);
- }
- }
- }
- }
-
- /**
- * Check if the device requires a provisioning check in order to enable tethering.
- *
- * @param config an object that encapsulates the various tethering configuration elements.
- * @return a boolean - {@code true} indicating tether provisioning is required by the carrier.
- */
- @VisibleForTesting
- protected boolean isTetherProvisioningRequired(final TetheringConfiguration config) {
- if (SystemProperties.getBoolean(DISABLE_PROVISIONING_SYSPROP_KEY, false)
- || config.provisioningApp.length == 0) {
- return false;
- }
- if (carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
- return false;
- }
- return (config.provisioningApp.length == 2);
- }
-
- /**
- * Re-check tethering provisioning for all enabled tether types.
- * Reference TetheringManager.TETHERING_{@code *} for each tether type.
- *
- * @param config an object that encapsulates the various tethering configuration elements.
- * Note: this method is only called from @{link Tethering.TetherMainSM} on the handler thread.
- * If there are new callers from different threads, the logic should move to
- * @{link Tethering.TetherMainSM} handler to avoid race conditions.
- */
- public void reevaluateSimCardProvisioning(final TetheringConfiguration config) {
- if (DBG) mLog.i("reevaluateSimCardProvisioning");
-
- if (!mHandler.getLooper().isCurrentThread()) {
- // Except for test, this log should not appear in normal flow.
- mLog.log("reevaluateSimCardProvisioning() don't run in TetherMainSM thread");
- }
- mEntitlementCacheValue.clear();
- mCurrentEntitlementResults.clear();
-
- // TODO: refine provisioning check to isTetherProvisioningRequired() ??
- if (!config.hasMobileHotspotProvisionApp()
- || carrierConfigAffirmsEntitlementCheckNotRequired(config)) {
- evaluateCellularPermission(config);
- return;
- }
-
- if (mUsingCellularAsUpstream) {
- maybeRunProvisioning(config);
- }
- }
-
- /**
- * Get carrier configuration bundle.
- * @param config an object that encapsulates the various tethering configuration elements.
- * */
- public PersistableBundle getCarrierConfig(final TetheringConfiguration config) {
- final CarrierConfigManager configManager = (CarrierConfigManager) mContext
- .getSystemService(Context.CARRIER_CONFIG_SERVICE);
- if (configManager == null) return null;
-
- final PersistableBundle carrierConfig = configManager.getConfigForSubId(
- config.activeDataSubId);
-
- if (CarrierConfigManager.isConfigForIdentifiedCarrier(carrierConfig)) {
- return carrierConfig;
- }
-
- return null;
- }
-
- // The logic here is aimed solely at confirming that a CarrierConfig exists
- // and affirms that entitlement checks are not required.
- //
- // TODO: find a better way to express this, or alter the checking process
- // entirely so that this is more intuitive.
- private boolean carrierConfigAffirmsEntitlementCheckNotRequired(
- final TetheringConfiguration config) {
- // Check carrier config for entitlement checks
- final PersistableBundle carrierConfig = getCarrierConfig(config);
- if (carrierConfig == null) return false;
-
- // A CarrierConfigManager was found and it has a config.
- final boolean isEntitlementCheckRequired = carrierConfig.getBoolean(
- CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
- return !isEntitlementCheckRequired;
- }
-
- /**
- * Run no UI tethering provisioning check.
- * @param type tethering type from TetheringManager.TETHERING_{@code *}
- * @param subId default data subscription ID.
- */
- @VisibleForTesting
- protected Intent runSilentTetherProvisioning(int type, final TetheringConfiguration config) {
- if (DBG) mLog.i("runSilentTetherProvisioning: " + type);
- // For silent provisioning, settings would stop tethering when entitlement fail.
- ResultReceiver receiver = buildProxyReceiver(type, false/* notifyFail */, null);
-
- Intent intent = new Intent();
- intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
- intent.putExtra(EXTRA_RUN_PROVISION, true);
- intent.putExtra(EXTRA_TETHER_SILENT_PROVISIONING_ACTION, config.provisioningAppNoUi);
- intent.putExtra(EXTRA_TETHER_PROVISIONING_RESPONSE, config.provisioningResponse);
- intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
- intent.putExtra(EXTRA_TETHER_SUBID, config.activeDataSubId);
- intent.setComponent(mSilentProvisioningService);
- // Only admin user can change tethering and SilentTetherProvisioning don't need to
- // show UI, it is fine to always start setting's background service as system user.
- mContext.startService(intent);
- return intent;
- }
-
- private void runUiTetherProvisioning(int type, final TetheringConfiguration config) {
- ResultReceiver receiver = buildProxyReceiver(type, true/* notifyFail */, null);
- runUiTetherProvisioning(type, config, receiver);
- }
-
- /**
- * Run the UI-enabled tethering provisioning check.
- * @param type tethering type from TetheringManager.TETHERING_{@code *}
- * @param subId default data subscription ID.
- * @param receiver to receive entitlement check result.
- */
- @VisibleForTesting
- protected Intent runUiTetherProvisioning(int type, final TetheringConfiguration config,
- ResultReceiver receiver) {
- if (DBG) mLog.i("runUiTetherProvisioning: " + type);
-
- Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING_UI);
- intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
- intent.putExtra(EXTRA_TETHER_UI_PROVISIONING_APP_NAME, config.provisioningApp);
- intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
- intent.putExtra(EXTRA_TETHER_SUBID, config.activeDataSubId);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- // Only launch entitlement UI for system user. Entitlement UI should not appear for other
- // user because only admin user is allowed to change tethering.
- mContext.startActivity(intent);
- return intent;
- }
-
- // Not needed to check if this don't run on the handler thread because it's private.
- private void scheduleProvisioningRechecks(final TetheringConfiguration config) {
- if (mProvisioningRecheckAlarm == null) {
- final int period = config.provisioningCheckPeriod;
- if (period <= 0) return;
-
- Intent intent = new Intent(ACTION_PROVISIONING_ALARM);
- mProvisioningRecheckAlarm = PendingIntent.getBroadcast(mContext, 0, intent, 0);
- AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
- Context.ALARM_SERVICE);
- long periodMs = period * MS_PER_HOUR;
- long firstAlarmTime = SystemClock.elapsedRealtime() + periodMs;
- alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, firstAlarmTime, periodMs,
- mProvisioningRecheckAlarm);
- }
- }
-
- private void cancelTetherProvisioningRechecks() {
- if (mProvisioningRecheckAlarm != null) {
- AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
- Context.ALARM_SERVICE);
- alarmManager.cancel(mProvisioningRecheckAlarm);
- mProvisioningRecheckAlarm = null;
- }
- }
-
- private void evaluateCellularPermission(final TetheringConfiguration config) {
- final boolean permitted = isCellularUpstreamPermitted(config);
-
- if (DBG) {
- mLog.i("Cellular permission change from " + mLastCellularUpstreamPermitted
- + " to " + permitted);
- }
-
- if (mLastCellularUpstreamPermitted != permitted) {
- mLog.log("Cellular permission change: " + permitted);
- mPermissionChangeCallback.run();
- }
- // Only schedule periodic re-check when tether is provisioned
- // and the result is ok.
- if (permitted && mCurrentEntitlementResults.size() > 0) {
- scheduleProvisioningRechecks(config);
- } else {
- cancelTetherProvisioningRechecks();
- }
- mLastCellularUpstreamPermitted = permitted;
- }
-
- /**
- * Add the mapping between provisioning result and tethering type.
- * Notify UpstreamNetworkMonitor if Cellular permission changes.
- *
- * @param type tethering type from TetheringManager.TETHERING_{@code *}
- * @param resultCode Provisioning result
- */
- protected void addDownstreamMapping(int type, int resultCode) {
- mLog.i("addDownstreamMapping: " + type + ", result: " + resultCode
- + " ,TetherTypeRequested: " + mCurrentDownstreams.get(type));
- if (!mCurrentDownstreams.get(type)) return;
-
- mCurrentEntitlementResults.put(type, resultCode);
- final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
- evaluateCellularPermission(config);
- }
-
- /**
- * Remove the mapping for input tethering type.
- * @param type tethering type from TetheringManager.TETHERING_{@code *}
- */
- protected void removeDownstreamMapping(int type) {
- mLog.i("removeDownstreamMapping: " + type);
- mCurrentEntitlementResults.delete(type);
- final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
- evaluateCellularPermission(config);
- }
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (ACTION_PROVISIONING_ALARM.equals(intent.getAction())) {
- mLog.log("Received provisioning alarm");
- final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
- reevaluateSimCardProvisioning(config);
- }
- }
- };
-
- private static boolean isValidDownstreamType(int type) {
- switch (type) {
- case TETHERING_BLUETOOTH:
- case TETHERING_ETHERNET:
- case TETHERING_USB:
- case TETHERING_WIFI:
- return true;
- default:
- return false;
- }
- }
-
- /**
- * Dump the infromation of EntitlementManager.
- * @param pw {@link PrintWriter} is used to print formatted
- */
- public void dump(PrintWriter pw) {
- final ConditionVariable mWaiting = new ConditionVariable();
- mHandler.post(() -> {
- pw.print("isCellularUpstreamPermitted: ");
- pw.println(isCellularUpstreamPermitted());
- for (int type = mCurrentDownstreams.nextSetBit(0); type >= 0;
- type = mCurrentDownstreams.nextSetBit(type + 1)) {
- pw.print("Type: ");
- pw.print(typeString(type));
- if (mCurrentEntitlementResults.indexOfKey(type) > -1) {
- pw.print(", Value: ");
- pw.println(errorString(mCurrentEntitlementResults.get(type)));
- } else {
- pw.println(", Value: empty");
- }
- }
- mWaiting.open();
- });
- if (!mWaiting.block(DUMP_TIMEOUT)) {
- pw.println("... dump timed out after " + DUMP_TIMEOUT + "ms");
- }
- pw.print("Exempted: [");
- for (int type = mExemptedDownstreams.nextSetBit(0); type >= 0;
- type = mExemptedDownstreams.nextSetBit(type + 1)) {
- pw.print(typeString(type));
- pw.print(", ");
- }
- pw.println("]");
- }
-
- private static String typeString(int type) {
- switch (type) {
- case TETHERING_BLUETOOTH: return "TETHERING_BLUETOOTH";
- case TETHERING_INVALID: return "TETHERING_INVALID";
- case TETHERING_USB: return "TETHERING_USB";
- case TETHERING_WIFI: return "TETHERING_WIFI";
- default:
- return String.format("TETHERING UNKNOWN TYPE (%d)", type);
- }
- }
-
- private static String errorString(int value) {
- switch (value) {
- case TETHER_ERROR_ENTITLEMENT_UNKNOWN: return "TETHER_ERROR_ENTITLEMENT_UNKONWN";
- case TETHER_ERROR_NO_ERROR: return "TETHER_ERROR_NO_ERROR";
- case TETHER_ERROR_PROVISIONING_FAILED: return "TETHER_ERROR_PROVISIONING_FAILED";
- default:
- return String.format("UNKNOWN ERROR (%d)", value);
- }
- }
-
- private ResultReceiver buildProxyReceiver(int type, boolean notifyFail,
- final ResultReceiver receiver) {
- ResultReceiver rr = new ResultReceiver(mHandler) {
- @Override
- protected void onReceiveResult(int resultCode, Bundle resultData) {
- int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
- addDownstreamMapping(type, updatedCacheValue);
- if (updatedCacheValue == TETHER_ERROR_PROVISIONING_FAILED && notifyFail) {
- mListener.onUiEntitlementFailed(type);
- }
- if (receiver != null) receiver.send(updatedCacheValue, null);
- }
- };
-
- return writeToParcel(rr);
- }
-
- // Instances of ResultReceiver need to be public classes for remote processes to be able
- // to load them (otherwise, ClassNotFoundException). For private classes, this method
- // performs a trick : round-trip parceling any instance of ResultReceiver will return a
- // vanilla instance of ResultReceiver sharing the binder token with the original receiver.
- // The binder token has a reference to the original instance of the private class and will
- // still call its methods, and can be sent over. However it cannot be used for anything
- // else than sending over a Binder call.
- // While round-trip parceling is not great, there is currently no other way of generating
- // a vanilla instance of ResultReceiver because all its fields are private.
- private ResultReceiver writeToParcel(final ResultReceiver receiver) {
- Parcel parcel = Parcel.obtain();
- receiver.writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel);
- parcel.recycle();
- return receiverForSending;
- }
-
- /**
- * Update the last entitlement value to internal cache
- *
- * @param type tethering type from TetheringManager.TETHERING_{@code *}
- * @param resultCode last entitlement value
- * @return the last updated entitlement value
- */
- private int updateEntitlementCacheValue(int type, int resultCode) {
- if (DBG) {
- mLog.i("updateEntitlementCacheValue: " + type + ", result: " + resultCode);
- }
- if (resultCode == TETHER_ERROR_NO_ERROR) {
- mEntitlementCacheValue.put(type, resultCode);
- return resultCode;
- } else {
- mEntitlementCacheValue.put(type, TETHER_ERROR_PROVISIONING_FAILED);
- return TETHER_ERROR_PROVISIONING_FAILED;
- }
- }
-
- /** Get the last value of the tethering entitlement check. */
- public void requestLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver,
- boolean showEntitlementUi) {
- if (!isValidDownstreamType(downstream)) {
- receiver.send(TETHER_ERROR_ENTITLEMENT_UNKNOWN, null);
- return;
- }
-
- final TetheringConfiguration config = mFetcher.fetchTetheringConfiguration();
- if (!isTetherProvisioningRequired(config)) {
- receiver.send(TETHER_ERROR_NO_ERROR, null);
- return;
- }
-
- final int cacheValue = mEntitlementCacheValue.get(
- downstream, TETHER_ERROR_ENTITLEMENT_UNKNOWN);
- if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
- receiver.send(cacheValue, null);
- } else {
- ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver);
- runUiTetherProvisioning(downstream, config, proxy);
- }
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java
deleted file mode 100644
index f3dcaa2529e77..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/IPv6TetheringCoordinator.java
+++ /dev/null
@@ -1,328 +0,0 @@
-/*
- * Copyright (C) 2016 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 android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.RouteInfo;
-import android.net.ip.IpServer;
-import android.net.util.NetworkConstants;
-import android.net.util.SharedLog;
-import android.util.Log;
-
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.LinkedList;
-import java.util.Random;
-
-
-/**
- * IPv6 tethering is rather different from IPv4 owing to the absence of NAT.
- * This coordinator is responsible for evaluating the dedicated prefixes
- * assigned to the device and deciding how to divvy them up among downstream
- * interfaces.
- *
- * @hide
- */
-public class IPv6TetheringCoordinator {
- private static final String TAG = IPv6TetheringCoordinator.class.getSimpleName();
- private static final boolean DBG = false;
- private static final boolean VDBG = false;
-
- private static class Downstream {
- public final IpServer ipServer;
- public final int mode; // IpServer.STATE_*
- // Used to append to a ULA /48, constructing a ULA /64 for local use.
- public final short subnetId;
-
- Downstream(IpServer ipServer, int mode, short subnetId) {
- this.ipServer = ipServer;
- this.mode = mode;
- this.subnetId = subnetId;
- }
- }
-
- private final ArrayList mNotifyList;
- private final SharedLog mLog;
- // NOTE: mActiveDownstreams is a list and not a hash data structure because
- // we keep active downstreams in arrival order. This is done so /64s can
- // be parceled out on a "first come, first served" basis and a /64 used by
- // a downstream that is no longer active can be redistributed to any next
- // waiting active downstream (again, in arrival order).
- private final LinkedList mActiveDownstreams;
- private final byte[] mUniqueLocalPrefix;
- private short mNextSubnetId;
- private UpstreamNetworkState mUpstreamNetworkState;
-
- public IPv6TetheringCoordinator(ArrayList notifyList, SharedLog log) {
- mNotifyList = notifyList;
- mLog = log.forSubComponent(TAG);
- mActiveDownstreams = new LinkedList<>();
- mUniqueLocalPrefix = generateUniqueLocalPrefix();
- mNextSubnetId = 0;
- }
-
- /** Add active downstream to ipv6 tethering candidate list. */
- public void addActiveDownstream(IpServer downstream, int mode) {
- if (findDownstream(downstream) == null) {
- // Adding a new downstream appends it to the list. Adding a
- // downstream a second time without first removing it has no effect.
- // We never change the mode of a downstream except by first removing
- // it and then re-adding it (with its new mode specified);
- if (mActiveDownstreams.offer(new Downstream(downstream, mode, mNextSubnetId))) {
- // Make sure subnet IDs are always positive. They are appended
- // to a ULA /48 to make a ULA /64 for local use.
- mNextSubnetId = (short) Math.max(0, mNextSubnetId + 1);
- }
- updateIPv6TetheringInterfaces();
- }
- }
-
- /** Remove downstream from ipv6 tethering candidate list. */
- public void removeActiveDownstream(IpServer downstream) {
- stopIPv6TetheringOn(downstream);
- if (mActiveDownstreams.remove(findDownstream(downstream))) {
- updateIPv6TetheringInterfaces();
- }
-
- // When tethering is stopping we can reset the subnet counter.
- if (mNotifyList.isEmpty()) {
- if (!mActiveDownstreams.isEmpty()) {
- Log.wtf(TAG, "Tethering notify list empty, IPv6 downstreams non-empty.");
- }
- mNextSubnetId = 0;
- }
- }
-
- /**
- * Call when UpstreamNetworkState may be changed.
- * If upstream has ipv6 for tethering, update this new UpstreamNetworkState
- * to IpServer. Otherwise stop ipv6 tethering on downstream interfaces.
- */
- public void updateUpstreamNetworkState(UpstreamNetworkState ns) {
- if (VDBG) {
- Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
- }
- if (TetheringInterfaceUtils.getIPv6Interface(ns) == null) {
- stopIPv6TetheringOnAllInterfaces();
- setUpstreamNetworkState(null);
- return;
- }
-
- if (mUpstreamNetworkState != null
- && !ns.network.equals(mUpstreamNetworkState.network)) {
- stopIPv6TetheringOnAllInterfaces();
- }
-
- setUpstreamNetworkState(ns);
- updateIPv6TetheringInterfaces();
- }
-
- private void stopIPv6TetheringOnAllInterfaces() {
- for (IpServer ipServer : mNotifyList) {
- stopIPv6TetheringOn(ipServer);
- }
- }
-
- private void setUpstreamNetworkState(UpstreamNetworkState ns) {
- if (ns == null) {
- mUpstreamNetworkState = null;
- } else {
- // Make a deep copy of the parts we need.
- mUpstreamNetworkState = new UpstreamNetworkState(
- new LinkProperties(ns.linkProperties),
- new NetworkCapabilities(ns.networkCapabilities),
- new Network(ns.network));
- }
-
- mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
- }
-
- private void updateIPv6TetheringInterfaces() {
- for (IpServer ipServer : mNotifyList) {
- final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer);
- ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, getTtlAdjustment(), 0, lp);
- break;
- }
- }
-
- private int getTtlAdjustment() {
- if (mUpstreamNetworkState == null || mUpstreamNetworkState.networkCapabilities == null) {
- return 0;
- }
-
- // If upstream is cellular, set the TTL in Router Advertisements to "network-set TTL" - 1
- // for carrier requirement.
- if (mUpstreamNetworkState.networkCapabilities.hasTransport(
- NetworkCapabilities.TRANSPORT_CELLULAR)) {
- return -1;
- }
-
- // For other non-cellular upstream, set TTL as "network-set TTL" + 1 to preventing arbitrary
- // distinction between tethered and untethered traffic.
- return 1;
- }
-
- private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) {
- final Downstream ds = findDownstream(ipServer);
- if (ds == null) return null;
-
- if (ds.mode == IpServer.STATE_LOCAL_ONLY) {
- // Build a Unique Locally-assigned Prefix configuration.
- return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
- }
-
- // This downstream is in IpServer.STATE_TETHERED mode.
- if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) {
- return null;
- }
-
- // NOTE: Here, in future, we would have policies to decide how to divvy
- // up the available dedicated prefixes among downstream interfaces.
- // At this time we have no such mechanism--we only support tethering
- // IPv6 toward the oldest (first requested) active downstream.
-
- final Downstream currentActive = mActiveDownstreams.peek();
- if (currentActive != null && currentActive.ipServer == ipServer) {
- final LinkProperties lp = getIPv6OnlyLinkProperties(
- mUpstreamNetworkState.linkProperties);
- if (lp.hasIpv6DefaultRoute() && lp.hasGlobalIpv6Address()) {
- return lp;
- }
- }
-
- return null;
- }
-
- Downstream findDownstream(IpServer ipServer) {
- for (Downstream ds : mActiveDownstreams) {
- if (ds.ipServer == ipServer) return ds;
- }
- return null;
- }
-
- private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) {
- final LinkProperties v6only = new LinkProperties();
- if (lp == null) {
- return v6only;
- }
-
- // NOTE: At this time we don't copy over any information about any
- // stacked links. No current stacked link configuration has IPv6.
-
- v6only.setInterfaceName(lp.getInterfaceName());
-
- v6only.setMtu(lp.getMtu());
-
- for (LinkAddress linkAddr : lp.getLinkAddresses()) {
- if (linkAddr.isGlobalPreferred() && linkAddr.getPrefixLength() == 64) {
- v6only.addLinkAddress(linkAddr);
- }
- }
-
- for (RouteInfo routeInfo : lp.getRoutes()) {
- final IpPrefix destination = routeInfo.getDestination();
- if ((destination.getAddress() instanceof Inet6Address)
- && (destination.getPrefixLength() <= 64)) {
- v6only.addRoute(routeInfo);
- }
- }
-
- for (InetAddress dnsServer : lp.getDnsServers()) {
- if (isIPv6GlobalAddress(dnsServer)) {
- // For now we include ULAs.
- v6only.addDnsServer(dnsServer);
- }
- }
-
- v6only.setDomains(lp.getDomains());
-
- return v6only;
- }
-
- // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we
- // announce our own IPv6 address as DNS server.
- private static boolean isIPv6GlobalAddress(InetAddress ip) {
- return (ip instanceof Inet6Address)
- && !ip.isAnyLocalAddress()
- && !ip.isLoopbackAddress()
- && !ip.isLinkLocalAddress()
- && !ip.isSiteLocalAddress()
- && !ip.isMulticastAddress();
- }
-
- private static LinkProperties getUniqueLocalConfig(byte[] ulp, short subnetId) {
- final LinkProperties lp = new LinkProperties();
-
- final IpPrefix local48 = makeUniqueLocalPrefix(ulp, (short) 0, 48);
- lp.addRoute(new RouteInfo(local48, null, null, RouteInfo.RTN_UNICAST));
-
- final IpPrefix local64 = makeUniqueLocalPrefix(ulp, subnetId, 64);
- // Because this is a locally-generated ULA, we don't have an upstream
- // address. But because the downstream IP address management code gets
- // its prefix from the upstream's IP address, we create a fake one here.
- lp.addLinkAddress(new LinkAddress(local64.getAddress(), 64));
-
- lp.setMtu(NetworkConstants.ETHER_MTU);
- return lp;
- }
-
- private static IpPrefix makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen) {
- final byte[] bytes = Arrays.copyOf(in6addr, in6addr.length);
- bytes[7] = (byte) (subnetId >> 8);
- bytes[8] = (byte) subnetId;
- final InetAddress addr;
- try {
- addr = InetAddress.getByAddress(bytes);
- } catch (UnknownHostException e) {
- throw new IllegalStateException("Invalid address length: " + bytes.length, e);
- }
- return new IpPrefix(addr, prefixlen);
- }
-
- // Generates a Unique Locally-assigned Prefix:
- //
- // https://tools.ietf.org/html/rfc4193#section-3.1
- //
- // The result is a /48 that can be used for local-only communications.
- private static byte[] generateUniqueLocalPrefix() {
- final byte[] ulp = new byte[6]; // 6 = 48bits / 8bits/byte
- (new Random()).nextBytes(ulp);
-
- final byte[] in6addr = Arrays.copyOf(ulp, NetworkConstants.IPV6_ADDR_LEN);
- in6addr[0] = (byte) 0xfd; // fc00::/7 and L=1
-
- return in6addr;
- }
-
- private static String toDebugString(UpstreamNetworkState ns) {
- if (ns == null) {
- return "UpstreamNetworkState{null}";
- }
- return ns.toString();
- }
-
- private static void stopIPv6TetheringOn(IpServer ipServer) {
- ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java
deleted file mode 100644
index 88c77b07e7e39..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/OffloadController.java
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- * Copyright (C) 2017 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 static android.net.NetworkStats.DEFAULT_NETWORK_NO;
-import static android.net.NetworkStats.METERED_NO;
-import static android.net.NetworkStats.ROAMING_NO;
-import static android.net.NetworkStats.SET_DEFAULT;
-import static android.net.NetworkStats.TAG_NONE;
-import static android.net.NetworkStats.UID_ALL;
-import static android.net.NetworkStats.UID_TETHERING;
-import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED;
-import static android.provider.Settings.Global.TETHER_OFFLOAD_DISABLED;
-
-import static com.android.networkstack.tethering.TetheringConfiguration.DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.usage.NetworkStatsManager;
-import android.content.ContentResolver;
-import android.net.InetAddresses;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.NetworkStats;
-import android.net.NetworkStats.Entry;
-import android.net.RouteInfo;
-import android.net.netlink.ConntrackMessage;
-import android.net.netlink.NetlinkConstants;
-import android.net.netlink.NetlinkSocket;
-import android.net.netstats.provider.NetworkStatsProvider;
-import android.net.util.SharedLog;
-import android.os.Handler;
-import android.provider.Settings;
-import android.system.ErrnoException;
-import android.system.OsConstants;
-import android.text.TextUtils;
-import android.util.Log;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.networkstack.tethering.OffloadHardwareInterface.ForwardedStats;
-
-import java.net.Inet4Address;
-import java.net.Inet6Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-/**
- * A class to encapsulate the business logic of programming the tethering
- * hardware offload interface.
- *
- * @hide
- */
-public class OffloadController {
- private static final String TAG = OffloadController.class.getSimpleName();
- private static final boolean DBG = false;
- private static final String ANYIP = "0.0.0.0";
- private static final ForwardedStats EMPTY_STATS = new ForwardedStats();
-
- @VisibleForTesting
- enum StatsType {
- STATS_PER_IFACE,
- STATS_PER_UID,
- }
-
- private enum UpdateType { IF_NEEDED, FORCE };
-
- private final Handler mHandler;
- private final OffloadHardwareInterface mHwInterface;
- private final ContentResolver mContentResolver;
- @Nullable
- private final OffloadTetheringStatsProvider mStatsProvider;
- private final SharedLog mLog;
- private final HashMap mDownstreams;
- private boolean mConfigInitialized;
- private boolean mControlInitialized;
- private LinkProperties mUpstreamLinkProperties;
- // The complete set of offload-exempt prefixes passed in via Tethering from
- // all upstream and downstream sources.
- private Set mExemptPrefixes;
- // A strictly "smaller" set of prefixes, wherein offload-approved prefixes
- // (e.g. downstream on-link prefixes) have been removed and replaced with
- // prefixes representing only the locally-assigned IP addresses.
- private Set mLastLocalPrefixStrs;
-
- // Maps upstream interface names to offloaded traffic statistics.
- // Always contains the latest value received from the hardware for each interface, regardless of
- // whether offload is currently running on that interface.
- private ConcurrentHashMap mForwardedStats =
- new ConcurrentHashMap<>(16, 0.75F, 1);
-
- // Maps upstream interface names to interface quotas.
- // Always contains the latest value received from the framework for each interface, regardless
- // of whether offload is currently running (or is even supported) on that interface. Only
- // includes upstream interfaces that have a quota set.
- private HashMap mInterfaceQuotas = new HashMap<>();
-
- // Tracking remaining alert quota. Unlike limit quota is subject to interface, the alert
- // quota is interface independent and global for tether offload. Note that this is only
- // accessed on the handler thread and in the constructor.
- private long mRemainingAlertQuota = QUOTA_UNLIMITED;
- // Runnable that used to schedule the next stats poll.
- private final Runnable mScheduledPollingTask = () -> {
- updateStatsForCurrentUpstream();
- maybeSchedulePollingStats();
- };
-
- private int mNatUpdateCallbacksReceived;
- private int mNatUpdateNetlinkErrors;
-
- @NonNull
- private final Dependencies mDeps;
-
- // TODO: Put more parameters in constructor into dependency object.
- interface Dependencies {
- @NonNull
- TetheringConfiguration getTetherConfig();
- }
-
- public OffloadController(Handler h, OffloadHardwareInterface hwi,
- ContentResolver contentResolver, NetworkStatsManager nsm, SharedLog log,
- @NonNull Dependencies deps) {
- mHandler = h;
- mHwInterface = hwi;
- mContentResolver = contentResolver;
- mLog = log.forSubComponent(TAG);
- mDownstreams = new HashMap<>();
- mExemptPrefixes = new HashSet<>();
- mLastLocalPrefixStrs = new HashSet<>();
- OffloadTetheringStatsProvider provider = new OffloadTetheringStatsProvider();
- try {
- nsm.registerNetworkStatsProvider(getClass().getSimpleName(), provider);
- } catch (RuntimeException e) {
- Log.wtf(TAG, "Cannot register offload stats provider: " + e);
- provider = null;
- }
- mStatsProvider = provider;
- mDeps = deps;
- }
-
- /** Start hardware offload. */
- public boolean start() {
- if (started()) return true;
-
- if (isOffloadDisabled()) {
- mLog.i("tethering offload disabled");
- return false;
- }
-
- if (!mConfigInitialized) {
- mConfigInitialized = mHwInterface.initOffloadConfig();
- if (!mConfigInitialized) {
- mLog.i("tethering offload config not supported");
- stop();
- return false;
- }
- }
-
- mControlInitialized = mHwInterface.initOffloadControl(
- // OffloadHardwareInterface guarantees that these callback
- // methods are called on the handler passed to it, which is the
- // same as mHandler, as coordinated by the setup in Tethering.
- new OffloadHardwareInterface.ControlCallback() {
- @Override
- public void onStarted() {
- if (!started()) return;
- mLog.log("onStarted");
- }
-
- @Override
- public void onStoppedError() {
- if (!started()) return;
- mLog.log("onStoppedError");
- }
-
- @Override
- public void onStoppedUnsupported() {
- if (!started()) return;
- mLog.log("onStoppedUnsupported");
- // Poll for statistics and trigger a sweep of tethering
- // stats by observers. This might not succeed, but it's
- // worth trying anyway. We need to do this because from
- // this point on we continue with software forwarding,
- // and we need to synchronize stats and limits between
- // software and hardware forwarding.
- updateStatsForAllUpstreams();
- if (mStatsProvider != null) mStatsProvider.pushTetherStats();
- }
-
- @Override
- public void onSupportAvailable() {
- if (!started()) return;
- mLog.log("onSupportAvailable");
-
- // [1] Poll for statistics and trigger a sweep of stats
- // by observers. We need to do this to ensure that any
- // limits set take into account any software tethering
- // traffic that has been happening in the meantime.
- updateStatsForAllUpstreams();
- if (mStatsProvider != null) mStatsProvider.pushTetherStats();
- // [2] (Re)Push all state.
- computeAndPushLocalPrefixes(UpdateType.FORCE);
- pushAllDownstreamState();
- pushUpstreamParameters(null);
- }
-
- @Override
- public void onStoppedLimitReached() {
- if (!started()) return;
- mLog.log("onStoppedLimitReached");
-
- // We cannot reliably determine on which interface the limit was reached,
- // because the HAL interface does not specify it. We cannot just use the
- // current upstream, because that might have changed since the time that
- // the HAL queued the callback.
- // TODO: rev the HAL so that it provides an interface name.
-
- updateStatsForCurrentUpstream();
- if (mStatsProvider != null) {
- mStatsProvider.pushTetherStats();
- // Push stats to service does not cause the service react to it
- // immediately. Inform the service about limit reached.
- mStatsProvider.notifyLimitReached();
- }
- }
-
- @Override
- public void onNatTimeoutUpdate(int proto,
- String srcAddr, int srcPort,
- String dstAddr, int dstPort) {
- if (!started()) return;
- updateNatTimeout(proto, srcAddr, srcPort, dstAddr, dstPort);
- }
- });
-
- final boolean isStarted = started();
- if (!isStarted) {
- mLog.i("tethering offload control not supported");
- stop();
- } else {
- mLog.log("tethering offload started");
- mNatUpdateCallbacksReceived = 0;
- mNatUpdateNetlinkErrors = 0;
- maybeSchedulePollingStats();
- }
- return isStarted;
- }
-
- /** Stop hardware offload. */
- public void stop() {
- // Completely stops tethering offload. After this method is called, it is no longer safe to
- // call any HAL method, no callbacks from the hardware will be delivered, and any in-flight
- // callbacks must be ignored. Offload may be started again by calling start().
- final boolean wasStarted = started();
- updateStatsForCurrentUpstream();
- mUpstreamLinkProperties = null;
- mHwInterface.stopOffloadControl();
- mControlInitialized = false;
- mConfigInitialized = false;
- if (mHandler.hasCallbacks(mScheduledPollingTask)) {
- mHandler.removeCallbacks(mScheduledPollingTask);
- }
- if (wasStarted) mLog.log("tethering offload stopped");
- }
-
- private boolean started() {
- return mConfigInitialized && mControlInitialized;
- }
-
- @VisibleForTesting
- class OffloadTetheringStatsProvider extends NetworkStatsProvider {
- // These stats must only ever be touched on the handler thread.
- @NonNull
- private NetworkStats mIfaceStats = new NetworkStats(0L, 0);
- @NonNull
- private NetworkStats mUidStats = new NetworkStats(0L, 0);
-
- /**
- * A helper function that collect tether stats from local hashmap. Note that this does not
- * invoke binder call.
- */
- @VisibleForTesting
- @NonNull
- NetworkStats getTetherStats(@NonNull StatsType how) {
- NetworkStats stats = new NetworkStats(0L, 0);
- final int uid = (how == StatsType.STATS_PER_UID) ? UID_TETHERING : UID_ALL;
-
- for (final Map.Entry kv : mForwardedStats.entrySet()) {
- final ForwardedStats value = kv.getValue();
- final Entry entry = new Entry(kv.getKey(), uid, SET_DEFAULT, TAG_NONE, METERED_NO,
- ROAMING_NO, DEFAULT_NETWORK_NO, value.rxBytes, 0L, value.txBytes, 0L, 0L);
- stats = stats.addEntry(entry);
- }
-
- return stats;
- }
-
- @Override
- public void onSetLimit(String iface, long quotaBytes) {
- // Listen for all iface is necessary since upstream might be changed after limit
- // is set.
- mHandler.post(() -> {
- final Long curIfaceQuota = mInterfaceQuotas.get(iface);
-
- // If the quota is set to unlimited, the value set to HAL is Long.MAX_VALUE,
- // which is ~8.4 x 10^6 TiB, no one can actually reach it. Thus, it is not
- // useful to set it multiple times.
- // Otherwise, the quota needs to be updated to tell HAL to re-count from now even
- // if the quota is the same as the existing one.
- if (null == curIfaceQuota && QUOTA_UNLIMITED == quotaBytes) return;
-
- if (quotaBytes == QUOTA_UNLIMITED) {
- mInterfaceQuotas.remove(iface);
- } else {
- mInterfaceQuotas.put(iface, quotaBytes);
- }
- maybeUpdateDataLimit(iface);
- });
- }
-
- /**
- * Push stats to service, but does not cause a force polling. Note that this can only be
- * called on the handler thread.
- */
- public void pushTetherStats() {
- // TODO: remove the accumulated stats and report the diff from HAL directly.
- final NetworkStats ifaceDiff =
- getTetherStats(StatsType.STATS_PER_IFACE).subtract(mIfaceStats);
- final NetworkStats uidDiff =
- getTetherStats(StatsType.STATS_PER_UID).subtract(mUidStats);
- try {
- notifyStatsUpdated(0 /* token */, ifaceDiff, uidDiff);
- mIfaceStats = mIfaceStats.add(ifaceDiff);
- mUidStats = mUidStats.add(uidDiff);
- } catch (RuntimeException e) {
- mLog.e("Cannot report network stats: ", e);
- }
- }
-
- @Override
- public void onRequestStatsUpdate(int token) {
- // Do not attempt to update stats by querying the offload HAL
- // synchronously from a different thread than the Handler thread. http://b/64771555.
- mHandler.post(() -> {
- updateStatsForCurrentUpstream();
- pushTetherStats();
- });
- }
-
- @Override
- public void onSetAlert(long quotaBytes) {
- // TODO: Ask offload HAL to notify alert without stopping traffic.
- // Post it to handler thread since it access remaining quota bytes.
- mHandler.post(() -> {
- updateAlertQuota(quotaBytes);
- maybeSchedulePollingStats();
- });
- }
- }
-
- private String currentUpstreamInterface() {
- return (mUpstreamLinkProperties != null)
- ? mUpstreamLinkProperties.getInterfaceName() : null;
- }
-
- private void maybeUpdateStats(String iface) {
- if (TextUtils.isEmpty(iface)) {
- return;
- }
-
- // Always called on the handler thread.
- //
- // Use get()/put() instead of updating ForwardedStats in place because we can be called
- // concurrently with getTetherStats. In combination with the guarantees provided by
- // ConcurrentHashMap, this ensures that getTetherStats always gets the most recent copy of
- // the stats for each interface, and does not observe partial writes where rxBytes is
- // updated and txBytes is not.
- ForwardedStats diff = mHwInterface.getForwardedStats(iface);
- final long usedAlertQuota = diff.rxBytes + diff.txBytes;
- ForwardedStats base = mForwardedStats.get(iface);
- if (base != null) {
- diff.add(base);
- }
-
- // Update remaining alert quota if it is still positive.
- if (mRemainingAlertQuota > 0 && usedAlertQuota > 0) {
- // Trim to zero if overshoot.
- final long newQuota = Math.max(mRemainingAlertQuota - usedAlertQuota, 0);
- updateAlertQuota(newQuota);
- }
-
- mForwardedStats.put(iface, diff);
- // diff is a new object, just created by getForwardedStats(). Therefore, anyone reading from
- // mForwardedStats (i.e., any caller of getTetherStats) will see the new stats immediately.
- }
-
- /**
- * Update remaining alert quota, fire the {@link NetworkStatsProvider#notifyAlertReached()}
- * callback when it reaches zero. This can be invoked either from service setting the alert, or
- * {@code maybeUpdateStats} when updating stats. Note that this can be only called on
- * handler thread.
- *
- * @param newQuota non-negative value to indicate the new quota, or
- * {@link NetworkStatsProvider#QUOTA_UNLIMITED} to indicate there is no
- * quota.
- */
- private void updateAlertQuota(long newQuota) {
- if (newQuota < QUOTA_UNLIMITED) {
- throw new IllegalArgumentException("invalid quota value " + newQuota);
- }
- if (mRemainingAlertQuota == newQuota) return;
-
- mRemainingAlertQuota = newQuota;
- if (mRemainingAlertQuota == 0) {
- mLog.i("notifyAlertReached");
- if (mStatsProvider != null) mStatsProvider.notifyAlertReached();
- }
- }
-
- /**
- * Schedule polling if needed, this will be stopped if offload has been
- * stopped or remaining quota reaches zero or upstream is empty.
- * Note that this can be only called on handler thread.
- */
- private void maybeSchedulePollingStats() {
- if (!isPollingStatsNeeded()) return;
-
- if (mHandler.hasCallbacks(mScheduledPollingTask)) {
- mHandler.removeCallbacks(mScheduledPollingTask);
- }
- mHandler.postDelayed(mScheduledPollingTask,
- mDeps.getTetherConfig().getOffloadPollInterval());
- }
-
- private boolean isPollingStatsNeeded() {
- return started() && mRemainingAlertQuota > 0
- && !TextUtils.isEmpty(currentUpstreamInterface())
- && mDeps.getTetherConfig() != null
- && mDeps.getTetherConfig().getOffloadPollInterval()
- >= DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS;
- }
-
- private boolean maybeUpdateDataLimit(String iface) {
- // setDataLimit may only be called while offload is occurring on this upstream.
- if (!started() || !TextUtils.equals(iface, currentUpstreamInterface())) {
- return true;
- }
-
- Long limit = mInterfaceQuotas.get(iface);
- if (limit == null) {
- limit = Long.MAX_VALUE;
- }
-
- return mHwInterface.setDataLimit(iface, limit);
- }
-
- private void updateStatsForCurrentUpstream() {
- maybeUpdateStats(currentUpstreamInterface());
- }
-
- private void updateStatsForAllUpstreams() {
- // In practice, there should only ever be a single digit number of
- // upstream interfaces over the lifetime of an active tethering session.
- // Roughly speaking, imagine a very ambitious one or two of each of the
- // following interface types: [ "rmnet_data", "wlan", "eth", "rndis" ].
- for (Map.Entry kv : mForwardedStats.entrySet()) {
- maybeUpdateStats(kv.getKey());
- }
- }
-
- /** Set current tethering upstream LinkProperties. */
- public void setUpstreamLinkProperties(LinkProperties lp) {
- if (!started() || Objects.equals(mUpstreamLinkProperties, lp)) return;
-
- final String prevUpstream = currentUpstreamInterface();
-
- mUpstreamLinkProperties = (lp != null) ? new LinkProperties(lp) : null;
- // Make sure we record this interface in the ForwardedStats map.
- final String iface = currentUpstreamInterface();
- if (!TextUtils.isEmpty(iface)) mForwardedStats.putIfAbsent(iface, EMPTY_STATS);
-
- maybeSchedulePollingStats();
-
- // TODO: examine return code and decide what to do if programming
- // upstream parameters fails (probably just wait for a subsequent
- // onOffloadEvent() callback to tell us offload is available again and
- // then reapply all state).
- computeAndPushLocalPrefixes(UpdateType.IF_NEEDED);
- pushUpstreamParameters(prevUpstream);
- }
-
- /** Set local prefixes. */
- public void setLocalPrefixes(Set localPrefixes) {
- mExemptPrefixes = localPrefixes;
-
- if (!started()) return;
- computeAndPushLocalPrefixes(UpdateType.IF_NEEDED);
- }
-
- /** Update current downstream LinkProperties. */
- public void notifyDownstreamLinkProperties(LinkProperties lp) {
- final String ifname = lp.getInterfaceName();
- final LinkProperties oldLp = mDownstreams.put(ifname, new LinkProperties(lp));
- if (Objects.equals(oldLp, lp)) return;
-
- if (!started()) return;
- pushDownstreamState(oldLp, lp);
- }
-
- private void pushDownstreamState(LinkProperties oldLp, LinkProperties newLp) {
- final String ifname = newLp.getInterfaceName();
- final List oldRoutes =
- (oldLp != null) ? oldLp.getRoutes() : Collections.EMPTY_LIST;
- final List newRoutes = newLp.getRoutes();
-
- // For each old route, if not in new routes: remove.
- for (RouteInfo ri : oldRoutes) {
- if (shouldIgnoreDownstreamRoute(ri)) continue;
- if (!newRoutes.contains(ri)) {
- mHwInterface.removeDownstreamPrefix(ifname, ri.getDestination().toString());
- }
- }
-
- // For each new route, if not in old routes: add.
- for (RouteInfo ri : newRoutes) {
- if (shouldIgnoreDownstreamRoute(ri)) continue;
- if (!oldRoutes.contains(ri)) {
- mHwInterface.addDownstreamPrefix(ifname, ri.getDestination().toString());
- }
- }
- }
-
- private void pushAllDownstreamState() {
- for (LinkProperties lp : mDownstreams.values()) {
- pushDownstreamState(null, lp);
- }
- }
-
- /** Remove downstream interface from offload hardware. */
- public void removeDownstreamInterface(String ifname) {
- final LinkProperties lp = mDownstreams.remove(ifname);
- if (lp == null) return;
-
- if (!started()) return;
-
- for (RouteInfo route : lp.getRoutes()) {
- if (shouldIgnoreDownstreamRoute(route)) continue;
- mHwInterface.removeDownstreamPrefix(ifname, route.getDestination().toString());
- }
- }
-
- private boolean isOffloadDisabled() {
- final int defaultDisposition = mHwInterface.getDefaultTetherOffloadDisabled();
- return (Settings.Global.getInt(
- mContentResolver, TETHER_OFFLOAD_DISABLED, defaultDisposition) != 0);
- }
-
- private boolean pushUpstreamParameters(String prevUpstream) {
- final String iface = currentUpstreamInterface();
-
- if (TextUtils.isEmpty(iface)) {
- final boolean rval = mHwInterface.setUpstreamParameters("", ANYIP, ANYIP, null);
- // Update stats after we've told the hardware to stop forwarding so
- // we don't miss packets.
- maybeUpdateStats(prevUpstream);
- return rval;
- }
-
- // A stacked interface cannot be an upstream for hardware offload.
- // Consequently, we examine only the primary interface name, look at
- // getAddresses() rather than getAllAddresses(), and check getRoutes()
- // rather than getAllRoutes().
- final ArrayList v6gateways = new ArrayList<>();
- String v4addr = null;
- String v4gateway = null;
-
- for (InetAddress ip : mUpstreamLinkProperties.getAddresses()) {
- if (ip instanceof Inet4Address) {
- v4addr = ip.getHostAddress();
- break;
- }
- }
-
- // Find the gateway addresses of all default routes of either address family.
- for (RouteInfo ri : mUpstreamLinkProperties.getRoutes()) {
- if (!ri.hasGateway()) continue;
-
- final String gateway = ri.getGateway().getHostAddress();
- final InetAddress address = ri.getDestination().getAddress();
- if (ri.isDefaultRoute() && address instanceof Inet4Address) {
- v4gateway = gateway;
- } else if (ri.isDefaultRoute() && address instanceof Inet6Address) {
- v6gateways.add(gateway);
- }
- }
-
- boolean success = mHwInterface.setUpstreamParameters(
- iface, v4addr, v4gateway, (v6gateways.isEmpty() ? null : v6gateways));
-
- if (!success) {
- return success;
- }
-
- // Update stats after we've told the hardware to change routing so we don't miss packets.
- maybeUpdateStats(prevUpstream);
-
- // Data limits can only be set once offload is running on the upstream.
- success = maybeUpdateDataLimit(iface);
- if (!success) {
- // If we failed to set a data limit, don't use this upstream, because we don't want to
- // blow through the data limit that we were told to apply.
- mLog.log("Setting data limit for " + iface + " failed, disabling offload.");
- stop();
- }
-
- return success;
- }
-
- private boolean computeAndPushLocalPrefixes(UpdateType how) {
- final boolean force = (how == UpdateType.FORCE);
- final Set localPrefixStrs = computeLocalPrefixStrings(
- mExemptPrefixes, mUpstreamLinkProperties);
- if (!force && mLastLocalPrefixStrs.equals(localPrefixStrs)) return true;
-
- mLastLocalPrefixStrs = localPrefixStrs;
- return mHwInterface.setLocalPrefixes(new ArrayList<>(localPrefixStrs));
- }
-
- // TODO: Factor in downstream LinkProperties once that information is available.
- private static Set computeLocalPrefixStrings(
- Set localPrefixes, LinkProperties upstreamLinkProperties) {
- // Create an editable copy.
- final Set prefixSet = new HashSet<>(localPrefixes);
-
- // TODO: If a downstream interface (not currently passed in) is reusing
- // the /64 of the upstream (64share) then:
- //
- // [a] remove that /64 from the local prefixes
- // [b] add in /128s for IP addresses on the downstream interface
- // [c] add in /128s for IP addresses on the upstream interface
- //
- // Until downstream information is available here, simply add /128s from
- // the upstream network; they'll just be redundant with their /64.
- if (upstreamLinkProperties != null) {
- for (LinkAddress linkAddr : upstreamLinkProperties.getLinkAddresses()) {
- if (!linkAddr.isGlobalPreferred()) continue;
- final InetAddress ip = linkAddr.getAddress();
- if (!(ip instanceof Inet6Address)) continue;
- prefixSet.add(new IpPrefix(ip, 128));
- }
- }
-
- final HashSet localPrefixStrs = new HashSet<>();
- for (IpPrefix pfx : prefixSet) localPrefixStrs.add(pfx.toString());
- return localPrefixStrs;
- }
-
- private static boolean shouldIgnoreDownstreamRoute(RouteInfo route) {
- // Ignore any link-local routes.
- final IpPrefix destination = route.getDestination();
- final LinkAddress linkAddr = new LinkAddress(destination.getAddress(),
- destination.getPrefixLength());
- if (!linkAddr.isGlobalPreferred()) return true;
-
- return false;
- }
-
- /** Dump information. */
- public void dump(IndentingPrintWriter pw) {
- if (isOffloadDisabled()) {
- pw.println("Offload disabled");
- return;
- }
- final boolean isStarted = started();
- pw.println("Offload HALs " + (isStarted ? "started" : "not started"));
- LinkProperties lp = mUpstreamLinkProperties;
- String upstream = (lp != null) ? lp.getInterfaceName() : null;
- pw.println("Current upstream: " + upstream);
- pw.println("Exempt prefixes: " + mLastLocalPrefixStrs);
- pw.println("NAT timeout update callbacks received during the "
- + (isStarted ? "current" : "last")
- + " offload session: "
- + mNatUpdateCallbacksReceived);
- pw.println("NAT timeout update netlink errors during the "
- + (isStarted ? "current" : "last")
- + " offload session: "
- + mNatUpdateNetlinkErrors);
- }
-
- private void updateNatTimeout(
- int proto, String srcAddr, int srcPort, String dstAddr, int dstPort) {
- final String protoName = protoNameFor(proto);
- if (protoName == null) {
- mLog.e("Unknown NAT update callback protocol: " + proto);
- return;
- }
-
- final Inet4Address src = parseIPv4Address(srcAddr);
- if (src == null) {
- mLog.e("Failed to parse IPv4 address: " + srcAddr);
- return;
- }
-
- if (!isValidUdpOrTcpPort(srcPort)) {
- mLog.e("Invalid src port: " + srcPort);
- return;
- }
-
- final Inet4Address dst = parseIPv4Address(dstAddr);
- if (dst == null) {
- mLog.e("Failed to parse IPv4 address: " + dstAddr);
- return;
- }
-
- if (!isValidUdpOrTcpPort(dstPort)) {
- mLog.e("Invalid dst port: " + dstPort);
- return;
- }
-
- mNatUpdateCallbacksReceived++;
- final String natDescription = String.format("%s (%s, %s) -> (%s, %s)",
- protoName, srcAddr, srcPort, dstAddr, dstPort);
- if (DBG) {
- mLog.log("NAT timeout update: " + natDescription);
- }
-
- final int timeoutSec = connectionTimeoutUpdateSecondsFor(proto);
- final byte[] msg = ConntrackMessage.newIPv4TimeoutUpdateRequest(
- proto, src, srcPort, dst, dstPort, timeoutSec);
-
- try {
- NetlinkSocket.sendOneShotKernelMessage(OsConstants.NETLINK_NETFILTER, msg);
- } catch (ErrnoException e) {
- mNatUpdateNetlinkErrors++;
- mLog.e("Error updating NAT conntrack entry >" + natDescription + "<: " + e
- + ", msg: " + NetlinkConstants.hexify(msg));
- mLog.log("NAT timeout update callbacks received: " + mNatUpdateCallbacksReceived);
- mLog.log("NAT timeout update netlink errors: " + mNatUpdateNetlinkErrors);
- }
- }
-
- private static Inet4Address parseIPv4Address(String addrString) {
- try {
- final InetAddress ip = InetAddresses.parseNumericAddress(addrString);
- // TODO: Consider other sanitization steps here, including perhaps:
- // not eql to 0.0.0.0
- // not within 169.254.0.0/16
- // not within ::ffff:0.0.0.0/96
- // not within ::/96
- // et cetera.
- if (ip instanceof Inet4Address) {
- return (Inet4Address) ip;
- }
- } catch (IllegalArgumentException iae) { }
- return null;
- }
-
- private static String protoNameFor(int proto) {
- // OsConstants values are not constant expressions; no switch statement.
- if (proto == OsConstants.IPPROTO_UDP) {
- return "UDP";
- } else if (proto == OsConstants.IPPROTO_TCP) {
- return "TCP";
- }
- return null;
- }
-
- private static int connectionTimeoutUpdateSecondsFor(int proto) {
- // TODO: Replace this with more thoughtful work, perhaps reading from
- // and maybe writing to any required
- //
- // /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_*
- // /proc/sys/net/netfilter/nf_conntrack_udp_timeout{,_stream}
- //
- // entries. TBD.
- if (proto == OsConstants.IPPROTO_TCP) {
- // Cf. /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
- return 432000;
- } else {
- // Cf. /proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream
- return 180;
- }
- }
-
- private static boolean isValidUdpOrTcpPort(int port) {
- return port > 0 && port < 65536;
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java b/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
deleted file mode 100644
index da5f25b2a596c..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/OffloadHardwareInterface.java
+++ /dev/null
@@ -1,574 +0,0 @@
-/*
- * Copyright (C) 2017 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 static android.net.netlink.StructNlMsgHdr.NLM_F_DUMP;
-import static android.net.netlink.StructNlMsgHdr.NLM_F_REQUEST;
-import static android.net.util.TetheringUtils.uint16;
-
-import android.annotation.NonNull;
-import android.hardware.tetheroffload.config.V1_0.IOffloadConfig;
-import android.hardware.tetheroffload.control.V1_0.IOffloadControl;
-import android.hardware.tetheroffload.control.V1_0.ITetheringOffloadCallback;
-import android.hardware.tetheroffload.control.V1_0.NatTimeoutUpdate;
-import android.hardware.tetheroffload.control.V1_0.NetworkProtocol;
-import android.hardware.tetheroffload.control.V1_0.OffloadCallbackEvent;
-import android.net.netlink.NetlinkSocket;
-import android.net.netlink.StructNfGenMsg;
-import android.net.netlink.StructNlMsgHdr;
-import android.net.util.SharedLog;
-import android.net.util.SocketUtils;
-import android.os.Handler;
-import android.os.NativeHandle;
-import android.os.RemoteException;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.system.OsConstants;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.FileDescriptor;
-import java.io.IOException;
-import java.io.InterruptedIOException;
-import java.net.SocketAddress;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.util.ArrayList;
-import java.util.NoSuchElementException;
-
-
-/**
- * Capture tethering dependencies, for injection.
- *
- * @hide
- */
-public class OffloadHardwareInterface {
- private static final String TAG = OffloadHardwareInterface.class.getSimpleName();
- private static final String YIELDS = " -> ";
- // Change this value to control whether tether offload is enabled or
- // disabled by default in the absence of an explicit Settings value.
- // See accompanying unittest to distinguish 0 from non-0 values.
- private static final int DEFAULT_TETHER_OFFLOAD_DISABLED = 0;
- private static final String NO_INTERFACE_NAME = "";
- private static final String NO_IPV4_ADDRESS = "";
- private static final String NO_IPV4_GATEWAY = "";
- // Reference kernel/uapi/linux/netfilter/nfnetlink_compat.h
- public static final int NF_NETLINK_CONNTRACK_NEW = 1;
- public static final int NF_NETLINK_CONNTRACK_UPDATE = 2;
- public static final int NF_NETLINK_CONNTRACK_DESTROY = 4;
- // Reference libnetfilter_conntrack/linux_nfnetlink_conntrack.h
- public static final short NFNL_SUBSYS_CTNETLINK = 1;
- public static final short IPCTNL_MSG_CT_NEW = 0;
- public static final short IPCTNL_MSG_CT_GET = 1;
-
- private final long NETLINK_MESSAGE_TIMEOUT_MS = 500;
-
- private final Handler mHandler;
- private final SharedLog mLog;
- private final Dependencies mDeps;
- private IOffloadControl mOffloadControl;
- private TetheringOffloadCallback mTetheringOffloadCallback;
- private ControlCallback mControlCallback;
-
- /** The callback to notify status of offload management process. */
- public static class ControlCallback {
- /** Offload started. */
- public void onStarted() {}
- /**
- * Offload stopped because an error has occurred in lower layer.
- */
- public void onStoppedError() {}
- /**
- * Offload stopped because the device has moved to a bearer on which hardware offload is
- * not supported. Subsequent calls to setUpstreamParameters and add/removeDownstream will
- * likely fail and cannot be presumed to be saved inside of the hardware management process.
- * Upon receiving #onSupportAvailable(), the caller should reprogram the hardware to begin
- * offload again.
- */
- public void onStoppedUnsupported() {}
- /** Indicate that offload is able to proivde support for this time. */
- public void onSupportAvailable() {}
- /** Offload stopped because of usage limit reached. */
- public void onStoppedLimitReached() {}
-
- /** Indicate to update NAT timeout. */
- public void onNatTimeoutUpdate(int proto,
- String srcAddr, int srcPort,
- String dstAddr, int dstPort) {}
- }
-
- /** The object which records Tx/Rx forwarded bytes. */
- public static class ForwardedStats {
- public long rxBytes;
- public long txBytes;
-
- public ForwardedStats() {
- rxBytes = 0;
- txBytes = 0;
- }
-
- @VisibleForTesting
- public ForwardedStats(long rxBytes, long txBytes) {
- this.rxBytes = rxBytes;
- this.txBytes = txBytes;
- }
-
- /** Add Tx/Rx bytes. */
- public void add(ForwardedStats other) {
- rxBytes += other.rxBytes;
- txBytes += other.txBytes;
- }
-
- /** Returns the string representation of this object. */
- public String toString() {
- return String.format("rx:%s tx:%s", rxBytes, txBytes);
- }
- }
-
- public OffloadHardwareInterface(Handler h, SharedLog log) {
- this(h, log, new Dependencies(log));
- }
-
- OffloadHardwareInterface(Handler h, SharedLog log, Dependencies deps) {
- mHandler = h;
- mLog = log.forSubComponent(TAG);
- mDeps = deps;
- }
-
- /** Capture OffloadHardwareInterface dependencies, for injection. */
- static class Dependencies {
- private final SharedLog mLog;
-
- Dependencies(SharedLog log) {
- mLog = log;
- }
-
- public IOffloadConfig getOffloadConfig() {
- try {
- return IOffloadConfig.getService(true /*retry*/);
- } catch (RemoteException | NoSuchElementException e) {
- mLog.e("getIOffloadConfig error " + e);
- return null;
- }
- }
-
- public IOffloadControl getOffloadControl() {
- try {
- return IOffloadControl.getService(true /*retry*/);
- } catch (RemoteException | NoSuchElementException e) {
- mLog.e("tethering offload control not supported: " + e);
- return null;
- }
- }
-
- public NativeHandle createConntrackSocket(final int groups) {
- final FileDescriptor fd;
- try {
- fd = NetlinkSocket.forProto(OsConstants.NETLINK_NETFILTER);
- } catch (ErrnoException e) {
- mLog.e("Unable to create conntrack socket " + e);
- return null;
- }
-
- final SocketAddress sockAddr = SocketUtils.makeNetlinkSocketAddress(0, groups);
- try {
- Os.bind(fd, sockAddr);
- } catch (ErrnoException | SocketException e) {
- mLog.e("Unable to bind conntrack socket for groups " + groups + " error: " + e);
- try {
- SocketUtils.closeSocket(fd);
- } catch (IOException ie) {
- // Nothing we can do here
- }
- return null;
- }
- try {
- Os.connect(fd, sockAddr);
- } catch (ErrnoException | SocketException e) {
- mLog.e("connect to kernel fail for groups " + groups + " error: " + e);
- try {
- SocketUtils.closeSocket(fd);
- } catch (IOException ie) {
- // Nothing we can do here
- }
- return null;
- }
-
- return new NativeHandle(fd, true);
- }
- }
-
- /** Get default value indicating whether offload is supported. */
- public int getDefaultTetherOffloadDisabled() {
- return DEFAULT_TETHER_OFFLOAD_DISABLED;
- }
-
- /**
- * Offload management process need to know conntrack rules to support NAT, but it may not have
- * permission to create netlink netfilter sockets. Create two netlink netfilter sockets and
- * share them with offload management process.
- */
- public boolean initOffloadConfig() {
- final IOffloadConfig offloadConfig = mDeps.getOffloadConfig();
- if (offloadConfig == null) {
- mLog.e("Could not find IOffloadConfig service");
- return false;
- }
- // Per the IConfigOffload definition:
- //
- // h1 provides a file descriptor bound to the following netlink groups
- // (NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY).
- //
- // h2 provides a file descriptor bound to the following netlink groups
- // (NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY).
- final NativeHandle h1 = mDeps.createConntrackSocket(
- NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY);
- if (h1 == null) return false;
-
- sendIpv4NfGenMsg(h1, (short) ((NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET),
- (short) (NLM_F_REQUEST | NLM_F_DUMP));
-
- final NativeHandle h2 = mDeps.createConntrackSocket(
- NF_NETLINK_CONNTRACK_UPDATE | NF_NETLINK_CONNTRACK_DESTROY);
- if (h2 == null) {
- closeFdInNativeHandle(h1);
- return false;
- }
-
- final CbResults results = new CbResults();
- try {
- offloadConfig.setHandles(h1, h2,
- (boolean success, String errMsg) -> {
- results.mSuccess = success;
- results.mErrMsg = errMsg;
- });
- } catch (RemoteException e) {
- record("initOffloadConfig, setHandles fail", e);
- return false;
- }
- // Explicitly close FDs.
- closeFdInNativeHandle(h1);
- closeFdInNativeHandle(h2);
-
- record("initOffloadConfig, setHandles results:", results);
- return results.mSuccess;
- }
-
- @VisibleForTesting
- public void sendIpv4NfGenMsg(@NonNull NativeHandle handle, short type, short flags) {
- final int length = StructNlMsgHdr.STRUCT_SIZE + StructNfGenMsg.STRUCT_SIZE;
- final byte[] msg = new byte[length];
- final ByteBuffer byteBuffer = ByteBuffer.wrap(msg);
- byteBuffer.order(ByteOrder.nativeOrder());
-
- final StructNlMsgHdr nlh = new StructNlMsgHdr();
- nlh.nlmsg_len = length;
- nlh.nlmsg_type = type;
- nlh.nlmsg_flags = flags;
- nlh.nlmsg_seq = 0;
- nlh.pack(byteBuffer);
-
- // Header needs to be added to buffer since a generic netlink request is being sent.
- final StructNfGenMsg nfh = new StructNfGenMsg((byte) OsConstants.AF_INET);
- nfh.pack(byteBuffer);
-
- try {
- NetlinkSocket.sendMessage(handle.getFileDescriptor(), msg, 0 /* offset */, length,
- NETLINK_MESSAGE_TIMEOUT_MS);
- } catch (ErrnoException | InterruptedIOException e) {
- mLog.e("Unable to send netfilter message, error: " + e);
- }
- }
-
- private void closeFdInNativeHandle(final NativeHandle h) {
- try {
- h.close();
- } catch (IOException | IllegalStateException e) {
- // IllegalStateException means fd is already closed, do nothing here.
- // Also nothing we can do if IOException.
- }
- }
-
- /** Initialize the tethering offload HAL. */
- public boolean initOffloadControl(ControlCallback controlCb) {
- mControlCallback = controlCb;
-
- if (mOffloadControl == null) {
- mOffloadControl = mDeps.getOffloadControl();
- if (mOffloadControl == null) {
- mLog.e("tethering IOffloadControl.getService() returned null");
- return false;
- }
- }
-
- final String logmsg = String.format("initOffloadControl(%s)",
- (controlCb == null) ? "null"
- : "0x" + Integer.toHexString(System.identityHashCode(controlCb)));
-
- mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, mControlCallback, mLog);
- final CbResults results = new CbResults();
- try {
- mOffloadControl.initOffload(
- mTetheringOffloadCallback,
- (boolean success, String errMsg) -> {
- results.mSuccess = success;
- results.mErrMsg = errMsg;
- });
- } catch (RemoteException e) {
- record(logmsg, e);
- return false;
- }
-
- record(logmsg, results);
- return results.mSuccess;
- }
-
- /** Stop IOffloadControl. */
- public void stopOffloadControl() {
- if (mOffloadControl != null) {
- try {
- mOffloadControl.stopOffload(
- (boolean success, String errMsg) -> {
- if (!success) mLog.e("stopOffload failed: " + errMsg);
- });
- } catch (RemoteException e) {
- mLog.e("failed to stopOffload: " + e);
- }
- }
- mOffloadControl = null;
- mTetheringOffloadCallback = null;
- mControlCallback = null;
- mLog.log("stopOffloadControl()");
- }
-
- /** Get Tx/Rx usage from last query. */
- public ForwardedStats getForwardedStats(String upstream) {
- final String logmsg = String.format("getForwardedStats(%s)", upstream);
-
- final ForwardedStats stats = new ForwardedStats();
- try {
- mOffloadControl.getForwardedStats(
- upstream,
- (long rxBytes, long txBytes) -> {
- stats.rxBytes = (rxBytes > 0) ? rxBytes : 0;
- stats.txBytes = (txBytes > 0) ? txBytes : 0;
- });
- } catch (RemoteException e) {
- record(logmsg, e);
- return stats;
- }
-
- return stats;
- }
-
- /** Set local prefixes to offload management process. */
- public boolean setLocalPrefixes(ArrayList localPrefixes) {
- final String logmsg = String.format("setLocalPrefixes([%s])",
- String.join(",", localPrefixes));
-
- final CbResults results = new CbResults();
- try {
- mOffloadControl.setLocalPrefixes(localPrefixes,
- (boolean success, String errMsg) -> {
- results.mSuccess = success;
- results.mErrMsg = errMsg;
- });
- } catch (RemoteException e) {
- record(logmsg, e);
- return false;
- }
-
- record(logmsg, results);
- return results.mSuccess;
- }
-
- /** Set data limit value to offload management process. */
- public boolean setDataLimit(String iface, long limit) {
-
- final String logmsg = String.format("setDataLimit(%s, %d)", iface, limit);
-
- final CbResults results = new CbResults();
- try {
- mOffloadControl.setDataLimit(
- iface, limit,
- (boolean success, String errMsg) -> {
- results.mSuccess = success;
- results.mErrMsg = errMsg;
- });
- } catch (RemoteException e) {
- record(logmsg, e);
- return false;
- }
-
- record(logmsg, results);
- return results.mSuccess;
- }
-
- /** Set upstream parameters to offload management process. */
- public boolean setUpstreamParameters(
- String iface, String v4addr, String v4gateway, ArrayList v6gws) {
- iface = (iface != null) ? iface : NO_INTERFACE_NAME;
- v4addr = (v4addr != null) ? v4addr : NO_IPV4_ADDRESS;
- v4gateway = (v4gateway != null) ? v4gateway : NO_IPV4_GATEWAY;
- v6gws = (v6gws != null) ? v6gws : new ArrayList<>();
-
- final String logmsg = String.format("setUpstreamParameters(%s, %s, %s, [%s])",
- iface, v4addr, v4gateway, String.join(",", v6gws));
-
- final CbResults results = new CbResults();
- try {
- mOffloadControl.setUpstreamParameters(
- iface, v4addr, v4gateway, v6gws,
- (boolean success, String errMsg) -> {
- results.mSuccess = success;
- results.mErrMsg = errMsg;
- });
- } catch (RemoteException e) {
- record(logmsg, e);
- return false;
- }
-
- record(logmsg, results);
- return results.mSuccess;
- }
-
- /** Add downstream prefix to offload management process. */
- public boolean addDownstreamPrefix(String ifname, String prefix) {
- final String logmsg = String.format("addDownstreamPrefix(%s, %s)", ifname, prefix);
-
- final CbResults results = new CbResults();
- try {
- mOffloadControl.addDownstream(ifname, prefix,
- (boolean success, String errMsg) -> {
- results.mSuccess = success;
- results.mErrMsg = errMsg;
- });
- } catch (RemoteException e) {
- record(logmsg, e);
- return false;
- }
-
- record(logmsg, results);
- return results.mSuccess;
- }
-
- /** Remove downstream prefix from offload management process. */
- public boolean removeDownstreamPrefix(String ifname, String prefix) {
- final String logmsg = String.format("removeDownstreamPrefix(%s, %s)", ifname, prefix);
-
- final CbResults results = new CbResults();
- try {
- mOffloadControl.removeDownstream(ifname, prefix,
- (boolean success, String errMsg) -> {
- results.mSuccess = success;
- results.mErrMsg = errMsg;
- });
- } catch (RemoteException e) {
- record(logmsg, e);
- return false;
- }
-
- record(logmsg, results);
- return results.mSuccess;
- }
-
- private void record(String msg, Throwable t) {
- mLog.e(msg + YIELDS + "exception: " + t);
- }
-
- private void record(String msg, CbResults results) {
- final String logmsg = msg + YIELDS + results;
- if (!results.mSuccess) {
- mLog.e(logmsg);
- } else {
- mLog.log(logmsg);
- }
- }
-
- private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
- public final Handler handler;
- public final ControlCallback controlCb;
- public final SharedLog log;
-
- TetheringOffloadCallback(Handler h, ControlCallback cb, SharedLog sharedLog) {
- handler = h;
- controlCb = cb;
- log = sharedLog;
- }
-
- @Override
- public void onEvent(int event) {
- handler.post(() -> {
- switch (event) {
- case OffloadCallbackEvent.OFFLOAD_STARTED:
- controlCb.onStarted();
- break;
- case OffloadCallbackEvent.OFFLOAD_STOPPED_ERROR:
- controlCb.onStoppedError();
- break;
- case OffloadCallbackEvent.OFFLOAD_STOPPED_UNSUPPORTED:
- controlCb.onStoppedUnsupported();
- break;
- case OffloadCallbackEvent.OFFLOAD_SUPPORT_AVAILABLE:
- controlCb.onSupportAvailable();
- break;
- case OffloadCallbackEvent.OFFLOAD_STOPPED_LIMIT_REACHED:
- controlCb.onStoppedLimitReached();
- break;
- default:
- log.e("Unsupported OffloadCallbackEvent: " + event);
- }
- });
- }
-
- @Override
- public void updateTimeout(NatTimeoutUpdate params) {
- handler.post(() -> {
- controlCb.onNatTimeoutUpdate(
- networkProtocolToOsConstant(params.proto),
- params.src.addr, uint16(params.src.port),
- params.dst.addr, uint16(params.dst.port));
- });
- }
- }
-
- private static int networkProtocolToOsConstant(int proto) {
- switch (proto) {
- case NetworkProtocol.TCP: return OsConstants.IPPROTO_TCP;
- case NetworkProtocol.UDP: return OsConstants.IPPROTO_UDP;
- default:
- // The caller checks this value and will log an error. Just make
- // sure it won't collide with valid OsContants.IPPROTO_* values.
- return -Math.abs(proto);
- }
- }
-
- private static class CbResults {
- boolean mSuccess;
- String mErrMsg;
-
- @Override
- public String toString() {
- if (mSuccess) {
- return "ok";
- } else {
- return "fail: " + mErrMsg;
- }
- }
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
deleted file mode 100644
index 4f616cdff086e..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/PrivateAddressCoordinator.java
+++ /dev/null
@@ -1,416 +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 static android.net.NetworkCapabilities.TRANSPORT_VPN;
-import static android.net.TetheringManager.TETHERING_BLUETOOTH;
-import static android.net.TetheringManager.TETHERING_WIFI_P2P;
-import static android.net.util.PrefixUtils.asIpPrefix;
-
-import static com.android.net.module.util.Inet4AddressUtils.inet4AddressToIntHTH;
-import static com.android.net.module.util.Inet4AddressUtils.intToInet4AddressHTH;
-import static com.android.net.module.util.Inet4AddressUtils.prefixLengthToV4NetmaskIntHTH;
-
-import static java.util.Arrays.asList;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.Network;
-import android.net.ip.IpServer;
-import android.util.ArrayMap;
-import android.util.ArraySet;
-import android.util.SparseArray;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
-
-import java.net.Inet4Address;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Random;
-import java.util.Set;
-
-/**
- * This class coordinate IP addresses conflict problem.
- *
- * Tethering downstream IP addresses may conflict with network assigned addresses. This
- * coordinator is responsible for recording all of network assigned addresses and dispatched
- * free address to downstream interfaces.
- *
- * This class is not thread-safe and should be accessed on the same tethering internal thread.
- * @hide
- */
-public class PrivateAddressCoordinator {
- public static final int PREFIX_LENGTH = 24;
-
- // Upstream monitor would be stopped when tethering is down. When tethering restart, downstream
- // address may be requested before coordinator get current upstream notification. To ensure
- // coordinator do not select conflict downstream prefix, mUpstreamPrefixMap would not be cleared
- // when tethering is down. Instead tethering would remove all deprecated upstreams from
- // mUpstreamPrefixMap when tethering is starting. See #maybeRemoveDeprecatedUpstreams().
- private final ArrayMap> mUpstreamPrefixMap;
- private final ArraySet mDownstreams;
- private static final String LEGACY_WIFI_P2P_IFACE_ADDRESS = "192.168.49.1/24";
- private static final String LEGACY_BLUETOOTH_IFACE_ADDRESS = "192.168.44.1/24";
- private final List mTetheringPrefixes;
- private final ConnectivityManager mConnectivityMgr;
- private final TetheringConfiguration mConfig;
- // keyed by downstream type(TetheringManager.TETHERING_*).
- private final SparseArray mCachedAddresses;
-
- public PrivateAddressCoordinator(Context context, TetheringConfiguration config) {
- mDownstreams = new ArraySet<>();
- mUpstreamPrefixMap = new ArrayMap<>();
- mConnectivityMgr = (ConnectivityManager) context.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- mConfig = config;
- mCachedAddresses = new SparseArray<>();
- // Reserved static addresses for bluetooth and wifi p2p.
- mCachedAddresses.put(TETHERING_BLUETOOTH, new LinkAddress(LEGACY_BLUETOOTH_IFACE_ADDRESS));
- mCachedAddresses.put(TETHERING_WIFI_P2P, new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS));
-
- mTetheringPrefixes = new ArrayList<>(Arrays.asList(new IpPrefix("192.168.0.0/16")));
- if (config.isSelectAllPrefixRangeEnabled()) {
- mTetheringPrefixes.add(new IpPrefix("172.16.0.0/12"));
- mTetheringPrefixes.add(new IpPrefix("10.0.0.0/8"));
- }
- }
-
- /**
- * Record a new upstream IpPrefix which may conflict with tethering downstreams.
- * The downstreams will be notified if a conflict is found. When updateUpstreamPrefix is called,
- * UpstreamNetworkState must have an already populated LinkProperties.
- */
- public void updateUpstreamPrefix(final UpstreamNetworkState ns) {
- // Do not support VPN as upstream. Normally, networkCapabilities is not expected to be null,
- // but just checking to be sure.
- if (ns.networkCapabilities != null && ns.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
- removeUpstreamPrefix(ns.network);
- return;
- }
-
- final ArrayList ipv4Prefixes = getIpv4Prefixes(
- ns.linkProperties.getAllLinkAddresses());
- if (ipv4Prefixes.isEmpty()) {
- removeUpstreamPrefix(ns.network);
- return;
- }
-
- mUpstreamPrefixMap.put(ns.network, ipv4Prefixes);
- handleMaybePrefixConflict(ipv4Prefixes);
- }
-
- private ArrayList getIpv4Prefixes(final List linkAddresses) {
- final ArrayList list = new ArrayList<>();
- for (LinkAddress address : linkAddresses) {
- if (!address.isIpv4()) continue;
-
- list.add(asIpPrefix(address));
- }
-
- return list;
- }
-
- private void handleMaybePrefixConflict(final List prefixes) {
- for (IpServer downstream : mDownstreams) {
- final IpPrefix target = getDownstreamPrefix(downstream);
-
- for (IpPrefix source : prefixes) {
- if (isConflictPrefix(source, target)) {
- downstream.sendMessage(IpServer.CMD_NOTIFY_PREFIX_CONFLICT);
- break;
- }
- }
- }
- }
-
- /** Remove IpPrefix records corresponding to input network. */
- public void removeUpstreamPrefix(final Network network) {
- mUpstreamPrefixMap.remove(network);
- }
-
- /**
- * Maybe remove deprecated upstream records, this would be called once tethering started without
- * any exiting tethered downstream.
- */
- public void maybeRemoveDeprecatedUpstreams() {
- if (mUpstreamPrefixMap.isEmpty()) return;
-
- // Remove all upstreams that are no longer valid networks
- final Set toBeRemoved = new HashSet<>(mUpstreamPrefixMap.keySet());
- toBeRemoved.removeAll(asList(mConnectivityMgr.getAllNetworks()));
-
- mUpstreamPrefixMap.removeAll(toBeRemoved);
- }
-
- /**
- * Pick a random available address and mark its prefix as in use for the provided IpServer,
- * returns null if there is no available address.
- */
- @Nullable
- public LinkAddress requestDownstreamAddress(final IpServer ipServer, boolean useLastAddress) {
- if (mConfig.shouldEnableWifiP2pDedicatedIp()
- && ipServer.interfaceType() == TETHERING_WIFI_P2P) {
- return new LinkAddress(LEGACY_WIFI_P2P_IFACE_ADDRESS);
- }
-
- final LinkAddress cachedAddress = mCachedAddresses.get(ipServer.interfaceType());
- if (useLastAddress && cachedAddress != null
- && !isConflictWithUpstream(asIpPrefix(cachedAddress))) {
- mDownstreams.add(ipServer);
- return cachedAddress;
- }
-
- for (IpPrefix prefixRange : mTetheringPrefixes) {
- final LinkAddress newAddress = chooseDownstreamAddress(prefixRange);
- if (newAddress != null) {
- mDownstreams.add(ipServer);
- mCachedAddresses.put(ipServer.interfaceType(), newAddress);
- return newAddress;
- }
- }
-
- // No available address.
- return null;
- }
-
- private int getPrefixBaseAddress(final IpPrefix prefix) {
- return inet4AddressToIntHTH((Inet4Address) prefix.getAddress());
- }
-
- /**
- * Check whether input prefix conflict with upstream prefixes or in-use downstream prefixes.
- * If yes, return one of them.
- */
- private IpPrefix getConflictPrefix(final IpPrefix prefix) {
- final IpPrefix upstream = getConflictWithUpstream(prefix);
- if (upstream != null) return upstream;
-
- return getInUseDownstreamPrefix(prefix);
- }
-
- // Get the next non-conflict sub prefix. E.g: To get next sub prefix from 10.0.0.0/8, if the
- // previously selected prefix is 10.20.42.0/24(subPrefix: 0.20.42.0) and the conflicting prefix
- // is 10.16.0.0/20 (10.16.0.0 ~ 10.16.15.255), then the max address under subPrefix is
- // 0.16.15.255 and the next subPrefix is 0.16.16.255/24 (0.16.15.255 + 0.0.1.0).
- // Note: the sub address 0.0.0.255 here is fine to be any value that it will be replaced as
- // selected random sub address later.
- private int getNextSubPrefix(final IpPrefix conflictPrefix, final int prefixRangeMask) {
- final int suffixMask = ~prefixLengthToV4NetmaskIntHTH(conflictPrefix.getPrefixLength());
- // The largest offset within the prefix assignment block that still conflicts with
- // conflictPrefix.
- final int maxConflict =
- (getPrefixBaseAddress(conflictPrefix) | suffixMask) & ~prefixRangeMask;
-
- final int prefixMask = prefixLengthToV4NetmaskIntHTH(PREFIX_LENGTH);
- // Pick a sub prefix a full prefix (1 << (32 - PREFIX_LENGTH) addresses) greater than
- // maxConflict. This ensures that the selected prefix never overlaps with conflictPrefix.
- // There is no need to mask the result with PREFIX_LENGTH bits because this is done by
- // findAvailablePrefixFromRange when it constructs the prefix.
- return maxConflict + (1 << (32 - PREFIX_LENGTH));
- }
-
- private LinkAddress chooseDownstreamAddress(final IpPrefix prefixRange) {
- // The netmask of the prefix assignment block (e.g., 0xfff00000 for 172.16.0.0/12).
- final int prefixRangeMask = prefixLengthToV4NetmaskIntHTH(prefixRange.getPrefixLength());
-
- // The zero address in the block (e.g., 0xac100000 for 172.16.0.0/12).
- final int baseAddress = getPrefixBaseAddress(prefixRange);
-
- // The subnet mask corresponding to PREFIX_LENGTH.
- final int prefixMask = prefixLengthToV4NetmaskIntHTH(PREFIX_LENGTH);
-
- // The offset within prefixRange of a randomly-selected prefix of length PREFIX_LENGTH.
- // This may not be the prefix of the address returned by this method:
- // - If it is already in use, the method will return an address in another prefix.
- // - If all prefixes within prefixRange are in use, the method will return null. For
- // example, for a /24 prefix within 172.26.0.0/12, this will be a multiple of 256 in
- // [0, 1048576). In other words, a random 32-bit number with mask 0x000fff00.
- //
- // prefixRangeMask is required to ensure no wrapping. For example, consider:
- // - prefixRange 127.0.0.0/8
- // - randomPrefixStart 127.255.255.0
- // - A conflicting prefix of 127.255.254.0/23
- // In this case without prefixRangeMask, getNextSubPrefix would return 128.0.0.0, which
- // means the "start < end" check in findAvailablePrefixFromRange would not reject the prefix
- // because Java doesn't have unsigned integers, so 128.0.0.0 = 0x80000000 = -2147483648
- // is less than 127.0.0.0 = 0x7f000000 = 2130706432.
- //
- // Additionally, it makes debug output easier to read by making the numbers smaller.
- final int randomPrefixStart = getRandomInt() & ~prefixRangeMask & prefixMask;
-
- // A random offset within the prefix. Used to determine the local address once the prefix
- // is selected. It does not result in an IPv4 address ending in .0, .1, or .255
- // For a PREFIX_LENGTH of 255, this is a number between 2 and 254.
- final int subAddress = getSanitizedSubAddr(~prefixMask);
-
- // Find a prefix length PREFIX_LENGTH between randomPrefixStart and the end of the block,
- // such that the prefix does not conflict with any upstream.
- IpPrefix downstreamPrefix = findAvailablePrefixFromRange(
- randomPrefixStart, (~prefixRangeMask) + 1, baseAddress, prefixRangeMask);
- if (downstreamPrefix != null) return getLinkAddress(downstreamPrefix, subAddress);
-
- // If that failed, do the same, but between 0 and randomPrefixStart.
- downstreamPrefix = findAvailablePrefixFromRange(
- 0, randomPrefixStart, baseAddress, prefixRangeMask);
-
- return getLinkAddress(downstreamPrefix, subAddress);
- }
-
- private LinkAddress getLinkAddress(final IpPrefix prefix, final int subAddress) {
- if (prefix == null) return null;
-
- final InetAddress address = intToInet4AddressHTH(getPrefixBaseAddress(prefix) | subAddress);
- return new LinkAddress(address, PREFIX_LENGTH);
- }
-
- private IpPrefix findAvailablePrefixFromRange(final int start, final int end,
- final int baseAddress, final int prefixRangeMask) {
- int newSubPrefix = start;
- while (newSubPrefix < end) {
- final InetAddress address = intToInet4AddressHTH(baseAddress | newSubPrefix);
- final IpPrefix prefix = new IpPrefix(address, PREFIX_LENGTH);
-
- final IpPrefix conflictPrefix = getConflictPrefix(prefix);
-
- if (conflictPrefix == null) return prefix;
-
- newSubPrefix = getNextSubPrefix(conflictPrefix, prefixRangeMask);
- }
-
- return null;
- }
-
- /** Get random int which could be used to generate random address. */
- @VisibleForTesting
- public int getRandomInt() {
- return (new Random()).nextInt();
- }
-
- /** Get random subAddress and avoid selecting x.x.x.0, x.x.x.1 and x.x.x.255 address. */
- private int getSanitizedSubAddr(final int subAddrMask) {
- final int randomSubAddr = getRandomInt() & subAddrMask;
- // If prefix length > 30, the selecting speace would be less than 4 which may be hard to
- // avoid 3 consecutive address.
- if (PREFIX_LENGTH > 30) return randomSubAddr;
-
- // TODO: maybe it is not necessary to avoid .0, .1 and .255 address because tethering
- // address would not be conflicted. This code only works because PREFIX_LENGTH is not longer
- // than 24
- final int candidate = randomSubAddr & 0xff;
- if (candidate == 0 || candidate == 1 || candidate == 255) {
- return (randomSubAddr & 0xfffffffc) + 2;
- }
-
- return randomSubAddr;
- }
-
- /** Release downstream record for IpServer. */
- public void releaseDownstream(final IpServer ipServer) {
- mDownstreams.remove(ipServer);
- }
-
- /** Clear current upstream prefixes records. */
- public void clearUpstreamPrefixes() {
- mUpstreamPrefixMap.clear();
- }
-
- private IpPrefix getConflictWithUpstream(final IpPrefix prefix) {
- for (int i = 0; i < mUpstreamPrefixMap.size(); i++) {
- final List list = mUpstreamPrefixMap.valueAt(i);
- for (IpPrefix upstream : list) {
- if (isConflictPrefix(prefix, upstream)) return upstream;
- }
- }
- return null;
- }
-
- private boolean isConflictWithUpstream(final IpPrefix prefix) {
- return getConflictWithUpstream(prefix) != null;
- }
-
- private boolean isConflictPrefix(final IpPrefix prefix1, final IpPrefix prefix2) {
- if (prefix2.getPrefixLength() < prefix1.getPrefixLength()) {
- return prefix2.contains(prefix1.getAddress());
- }
-
- return prefix1.contains(prefix2.getAddress());
- }
-
- // InUse Prefixes are prefixes of mCachedAddresses which are active downstream addresses, last
- // downstream addresses(reserved for next time) and static addresses(e.g. bluetooth, wifi p2p).
- private IpPrefix getInUseDownstreamPrefix(final IpPrefix prefix) {
- for (int i = 0; i < mCachedAddresses.size(); i++) {
- final IpPrefix downstream = asIpPrefix(mCachedAddresses.valueAt(i));
- if (isConflictPrefix(prefix, downstream)) return downstream;
- }
-
- // IpServer may use manually-defined address (mStaticIpv4ServerAddr) which does not include
- // in mCachedAddresses.
- for (IpServer downstream : mDownstreams) {
- final IpPrefix target = getDownstreamPrefix(downstream);
-
- if (isConflictPrefix(prefix, target)) return target;
- }
-
- return null;
- }
-
- @NonNull
- private IpPrefix getDownstreamPrefix(final IpServer downstream) {
- final LinkAddress address = downstream.getAddress();
-
- return asIpPrefix(address);
- }
-
- void dump(final IndentingPrintWriter pw) {
- pw.println("mTetheringPrefixes:");
- pw.increaseIndent();
- for (IpPrefix prefix : mTetheringPrefixes) {
- pw.println(prefix);
- }
- pw.decreaseIndent();
-
- pw.println("mUpstreamPrefixMap:");
- pw.increaseIndent();
- for (int i = 0; i < mUpstreamPrefixMap.size(); i++) {
- pw.println(mUpstreamPrefixMap.keyAt(i) + " - " + mUpstreamPrefixMap.valueAt(i));
- }
- pw.decreaseIndent();
-
- pw.println("mDownstreams:");
- pw.increaseIndent();
- for (IpServer ipServer : mDownstreams) {
- pw.println(ipServer.interfaceType() + " - " + ipServer.getAddress());
- }
- pw.decreaseIndent();
-
- pw.println("mCachedAddresses:");
- pw.increaseIndent();
- for (int i = 0; i < mCachedAddresses.size(); i++) {
- pw.println(mCachedAddresses.keyAt(i) + " - " + mCachedAddresses.valueAt(i));
- }
- pw.decreaseIndent();
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
deleted file mode 100644
index 5a0c5b0cff5f5..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java
+++ /dev/null
@@ -1,2427 +0,0 @@
-/*
- * Copyright (C) 2010 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 static android.Manifest.permission.NETWORK_SETTINGS;
-import static android.Manifest.permission.NETWORK_STACK;
-import static android.content.pm.PackageManager.GET_ACTIVITIES;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.hardware.usb.UsbManager.USB_CONFIGURED;
-import static android.hardware.usb.UsbManager.USB_CONNECTED;
-import static android.hardware.usb.UsbManager.USB_FUNCTION_NCM;
-import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
-import static android.net.ConnectivityManager.ACTION_RESTRICT_BACKGROUND_CHANGED;
-import static android.net.ConnectivityManager.CONNECTIVITY_ACTION;
-import static android.net.ConnectivityManager.EXTRA_NETWORK_INFO;
-import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
-import static android.net.TetheringManager.ACTION_TETHER_STATE_CHANGED;
-import static android.net.TetheringManager.EXTRA_ACTIVE_LOCAL_ONLY;
-import static android.net.TetheringManager.EXTRA_ACTIVE_TETHER;
-import static android.net.TetheringManager.EXTRA_AVAILABLE_TETHER;
-import static android.net.TetheringManager.EXTRA_ERRORED_TETHER;
-import static android.net.TetheringManager.TETHERING_BLUETOOTH;
-import static android.net.TetheringManager.TETHERING_ETHERNET;
-import static android.net.TetheringManager.TETHERING_INVALID;
-import static android.net.TetheringManager.TETHERING_NCM;
-import static android.net.TetheringManager.TETHERING_USB;
-import static android.net.TetheringManager.TETHERING_WIFI;
-import static android.net.TetheringManager.TETHERING_WIFI_P2P;
-import static android.net.TetheringManager.TETHERING_WIGIG;
-import static android.net.TetheringManager.TETHER_ERROR_INTERNAL_ERROR;
-import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
-import static android.net.TetheringManager.TETHER_ERROR_SERVICE_UNAVAIL;
-import static android.net.TetheringManager.TETHER_ERROR_UNAVAIL_IFACE;
-import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_IFACE;
-import static android.net.TetheringManager.TETHER_ERROR_UNKNOWN_TYPE;
-import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED;
-import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED;
-import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED;
-import static android.net.util.TetheringMessageBase.BASE_MAIN_SM;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE;
-import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE;
-import static android.net.wifi.WifiManager.IFACE_IP_MODE_CONFIGURATION_ERROR;
-import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
-import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
-import static android.net.wifi.WifiManager.IFACE_IP_MODE_UNSPECIFIED;
-import static android.net.wifi.WifiManager.WIFI_AP_STATE_DISABLED;
-import static android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED;
-import static android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
-import static com.android.networkstack.tethering.TetheringNotificationUpdater.DOWNSTREAM_NONE;
-
-import android.app.usage.NetworkStatsManager;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothPan;
-import android.bluetooth.BluetoothProfile;
-import android.bluetooth.BluetoothProfile.ServiceListener;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.hardware.usb.UsbManager;
-import android.net.ConnectivityManager;
-import android.net.EthernetManager;
-import android.net.IIntResultListener;
-import android.net.INetd;
-import android.net.ITetheringEventCallback;
-import android.net.IpPrefix;
-import android.net.LinkAddress;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkInfo;
-import android.net.TetherStatesParcel;
-import android.net.TetheredClient;
-import android.net.TetheringCallbackStartedParcel;
-import android.net.TetheringConfigurationParcel;
-import android.net.TetheringRequestParcel;
-import android.net.ip.IpServer;
-import android.net.shared.NetdUtils;
-import android.net.util.BaseNetdUnsolicitedEventListener;
-import android.net.util.InterfaceSet;
-import android.net.util.PrefixUtils;
-import android.net.util.SharedLog;
-import android.net.util.TetheringUtils;
-import android.net.util.VersionedBroadcastListener;
-import android.net.wifi.WifiClient;
-import android.net.wifi.WifiManager;
-import android.net.wifi.p2p.WifiP2pGroup;
-import android.net.wifi.p2p.WifiP2pInfo;
-import android.net.wifi.p2p.WifiP2pManager;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.RemoteCallbackList;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.os.ServiceSpecificException;
-import android.os.UserHandle;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.telephony.PhoneStateListener;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-import android.util.ArrayMap;
-import android.util.Log;
-import android.util.SparseArray;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.IndentingPrintWriter;
-import com.android.internal.util.MessageUtils;
-import com.android.internal.util.State;
-import com.android.internal.util.StateMachine;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.net.InetAddress;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashSet;
-import java.util.List;
-import java.util.Set;
-import java.util.concurrent.Executor;
-import java.util.concurrent.RejectedExecutionException;
-
-/**
- *
- * This class holds much of the business logic to allow Android devices
- * to act as IP gateways via USB, BT, and WiFi interfaces.
- */
-public class Tethering {
-
- private static final String TAG = Tethering.class.getSimpleName();
- private static final boolean DBG = false;
- private static final boolean VDBG = false;
-
- private static final Class[] sMessageClasses = {
- Tethering.class, TetherMainSM.class, IpServer.class
- };
- private static final SparseArray sMagicDecoderRing =
- MessageUtils.findMessageNames(sMessageClasses);
- // Keep in sync with NETID_UNSET in system/netd/include/netid_client.h
- private static final int NETID_UNSET = 0;
-
- private static class TetherState {
- public final IpServer ipServer;
- public int lastState;
- public int lastError;
-
- TetherState(IpServer ipServer) {
- this.ipServer = ipServer;
- // Assume all state machines start out available and with no errors.
- lastState = IpServer.STATE_AVAILABLE;
- lastError = TETHER_ERROR_NO_ERROR;
- }
-
- public boolean isCurrentlyServing() {
- switch (lastState) {
- case IpServer.STATE_TETHERED:
- case IpServer.STATE_LOCAL_ONLY:
- return true;
- default:
- return false;
- }
- }
- }
-
- /**
- * Cookie added when registering {@link android.net.TetheringManager.TetheringEventCallback}.
- */
- private static class CallbackCookie {
- public final boolean hasListClientsPermission;
-
- private CallbackCookie(boolean hasListClientsPermission) {
- this.hasListClientsPermission = hasListClientsPermission;
- }
- }
-
- private final SharedLog mLog = new SharedLog(TAG);
- private final RemoteCallbackList mTetheringEventCallbacks =
- new RemoteCallbackList<>();
- // Currently active tethering requests per tethering type. Only one of each type can be
- // requested at a time. After a tethering type is requested, the map keeps tethering parameters
- // to be used after the interface comes up asynchronously.
- private final SparseArray mActiveTetheringRequests =
- new SparseArray<>();
-
- // used to synchronize public access to members
- // TODO(b/153621704): remove mPublicSync to make Tethering lock free
- private final Object mPublicSync;
- private final Context mContext;
- private final ArrayMap mTetherStates;
- private final BroadcastReceiver mStateReceiver;
- private final Looper mLooper;
- private final StateMachine mTetherMainSM;
- private final OffloadController mOffloadController;
- private final UpstreamNetworkMonitor mUpstreamNetworkMonitor;
- // TODO: Figure out how to merge this and other downstream-tracking objects
- // into a single coherent structure.
- // Use LinkedHashSet for predictable ordering order for ConnectedClientsTracker.
- private final LinkedHashSet mForwardedDownstreams;
- private final VersionedBroadcastListener mCarrierConfigChange;
- private final TetheringDependencies mDeps;
- private final EntitlementManager mEntitlementMgr;
- private final Handler mHandler;
- private final INetd mNetd;
- private final NetdCallback mNetdCallback;
- private final UserRestrictionActionListener mTetheringRestriction;
- private final ActiveDataSubIdListener mActiveDataSubIdListener;
- private final ConnectedClientsTracker mConnectedClientsTracker;
- private final TetheringThreadExecutor mExecutor;
- private final TetheringNotificationUpdater mNotificationUpdater;
- private final UserManager mUserManager;
- private final BpfCoordinator mBpfCoordinator;
- private final PrivateAddressCoordinator mPrivateAddressCoordinator;
- private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID;
- // All the usage of mTetheringEventCallback should run in the same thread.
- private ITetheringEventCallback mTetheringEventCallback = null;
-
- private volatile TetheringConfiguration mConfig;
- private InterfaceSet mCurrentUpstreamIfaceSet;
-
- private boolean mRndisEnabled; // track the RNDIS function enabled state
- // True iff. WiFi tethering should be started when soft AP is ready.
- private boolean mWifiTetherRequested;
- private Network mTetherUpstream;
- private TetherStatesParcel mTetherStatesParcel;
- private boolean mDataSaverEnabled = false;
- private String mWifiP2pTetherInterface = null;
- private int mOffloadStatus = TETHER_HARDWARE_OFFLOAD_STOPPED;
-
- @GuardedBy("mPublicSync")
- private EthernetManager.TetheredInterfaceRequest mEthernetIfaceRequest;
- @GuardedBy("mPublicSync")
- private String mConfiguredEthernetIface;
- @GuardedBy("mPublicSync")
- private EthernetCallback mEthernetCallback;
-
- public Tethering(TetheringDependencies deps) {
- mLog.mark("Tethering.constructed");
- mDeps = deps;
- mContext = mDeps.getContext();
- mNetd = mDeps.getINetd(mContext);
- mLooper = mDeps.getTetheringLooper();
- mNotificationUpdater = mDeps.getNotificationUpdater(mContext, mLooper);
-
- mPublicSync = new Object();
-
- mTetherStates = new ArrayMap<>();
- mConnectedClientsTracker = new ConnectedClientsTracker();
-
- mTetherMainSM = new TetherMainSM("TetherMain", mLooper, deps);
- mTetherMainSM.start();
-
- mHandler = mTetherMainSM.getHandler();
- mOffloadController = mDeps.getOffloadController(mHandler, mLog,
- new OffloadController.Dependencies() {
-
- @Override
- public TetheringConfiguration getTetherConfig() {
- return mConfig;
- }
- });
- mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMainSM, mLog,
- TetherMainSM.EVENT_UPSTREAM_CALLBACK);
- mForwardedDownstreams = new LinkedHashSet<>();
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
- // EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream
- // permission is changed according to entitlement check result.
- mEntitlementMgr = mDeps.getEntitlementManager(mContext, mHandler, mLog,
- () -> mTetherMainSM.sendMessage(
- TetherMainSM.EVENT_UPSTREAM_PERMISSION_CHANGED));
- mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
- mLog.log("OBSERVED UiEnitlementFailed");
- stopTethering(downstream);
- });
- mEntitlementMgr.setTetheringConfigurationFetcher(() -> {
- return mConfig;
- });
-
- mCarrierConfigChange = new VersionedBroadcastListener(
- "CarrierConfigChangeListener", mContext, mHandler, filter,
- (Intent ignored) -> {
- mLog.log("OBSERVED carrier config change");
- updateConfiguration();
- mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
- });
-
- mStateReceiver = new StateReceiver();
-
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- mTetheringRestriction = new UserRestrictionActionListener(
- mUserManager, this, mNotificationUpdater);
- mExecutor = new TetheringThreadExecutor(mHandler);
- mActiveDataSubIdListener = new ActiveDataSubIdListener(mExecutor);
- mNetdCallback = new NetdCallback();
-
- // Load tethering configuration.
- updateConfiguration();
- // It is OK for the configuration to be passed to the PrivateAddressCoordinator at
- // construction time because the only part of the configuration it uses is
- // shouldEnableWifiP2pDedicatedIp(), and currently do not support changing that.
- mPrivateAddressCoordinator = mDeps.getPrivateAddressCoordinator(mContext, mConfig);
-
- // Must be initialized after tethering configuration is loaded because BpfCoordinator
- // constructor needs to use the configuration.
- mBpfCoordinator = mDeps.getBpfCoordinator(
- new BpfCoordinator.Dependencies() {
- @NonNull
- public Handler getHandler() {
- return mHandler;
- }
-
- @NonNull
- public INetd getNetd() {
- return mNetd;
- }
-
- @NonNull
- public NetworkStatsManager getNetworkStatsManager() {
- return mContext.getSystemService(NetworkStatsManager.class);
- }
-
- @NonNull
- public SharedLog getSharedLog() {
- return mLog;
- }
-
- @Nullable
- public TetheringConfiguration getTetherConfig() {
- return mConfig;
- }
- });
-
- startStateMachineUpdaters();
- }
-
- /**
- * Start to register callbacks.
- * Call this function when tethering is ready to handle callback events.
- */
- private void startStateMachineUpdaters() {
- try {
- mNetd.registerUnsolicitedEventListener(mNetdCallback);
- } catch (RemoteException e) {
- mLog.e("Unable to register netd UnsolicitedEventListener");
- }
- mCarrierConfigChange.startListening();
- mContext.getSystemService(TelephonyManager.class).listen(mActiveDataSubIdListener,
- PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(UsbManager.ACTION_USB_STATE);
- filter.addAction(CONNECTIVITY_ACTION);
- filter.addAction(WifiManager.WIFI_AP_STATE_CHANGED_ACTION);
- filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
- filter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
- filter.addAction(UserManager.ACTION_USER_RESTRICTIONS_CHANGED);
- filter.addAction(ACTION_RESTRICT_BACKGROUND_CHANGED);
- mContext.registerReceiver(mStateReceiver, filter, null, mHandler);
-
- final IntentFilter noUpstreamFilter = new IntentFilter();
- noUpstreamFilter.addAction(TetheringNotificationUpdater.ACTION_DISABLE_TETHERING);
- mContext.registerReceiver(
- mStateReceiver, noUpstreamFilter, PERMISSION_MAINLINE_NETWORK_STACK, mHandler);
-
- final WifiManager wifiManager = getWifiManager();
- if (wifiManager != null) {
- wifiManager.registerSoftApCallback(mExecutor, new TetheringSoftApCallback());
- }
-
- startTrackDefaultNetwork();
- }
-
- private class TetheringThreadExecutor implements Executor {
- private final Handler mTetherHandler;
- TetheringThreadExecutor(Handler handler) {
- mTetherHandler = handler;
- }
- @Override
- public void execute(Runnable command) {
- if (!mTetherHandler.post(command)) {
- throw new RejectedExecutionException(mTetherHandler + " is shutting down");
- }
- }
- }
-
- private class ActiveDataSubIdListener extends PhoneStateListener {
- ActiveDataSubIdListener(Executor executor) {
- super(executor);
- }
-
- @Override
- public void onActiveDataSubscriptionIdChanged(int subId) {
- mLog.log("OBSERVED active data subscription change, from " + mActiveDataSubId
- + " to " + subId);
- if (subId == mActiveDataSubId) return;
-
- mActiveDataSubId = subId;
- updateConfiguration();
- mNotificationUpdater.onActiveDataSubscriptionIdChanged(subId);
- // To avoid launching unexpected provisioning checks, ignore re-provisioning
- // when no CarrierConfig loaded yet. Assume reevaluateSimCardProvisioning()
- // will be triggered again when CarrierConfig is loaded.
- if (mEntitlementMgr.getCarrierConfig(mConfig) != null) {
- mEntitlementMgr.reevaluateSimCardProvisioning(mConfig);
- } else {
- mLog.log("IGNORED reevaluate provisioning, no carrier config loaded");
- }
- }
- }
-
- private WifiManager getWifiManager() {
- return (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
- }
-
- // NOTE: This is always invoked on the mLooper thread.
- private void updateConfiguration() {
- mConfig = mDeps.generateTetheringConfiguration(mContext, mLog, mActiveDataSubId);
- mUpstreamNetworkMonitor.updateMobileRequiresDun(mConfig.isDunRequired);
- reportConfigurationChanged(mConfig.toStableParcelable());
- }
-
- private void maybeDunSettingChanged() {
- final boolean isDunRequired = TetheringConfiguration.checkDunRequired(mContext);
- if (isDunRequired == mConfig.isDunRequired) return;
- updateConfiguration();
- }
-
- private class NetdCallback extends BaseNetdUnsolicitedEventListener {
- @Override
- public void onInterfaceChanged(String ifName, boolean up) {
- mHandler.post(() -> interfaceStatusChanged(ifName, up));
- }
-
- @Override
- public void onInterfaceLinkStateChanged(String ifName, boolean up) {
- mHandler.post(() -> interfaceLinkStateChanged(ifName, up));
- }
-
- @Override
- public void onInterfaceAdded(String ifName) {
- mHandler.post(() -> interfaceAdded(ifName));
- }
-
- @Override
- public void onInterfaceRemoved(String ifName) {
- mHandler.post(() -> interfaceRemoved(ifName));
- }
- }
-
- private class TetheringSoftApCallback implements WifiManager.SoftApCallback {
- // TODO: Remove onStateChanged override when this method has default on
- // WifiManager#SoftApCallback interface.
- // Wifi listener for state change of the soft AP
- @Override
- public void onStateChanged(final int state, final int failureReason) {
- // Nothing
- }
-
- // Called by wifi when the number of soft AP clients changed.
- @Override
- public void onConnectedClientsChanged(final List clients) {
- updateConnectedClients(clients);
- }
- }
-
- void interfaceStatusChanged(String iface, boolean up) {
- // Never called directly: only called from interfaceLinkStateChanged.
- // See NetlinkHandler.cpp: notifyInterfaceChanged.
- if (VDBG) Log.d(TAG, "interfaceStatusChanged " + iface + ", " + up);
- synchronized (mPublicSync) {
- if (up) {
- maybeTrackNewInterfaceLocked(iface);
- } else {
- if (ifaceNameToType(iface) == TETHERING_BLUETOOTH
- || ifaceNameToType(iface) == TETHERING_WIGIG) {
- stopTrackingInterfaceLocked(iface);
- } else {
- // Ignore usb0 down after enabling RNDIS.
- // We will handle disconnect in interfaceRemoved.
- // Similarly, ignore interface down for WiFi. We monitor WiFi AP status
- // through the WifiManager.WIFI_AP_STATE_CHANGED_ACTION intent.
- if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
- }
- }
- }
- }
-
- void interfaceLinkStateChanged(String iface, boolean up) {
- interfaceStatusChanged(iface, up);
- }
-
- private int ifaceNameToType(String iface) {
- final TetheringConfiguration cfg = mConfig;
-
- if (cfg.isWifi(iface)) {
- return TETHERING_WIFI;
- } else if (cfg.isWigig(iface)) {
- return TETHERING_WIGIG;
- } else if (cfg.isWifiP2p(iface)) {
- return TETHERING_WIFI_P2P;
- } else if (cfg.isUsb(iface)) {
- return TETHERING_USB;
- } else if (cfg.isBluetooth(iface)) {
- return TETHERING_BLUETOOTH;
- } else if (cfg.isNcm(iface)) {
- return TETHERING_NCM;
- }
- return TETHERING_INVALID;
- }
-
- void interfaceAdded(String iface) {
- if (VDBG) Log.d(TAG, "interfaceAdded " + iface);
- synchronized (mPublicSync) {
- maybeTrackNewInterfaceLocked(iface);
- }
- }
-
- void interfaceRemoved(String iface) {
- if (VDBG) Log.d(TAG, "interfaceRemoved " + iface);
- synchronized (mPublicSync) {
- stopTrackingInterfaceLocked(iface);
- }
- }
-
- void startTethering(final TetheringRequestParcel request, final IIntResultListener listener) {
- mHandler.post(() -> {
- final TetheringRequestParcel unfinishedRequest = mActiveTetheringRequests.get(
- request.tetheringType);
- // If tethering is already enabled with a different request,
- // disable before re-enabling.
- if (unfinishedRequest != null
- && !TetheringUtils.isTetheringRequestEquals(unfinishedRequest, request)) {
- enableTetheringInternal(request.tetheringType, false /* disabled */, null);
- mEntitlementMgr.stopProvisioningIfNeeded(request.tetheringType);
- }
- mActiveTetheringRequests.put(request.tetheringType, request);
-
- if (request.exemptFromEntitlementCheck) {
- mEntitlementMgr.setExemptedDownstreamType(request.tetheringType);
- } else {
- mEntitlementMgr.startProvisioningIfNeeded(request.tetheringType,
- request.showProvisioningUi);
- }
- enableTetheringInternal(request.tetheringType, true /* enabled */, listener);
- });
- }
-
- void stopTethering(int type) {
- mHandler.post(() -> {
- mActiveTetheringRequests.remove(type);
-
- enableTetheringInternal(type, false /* disabled */, null);
- mEntitlementMgr.stopProvisioningIfNeeded(type);
- });
- }
-
- /**
- * Enables or disables tethering for the given type. If provisioning is required, it will
- * schedule provisioning rechecks for the specified interface.
- */
- private void enableTetheringInternal(int type, boolean enable,
- final IIntResultListener listener) {
- int result = TETHER_ERROR_NO_ERROR;
- switch (type) {
- case TETHERING_WIFI:
- result = setWifiTethering(enable);
- break;
- case TETHERING_USB:
- result = setUsbTethering(enable);
- break;
- case TETHERING_BLUETOOTH:
- setBluetoothTethering(enable, listener);
- break;
- case TETHERING_NCM:
- result = setNcmTethering(enable);
- break;
- case TETHERING_ETHERNET:
- result = setEthernetTethering(enable);
- break;
- default:
- Log.w(TAG, "Invalid tether type.");
- result = TETHER_ERROR_UNKNOWN_TYPE;
- }
-
- // The result of Bluetooth tethering will be sent by #setBluetoothTethering.
- if (type != TETHERING_BLUETOOTH) {
- sendTetherResult(listener, result, type);
- }
- }
-
- private void sendTetherResult(final IIntResultListener listener, final int result,
- final int type) {
- if (listener != null) {
- try {
- listener.onResult(result);
- } catch (RemoteException e) { }
- }
-
- // If changing tethering fail, remove corresponding request
- // no matter who trigger the start/stop.
- if (result != TETHER_ERROR_NO_ERROR) mActiveTetheringRequests.remove(type);
- }
-
- private int setWifiTethering(final boolean enable) {
- final long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mPublicSync) {
- final WifiManager mgr = getWifiManager();
- if (mgr == null) {
- mLog.e("setWifiTethering: failed to get WifiManager!");
- return TETHER_ERROR_SERVICE_UNAVAIL;
- }
- if ((enable && mgr.startTetheredHotspot(null /* use existing softap config */))
- || (!enable && mgr.stopSoftAp())) {
- mWifiTetherRequested = enable;
- return TETHER_ERROR_NO_ERROR;
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
-
- return TETHER_ERROR_INTERNAL_ERROR;
- }
-
- private void setBluetoothTethering(final boolean enable, final IIntResultListener listener) {
- final BluetoothAdapter adapter = mDeps.getBluetoothAdapter();
- if (adapter == null || !adapter.isEnabled()) {
- Log.w(TAG, "Tried to enable bluetooth tethering with null or disabled adapter. null: "
- + (adapter == null));
- sendTetherResult(listener, TETHER_ERROR_SERVICE_UNAVAIL, TETHERING_BLUETOOTH);
- return;
- }
-
- adapter.getProfileProxy(mContext, new ServiceListener() {
- @Override
- public void onServiceDisconnected(int profile) { }
-
- @Override
- public void onServiceConnected(int profile, BluetoothProfile proxy) {
- // Clear identify is fine because caller already pass tethering permission at
- // ConnectivityService#startTethering()(or stopTethering) before the control comes
- // here. Bluetooth will check tethering permission again that there is
- // Context#getOpPackageName() under BluetoothPan#setBluetoothTethering() to get
- // caller's package name for permission check.
- // Calling BluetoothPan#setBluetoothTethering() here means the package name always
- // be system server. If calling identity is not cleared, that package's uid might
- // not match calling uid and end up in permission denied.
- final long identityToken = Binder.clearCallingIdentity();
- try {
- ((BluetoothPan) proxy).setBluetoothTethering(enable);
- } finally {
- Binder.restoreCallingIdentity(identityToken);
- }
- // TODO: Enabling bluetooth tethering can fail asynchronously here.
- // We should figure out a way to bubble up that failure instead of sending success.
- final int result = (((BluetoothPan) proxy).isTetheringOn() == enable)
- ? TETHER_ERROR_NO_ERROR
- : TETHER_ERROR_INTERNAL_ERROR;
- sendTetherResult(listener, result, TETHERING_BLUETOOTH);
- adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
- }
- }, BluetoothProfile.PAN);
- }
-
- private int setEthernetTethering(final boolean enable) {
- final EthernetManager em = (EthernetManager) mContext.getSystemService(
- Context.ETHERNET_SERVICE);
- synchronized (mPublicSync) {
- if (enable) {
- if (mEthernetCallback != null) {
- Log.d(TAG, "Ethernet tethering already started");
- return TETHER_ERROR_NO_ERROR;
- }
-
- mEthernetCallback = new EthernetCallback();
- mEthernetIfaceRequest = em.requestTetheredInterface(mExecutor, mEthernetCallback);
- } else {
- stopEthernetTetheringLocked();
- }
- }
- return TETHER_ERROR_NO_ERROR;
- }
-
- private void stopEthernetTetheringLocked() {
- if (mConfiguredEthernetIface != null) {
- stopTrackingInterfaceLocked(mConfiguredEthernetIface);
- mConfiguredEthernetIface = null;
- }
- if (mEthernetCallback != null) {
- mEthernetIfaceRequest.release();
- mEthernetCallback = null;
- mEthernetIfaceRequest = null;
- }
- }
-
- private class EthernetCallback implements EthernetManager.TetheredInterfaceCallback {
- @Override
- public void onAvailable(String iface) {
- synchronized (mPublicSync) {
- if (this != mEthernetCallback) {
- // Ethernet callback arrived after Ethernet tethering stopped. Ignore.
- return;
- }
- maybeTrackNewInterfaceLocked(iface, TETHERING_ETHERNET);
- changeInterfaceState(iface, IpServer.STATE_TETHERED);
- mConfiguredEthernetIface = iface;
- }
- }
-
- @Override
- public void onUnavailable() {
- synchronized (mPublicSync) {
- if (this != mEthernetCallback) {
- // onAvailable called after stopping Ethernet tethering.
- return;
- }
- stopEthernetTetheringLocked();
- }
- }
- }
-
- int tether(String iface) {
- return tether(iface, IpServer.STATE_TETHERED);
- }
-
- private int tether(String iface, int requestedState) {
- if (DBG) Log.d(TAG, "Tethering " + iface);
- synchronized (mPublicSync) {
- TetherState tetherState = mTetherStates.get(iface);
- if (tetherState == null) {
- Log.e(TAG, "Tried to Tether an unknown iface: " + iface + ", ignoring");
- return TETHER_ERROR_UNKNOWN_IFACE;
- }
- // Ignore the error status of the interface. If the interface is available,
- // the errors are referring to past tethering attempts anyway.
- if (tetherState.lastState != IpServer.STATE_AVAILABLE) {
- Log.e(TAG, "Tried to Tether an unavailable iface: " + iface + ", ignoring");
- return TETHER_ERROR_UNAVAIL_IFACE;
- }
- // NOTE: If a CMD_TETHER_REQUESTED message is already in the TISM's queue but not yet
- // processed, this will be a no-op and it will not return an error.
- //
- // This code cannot race with untether() because they both synchronize on mPublicSync.
- // TODO: reexamine the threading and messaging model to totally remove mPublicSync.
- final int type = tetherState.ipServer.interfaceType();
- final TetheringRequestParcel request = mActiveTetheringRequests.get(type, null);
- if (request != null) {
- mActiveTetheringRequests.delete(type);
- }
- tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_REQUESTED, requestedState, 0,
- request);
- return TETHER_ERROR_NO_ERROR;
- }
- }
-
- int untether(String iface) {
- if (DBG) Log.d(TAG, "Untethering " + iface);
- synchronized (mPublicSync) {
- TetherState tetherState = mTetherStates.get(iface);
- if (tetherState == null) {
- Log.e(TAG, "Tried to Untether an unknown iface :" + iface + ", ignoring");
- return TETHER_ERROR_UNKNOWN_IFACE;
- }
- if (!tetherState.isCurrentlyServing()) {
- Log.e(TAG, "Tried to untether an inactive iface :" + iface + ", ignoring");
- return TETHER_ERROR_UNAVAIL_IFACE;
- }
- tetherState.ipServer.sendMessage(IpServer.CMD_TETHER_UNREQUESTED);
- return TETHER_ERROR_NO_ERROR;
- }
- }
-
- void untetherAll() {
- stopTethering(TETHERING_WIFI);
- stopTethering(TETHERING_WIFI_P2P);
- stopTethering(TETHERING_USB);
- stopTethering(TETHERING_BLUETOOTH);
- stopTethering(TETHERING_ETHERNET);
- }
-
- int getLastTetherError(String iface) {
- synchronized (mPublicSync) {
- TetherState tetherState = mTetherStates.get(iface);
- if (tetherState == null) {
- Log.e(TAG, "Tried to getLastTetherError on an unknown iface :" + iface
- + ", ignoring");
- return TETHER_ERROR_UNKNOWN_IFACE;
- }
- return tetherState.lastError;
- }
- }
-
- private boolean isProvisioningNeededButUnavailable() {
- return isTetherProvisioningRequired() && !doesEntitlementPackageExist();
- }
-
- boolean isTetherProvisioningRequired() {
- final TetheringConfiguration cfg = mConfig;
- return mEntitlementMgr.isTetherProvisioningRequired(cfg);
- }
-
- private boolean doesEntitlementPackageExist() {
- // provisioningApp must contain package and class name.
- if (mConfig.provisioningApp.length != 2) {
- return false;
- }
-
- final PackageManager pm = mContext.getPackageManager();
- try {
- pm.getPackageInfo(mConfig.provisioningApp[0], GET_ACTIVITIES);
- } catch (PackageManager.NameNotFoundException e) {
- return false;
- }
- return true;
- }
-
- // TODO: Figure out how to update for local hotspot mode interfaces.
- private void sendTetherStateChangedBroadcast() {
- if (!isTetheringSupported()) return;
-
- final ArrayList availableList = new ArrayList<>();
- final ArrayList tetherList = new ArrayList<>();
- final ArrayList localOnlyList = new ArrayList<>();
- final ArrayList erroredList = new ArrayList<>();
- final ArrayList lastErrorList = new ArrayList<>();
-
- final TetheringConfiguration cfg = mConfig;
- mTetherStatesParcel = new TetherStatesParcel();
-
- int downstreamTypesMask = DOWNSTREAM_NONE;
- synchronized (mPublicSync) {
- for (int i = 0; i < mTetherStates.size(); i++) {
- TetherState tetherState = mTetherStates.valueAt(i);
- String iface = mTetherStates.keyAt(i);
- if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
- erroredList.add(iface);
- lastErrorList.add(tetherState.lastError);
- } else if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
- availableList.add(iface);
- } else if (tetherState.lastState == IpServer.STATE_LOCAL_ONLY) {
- localOnlyList.add(iface);
- } else if (tetherState.lastState == IpServer.STATE_TETHERED) {
- if (cfg.isUsb(iface)) {
- downstreamTypesMask |= (1 << TETHERING_USB);
- } else if (cfg.isWifi(iface)) {
- downstreamTypesMask |= (1 << TETHERING_WIFI);
- } else if (cfg.isBluetooth(iface)) {
- downstreamTypesMask |= (1 << TETHERING_BLUETOOTH);
- }
- tetherList.add(iface);
- }
- }
- }
-
- mTetherStatesParcel.availableList = availableList.toArray(new String[0]);
- mTetherStatesParcel.tetheredList = tetherList.toArray(new String[0]);
- mTetherStatesParcel.localOnlyList = localOnlyList.toArray(new String[0]);
- mTetherStatesParcel.erroredIfaceList = erroredList.toArray(new String[0]);
- mTetherStatesParcel.lastErrorList = new int[lastErrorList.size()];
- Iterator iterator = lastErrorList.iterator();
- for (int i = 0; i < lastErrorList.size(); i++) {
- mTetherStatesParcel.lastErrorList[i] = iterator.next().intValue();
- }
- reportTetherStateChanged(mTetherStatesParcel);
-
- final Intent bcast = new Intent(ACTION_TETHER_STATE_CHANGED);
- bcast.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- bcast.putStringArrayListExtra(EXTRA_AVAILABLE_TETHER, availableList);
- bcast.putStringArrayListExtra(EXTRA_ACTIVE_LOCAL_ONLY, localOnlyList);
- bcast.putStringArrayListExtra(EXTRA_ACTIVE_TETHER, tetherList);
- bcast.putStringArrayListExtra(EXTRA_ERRORED_TETHER, erroredList);
- mContext.sendStickyBroadcastAsUser(bcast, UserHandle.ALL);
- if (DBG) {
- Log.d(TAG, String.format(
- "sendTetherStateChangedBroadcast %s=[%s] %s=[%s] %s=[%s] %s=[%s]",
- "avail", TextUtils.join(",", availableList),
- "local_only", TextUtils.join(",", localOnlyList),
- "tether", TextUtils.join(",", tetherList),
- "error", TextUtils.join(",", erroredList)));
- }
-
- mNotificationUpdater.onDownstreamChanged(downstreamTypesMask);
- }
-
- private class StateReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context content, Intent intent) {
- final String action = intent.getAction();
- if (action == null) return;
-
- if (action.equals(UsbManager.ACTION_USB_STATE)) {
- handleUsbAction(intent);
- } else if (action.equals(CONNECTIVITY_ACTION)) {
- handleConnectivityAction(intent);
- } else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
- handleWifiApAction(intent);
- } else if (action.equals(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)) {
- handleWifiP2pAction(intent);
- } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
- mLog.log("OBSERVED configuration changed");
- updateConfiguration();
- } else if (action.equals(UserManager.ACTION_USER_RESTRICTIONS_CHANGED)) {
- mLog.log("OBSERVED user restrictions changed");
- handleUserRestrictionAction();
- } else if (action.equals(ACTION_RESTRICT_BACKGROUND_CHANGED)) {
- mLog.log("OBSERVED data saver changed");
- handleDataSaverChanged();
- } else if (action.equals(TetheringNotificationUpdater.ACTION_DISABLE_TETHERING)) {
- untetherAll();
- }
- }
-
- private void handleConnectivityAction(Intent intent) {
- final NetworkInfo networkInfo =
- (NetworkInfo) intent.getParcelableExtra(EXTRA_NETWORK_INFO);
- if (networkInfo == null
- || networkInfo.getDetailedState() == NetworkInfo.DetailedState.FAILED) {
- return;
- }
-
- if (VDBG) Log.d(TAG, "Tethering got CONNECTIVITY_ACTION: " + networkInfo.toString());
- mTetherMainSM.sendMessage(TetherMainSM.CMD_UPSTREAM_CHANGED);
- }
-
- private void handleUsbAction(Intent intent) {
- final boolean usbConnected = intent.getBooleanExtra(USB_CONNECTED, false);
- final boolean usbConfigured = intent.getBooleanExtra(USB_CONFIGURED, false);
- final boolean rndisEnabled = intent.getBooleanExtra(USB_FUNCTION_RNDIS, false);
- final boolean ncmEnabled = intent.getBooleanExtra(USB_FUNCTION_NCM, false);
-
- mLog.log(String.format("USB bcast connected:%s configured:%s rndis:%s",
- usbConnected, usbConfigured, rndisEnabled));
-
- // There are three types of ACTION_USB_STATE:
- //
- // - DISCONNECTED (USB_CONNECTED and USB_CONFIGURED are 0)
- // Meaning: USB connection has ended either because of
- // software reset or hard unplug.
- //
- // - CONNECTED (USB_CONNECTED is 1, USB_CONFIGURED is 0)
- // Meaning: the first stage of USB protocol handshake has
- // occurred but it is not complete.
- //
- // - CONFIGURED (USB_CONNECTED and USB_CONFIGURED are 1)
- // Meaning: the USB handshake is completely done and all the
- // functions are ready to use.
- //
- // For more explanation, see b/62552150 .
- synchronized (Tethering.this.mPublicSync) {
- if (!usbConnected && mRndisEnabled) {
- // Turn off tethering if it was enabled and there is a disconnect.
- tetherMatchingInterfaces(IpServer.STATE_AVAILABLE, TETHERING_USB);
- mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_USB);
- } else if (usbConfigured && rndisEnabled) {
- // Tether if rndis is enabled and usb is configured.
- tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
- } else if (usbConnected && ncmEnabled) {
- tetherMatchingInterfaces(IpServer.STATE_LOCAL_ONLY, TETHERING_NCM);
- }
- mRndisEnabled = usbConfigured && rndisEnabled;
- }
- }
-
- private void handleWifiApAction(Intent intent) {
- final int curState = intent.getIntExtra(EXTRA_WIFI_AP_STATE, WIFI_AP_STATE_DISABLED);
- final String ifname = intent.getStringExtra(EXTRA_WIFI_AP_INTERFACE_NAME);
- final int ipmode = intent.getIntExtra(EXTRA_WIFI_AP_MODE, IFACE_IP_MODE_UNSPECIFIED);
-
- synchronized (Tethering.this.mPublicSync) {
- switch (curState) {
- case WifiManager.WIFI_AP_STATE_ENABLING:
- // We can see this state on the way to both enabled and failure states.
- break;
- case WifiManager.WIFI_AP_STATE_ENABLED:
- enableWifiIpServingLocked(ifname, ipmode);
- break;
- case WifiManager.WIFI_AP_STATE_DISABLING:
- // We can see this state on the way to disabled.
- break;
- case WifiManager.WIFI_AP_STATE_DISABLED:
- case WifiManager.WIFI_AP_STATE_FAILED:
- default:
- disableWifiIpServingLocked(ifname, curState);
- break;
- }
- }
- }
-
- private boolean isGroupOwner(WifiP2pGroup group) {
- return group != null && group.isGroupOwner()
- && !TextUtils.isEmpty(group.getInterface());
- }
-
- private void handleWifiP2pAction(Intent intent) {
- if (mConfig.isWifiP2pLegacyTetheringMode()) return;
-
- final WifiP2pInfo p2pInfo =
- (WifiP2pInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);
- final WifiP2pGroup group =
- (WifiP2pGroup) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP);
-
- if (VDBG) {
- Log.d(TAG, "WifiP2pAction: P2pInfo: " + p2pInfo + " Group: " + group);
- }
-
- synchronized (Tethering.this.mPublicSync) {
- // if no group is formed, bring it down if needed.
- if (p2pInfo == null || !p2pInfo.groupFormed) {
- disableWifiP2pIpServingLockedIfNeeded(mWifiP2pTetherInterface);
- mWifiP2pTetherInterface = null;
- return;
- }
-
- // If there is a group but the device is not the owner, bail out.
- if (!isGroupOwner(group)) return;
-
- // If already serving from the correct interface, nothing to do.
- if (group.getInterface().equals(mWifiP2pTetherInterface)) return;
-
- // If already serving from another interface, turn it down first.
- if (!TextUtils.isEmpty(mWifiP2pTetherInterface)) {
- mLog.w("P2P tethered interface " + mWifiP2pTetherInterface
- + "is different from current interface "
- + group.getInterface() + ", re-tether it");
- disableWifiP2pIpServingLockedIfNeeded(mWifiP2pTetherInterface);
- }
-
- // Finally bring up serving on the new interface
- mWifiP2pTetherInterface = group.getInterface();
- enableWifiIpServingLocked(mWifiP2pTetherInterface, IFACE_IP_MODE_LOCAL_ONLY);
- }
- }
-
- private void handleUserRestrictionAction() {
- mTetheringRestriction.onUserRestrictionsChanged();
- }
-
- private void handleDataSaverChanged() {
- final ConnectivityManager connMgr = (ConnectivityManager) mContext.getSystemService(
- Context.CONNECTIVITY_SERVICE);
- final boolean isDataSaverEnabled = connMgr.getRestrictBackgroundStatus()
- != ConnectivityManager.RESTRICT_BACKGROUND_STATUS_DISABLED;
-
- if (mDataSaverEnabled == isDataSaverEnabled) return;
-
- mDataSaverEnabled = isDataSaverEnabled;
- if (mDataSaverEnabled) {
- untetherAll();
- }
- }
- }
-
- @VisibleForTesting
- boolean isTetheringActive() {
- return mActiveTetheringRequests.size() > 0;
- }
-
- @VisibleForTesting
- protected static class UserRestrictionActionListener {
- private final UserManager mUserMgr;
- private final Tethering mWrapper;
- private final TetheringNotificationUpdater mNotificationUpdater;
- public boolean mDisallowTethering;
-
- public UserRestrictionActionListener(@NonNull UserManager um, @NonNull Tethering wrapper,
- @NonNull TetheringNotificationUpdater updater) {
- mUserMgr = um;
- mWrapper = wrapper;
- mNotificationUpdater = updater;
- mDisallowTethering = false;
- }
-
- public void onUserRestrictionsChanged() {
- // getUserRestrictions gets restriction for this process' user, which is the primary
- // user. This is fine because DISALLOW_CONFIG_TETHERING can only be set on the primary
- // user. See UserManager.DISALLOW_CONFIG_TETHERING.
- final Bundle restrictions = mUserMgr.getUserRestrictions();
- final boolean newlyDisallowed =
- restrictions.getBoolean(UserManager.DISALLOW_CONFIG_TETHERING);
- final boolean prevDisallowed = mDisallowTethering;
- mDisallowTethering = newlyDisallowed;
-
- final boolean tetheringDisallowedChanged = (newlyDisallowed != prevDisallowed);
- if (!tetheringDisallowedChanged) {
- return;
- }
-
- if (!newlyDisallowed) {
- // Clear the restricted notification when user is allowed to have tethering
- // function.
- mNotificationUpdater.tetheringRestrictionLifted();
- return;
- }
-
- if (mWrapper.isTetheringActive()) {
- // Restricted notification is shown when tethering function is disallowed on
- // user's device.
- mNotificationUpdater.notifyTetheringDisabledByRestriction();
-
- // Untether from all downstreams since tethering is disallowed.
- mWrapper.untetherAll();
- }
- // TODO(b/148139325): send tetheringSupported on restriction change
- }
- }
-
- private void disableWifiIpServingLockedCommon(int tetheringType, String ifname, int apState) {
- mLog.log("Canceling WiFi tethering request -"
- + " type=" + tetheringType
- + " interface=" + ifname
- + " state=" + apState);
-
- if (!TextUtils.isEmpty(ifname)) {
- final TetherState ts = mTetherStates.get(ifname);
- if (ts != null) {
- ts.ipServer.unwanted();
- return;
- }
- }
-
- for (int i = 0; i < mTetherStates.size(); i++) {
- final IpServer ipServer = mTetherStates.valueAt(i).ipServer;
- if (ipServer.interfaceType() == tetheringType) {
- ipServer.unwanted();
- return;
- }
- }
-
- mLog.log("Error disabling Wi-Fi IP serving; "
- + (TextUtils.isEmpty(ifname) ? "no interface name specified"
- : "specified interface: " + ifname));
- }
-
- private void disableWifiIpServingLocked(String ifname, int apState) {
- // Regardless of whether we requested this transition, the AP has gone
- // down. Don't try to tether again unless we're requested to do so.
- // TODO: Remove this altogether, once Wi-Fi reliably gives us an
- // interface name with every broadcast.
- mWifiTetherRequested = false;
-
- disableWifiIpServingLockedCommon(TETHERING_WIFI, ifname, apState);
- }
-
- private void disableWifiP2pIpServingLockedIfNeeded(String ifname) {
- if (TextUtils.isEmpty(ifname)) return;
-
- disableWifiIpServingLockedCommon(TETHERING_WIFI_P2P, ifname, /* fake */ 0);
- }
-
- private void enableWifiIpServingLocked(String ifname, int wifiIpMode) {
- // Map wifiIpMode values to IpServer.Callback serving states, inferring
- // from mWifiTetherRequested as a final "best guess".
- final int ipServingMode;
- switch (wifiIpMode) {
- case IFACE_IP_MODE_TETHERED:
- ipServingMode = IpServer.STATE_TETHERED;
- break;
- case IFACE_IP_MODE_LOCAL_ONLY:
- ipServingMode = IpServer.STATE_LOCAL_ONLY;
- break;
- default:
- mLog.e("Cannot enable IP serving in unknown WiFi mode: " + wifiIpMode);
- return;
- }
-
- if (!TextUtils.isEmpty(ifname)) {
- maybeTrackNewInterfaceLocked(ifname);
- changeInterfaceState(ifname, ipServingMode);
- } else {
- mLog.e(String.format(
- "Cannot enable IP serving in mode %s on missing interface name",
- ipServingMode));
- }
- }
-
- // TODO: Consider renaming to something more accurate in its description.
- // This method:
- // - allows requesting either tethering or local hotspot serving states
- // - handles both enabling and disabling serving states
- // - only tethers the first matching interface in listInterfaces()
- // order of a given type
- private void tetherMatchingInterfaces(int requestedState, int interfaceType) {
- if (VDBG) {
- Log.d(TAG, "tetherMatchingInterfaces(" + requestedState + ", " + interfaceType + ")");
- }
-
- String[] ifaces = null;
- try {
- ifaces = mNetd.interfaceGetList();
- } catch (RemoteException | ServiceSpecificException e) {
- Log.e(TAG, "Error listing Interfaces", e);
- return;
- }
- String chosenIface = null;
- if (ifaces != null) {
- for (String iface : ifaces) {
- if (ifaceNameToType(iface) == interfaceType) {
- chosenIface = iface;
- break;
- }
- }
- }
- if (chosenIface == null) {
- Log.e(TAG, "could not find iface of type " + interfaceType);
- return;
- }
-
- changeInterfaceState(chosenIface, requestedState);
- }
-
- private void changeInterfaceState(String ifname, int requestedState) {
- final int result;
- switch (requestedState) {
- case IpServer.STATE_UNAVAILABLE:
- case IpServer.STATE_AVAILABLE:
- result = untether(ifname);
- break;
- case IpServer.STATE_TETHERED:
- case IpServer.STATE_LOCAL_ONLY:
- result = tether(ifname, requestedState);
- break;
- default:
- Log.wtf(TAG, "Unknown interface state: " + requestedState);
- return;
- }
- if (result != TETHER_ERROR_NO_ERROR) {
- Log.e(TAG, "unable start or stop tethering on iface " + ifname);
- return;
- }
- }
-
- TetheringConfiguration getTetheringConfiguration() {
- return mConfig;
- }
-
- boolean hasTetherableConfiguration() {
- final TetheringConfiguration cfg = mConfig;
- final boolean hasDownstreamConfiguration =
- (cfg.tetherableUsbRegexs.length != 0)
- || (cfg.tetherableWifiRegexs.length != 0)
- || (cfg.tetherableBluetoothRegexs.length != 0);
- final boolean hasUpstreamConfiguration = !cfg.preferredUpstreamIfaceTypes.isEmpty()
- || cfg.chooseUpstreamAutomatically;
-
- return hasDownstreamConfiguration && hasUpstreamConfiguration;
- }
-
- // TODO - update callers to use getTetheringConfiguration(),
- // which has only final members.
- String[] getTetherableUsbRegexs() {
- return copy(mConfig.tetherableUsbRegexs);
- }
-
- String[] getTetherableWifiRegexs() {
- return copy(mConfig.tetherableWifiRegexs);
- }
-
- String[] getTetherableBluetoothRegexs() {
- return copy(mConfig.tetherableBluetoothRegexs);
- }
-
- int setUsbTethering(boolean enable) {
- if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
- UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
- if (usbManager == null) {
- mLog.e("setUsbTethering: failed to get UsbManager!");
- return TETHER_ERROR_SERVICE_UNAVAIL;
- }
-
- synchronized (mPublicSync) {
- usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_RNDIS
- : UsbManager.FUNCTION_NONE);
- }
- return TETHER_ERROR_NO_ERROR;
- }
-
- private int setNcmTethering(boolean enable) {
- if (VDBG) Log.d(TAG, "setNcmTethering(" + enable + ")");
- UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
- synchronized (mPublicSync) {
- usbManager.setCurrentFunctions(enable ? UsbManager.FUNCTION_NCM
- : UsbManager.FUNCTION_NONE);
- }
- return TETHER_ERROR_NO_ERROR;
- }
-
- // TODO review API - figure out how to delete these entirely.
- String[] getTetheredIfaces() {
- ArrayList list = new ArrayList();
- synchronized (mPublicSync) {
- for (int i = 0; i < mTetherStates.size(); i++) {
- TetherState tetherState = mTetherStates.valueAt(i);
- if (tetherState.lastState == IpServer.STATE_TETHERED) {
- list.add(mTetherStates.keyAt(i));
- }
- }
- }
- return list.toArray(new String[list.size()]);
- }
-
- String[] getTetherableIfaces() {
- ArrayList list = new ArrayList();
- synchronized (mPublicSync) {
- for (int i = 0; i < mTetherStates.size(); i++) {
- TetherState tetherState = mTetherStates.valueAt(i);
- if (tetherState.lastState == IpServer.STATE_AVAILABLE) {
- list.add(mTetherStates.keyAt(i));
- }
- }
- }
- return list.toArray(new String[list.size()]);
- }
-
- String[] getTetheredDhcpRanges() {
- // TODO: this is only valid for the old DHCP server. Latest search suggests it is only used
- // by WifiP2pServiceImpl to start dnsmasq: remove/deprecate after migrating callers.
- return mConfig.legacyDhcpRanges;
- }
-
- String[] getErroredIfaces() {
- ArrayList list = new ArrayList();
- synchronized (mPublicSync) {
- for (int i = 0; i < mTetherStates.size(); i++) {
- TetherState tetherState = mTetherStates.valueAt(i);
- if (tetherState.lastError != TETHER_ERROR_NO_ERROR) {
- list.add(mTetherStates.keyAt(i));
- }
- }
- }
- return list.toArray(new String[list.size()]);
- }
-
- private void logMessage(State state, int what) {
- mLog.log(state.getName() + " got " + sMagicDecoderRing.get(what, Integer.toString(what)));
- }
-
- private boolean upstreamWanted() {
- if (!mForwardedDownstreams.isEmpty()) return true;
-
- synchronized (mPublicSync) {
- return mWifiTetherRequested;
- }
- }
-
- // Needed because the canonical source of upstream truth is just the
- // upstream interface set, |mCurrentUpstreamIfaceSet|.
- private boolean pertainsToCurrentUpstream(UpstreamNetworkState ns) {
- if (ns != null && ns.linkProperties != null && mCurrentUpstreamIfaceSet != null) {
- for (String ifname : ns.linkProperties.getAllInterfaceNames()) {
- if (mCurrentUpstreamIfaceSet.ifnames.contains(ifname)) {
- return true;
- }
- }
- }
- return false;
- }
-
- class TetherMainSM extends StateMachine {
- // an interface SM has requested Tethering/Local Hotspot
- static final int EVENT_IFACE_SERVING_STATE_ACTIVE = BASE_MAIN_SM + 1;
- // an interface SM has unrequested Tethering/Local Hotspot
- static final int EVENT_IFACE_SERVING_STATE_INACTIVE = BASE_MAIN_SM + 2;
- // upstream connection change - do the right thing
- static final int CMD_UPSTREAM_CHANGED = BASE_MAIN_SM + 3;
- // we don't have a valid upstream conn, check again after a delay
- static final int CMD_RETRY_UPSTREAM = BASE_MAIN_SM + 4;
- // Events from NetworkCallbacks that we process on the main state
- // machine thread on behalf of the UpstreamNetworkMonitor.
- static final int EVENT_UPSTREAM_CALLBACK = BASE_MAIN_SM + 5;
- // we treated the error and want now to clear it
- static final int CMD_CLEAR_ERROR = BASE_MAIN_SM + 6;
- static final int EVENT_IFACE_UPDATE_LINKPROPERTIES = BASE_MAIN_SM + 7;
- // Events from EntitlementManager to choose upstream again.
- static final int EVENT_UPSTREAM_PERMISSION_CHANGED = BASE_MAIN_SM + 8;
- private final State mInitialState;
- private final State mTetherModeAliveState;
-
- private final State mSetIpForwardingEnabledErrorState;
- private final State mSetIpForwardingDisabledErrorState;
- private final State mStartTetheringErrorState;
- private final State mStopTetheringErrorState;
- private final State mSetDnsForwardersErrorState;
-
- // This list is a little subtle. It contains all the interfaces that currently are
- // requesting tethering, regardless of whether these interfaces are still members of
- // mTetherStates. This allows us to maintain the following predicates:
- //
- // 1) mTetherStates contains the set of all currently existing, tetherable, link state up
- // interfaces.
- // 2) mNotifyList contains all state machines that may have outstanding tethering state
- // that needs to be torn down.
- //
- // Because we excise interfaces immediately from mTetherStates, we must maintain mNotifyList
- // so that the garbage collector does not clean up the state machine before it has a chance
- // to tear itself down.
- private final ArrayList mNotifyList;
- private final IPv6TetheringCoordinator mIPv6TetheringCoordinator;
- private final OffloadWrapper mOffload;
-
- private static final int UPSTREAM_SETTLE_TIME_MS = 10000;
-
- TetherMainSM(String name, Looper looper, TetheringDependencies deps) {
- super(name, looper);
-
- mInitialState = new InitialState();
- mTetherModeAliveState = new TetherModeAliveState();
- mSetIpForwardingEnabledErrorState = new SetIpForwardingEnabledErrorState();
- mSetIpForwardingDisabledErrorState = new SetIpForwardingDisabledErrorState();
- mStartTetheringErrorState = new StartTetheringErrorState();
- mStopTetheringErrorState = new StopTetheringErrorState();
- mSetDnsForwardersErrorState = new SetDnsForwardersErrorState();
-
- addState(mInitialState);
- addState(mTetherModeAliveState);
- addState(mSetIpForwardingEnabledErrorState);
- addState(mSetIpForwardingDisabledErrorState);
- addState(mStartTetheringErrorState);
- addState(mStopTetheringErrorState);
- addState(mSetDnsForwardersErrorState);
-
- mNotifyList = new ArrayList<>();
- mIPv6TetheringCoordinator = deps.getIPv6TetheringCoordinator(mNotifyList, mLog);
- mOffload = new OffloadWrapper();
-
- setInitialState(mInitialState);
- }
-
- class InitialState extends State {
- @Override
- public boolean processMessage(Message message) {
- logMessage(this, message.what);
- switch (message.what) {
- case EVENT_IFACE_SERVING_STATE_ACTIVE: {
- final IpServer who = (IpServer) message.obj;
- if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
- handleInterfaceServingStateActive(message.arg1, who);
- transitionTo(mTetherModeAliveState);
- break;
- }
- case EVENT_IFACE_SERVING_STATE_INACTIVE: {
- final IpServer who = (IpServer) message.obj;
- if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
- handleInterfaceServingStateInactive(who);
- break;
- }
- case EVENT_IFACE_UPDATE_LINKPROPERTIES:
- // Silently ignore these for now.
- break;
- default:
- return NOT_HANDLED;
- }
- return HANDLED;
- }
- }
-
- protected boolean turnOnMainTetherSettings() {
- final TetheringConfiguration cfg = mConfig;
- try {
- mNetd.ipfwdEnableForwarding(TAG);
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e(e);
- transitionTo(mSetIpForwardingEnabledErrorState);
- return false;
- }
-
- // TODO: Randomize DHCPv4 ranges, especially in hotspot mode.
- // Legacy DHCP server is disabled if passed an empty ranges array
- final String[] dhcpRanges = cfg.enableLegacyDhcpServer
- ? cfg.legacyDhcpRanges : new String[0];
- try {
- NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges);
- } catch (RemoteException | ServiceSpecificException e) {
- try {
- // Stop and retry.
- mNetd.tetherStop();
- NetdUtils.tetherStart(mNetd, true /** usingLegacyDnsProxy */, dhcpRanges);
- } catch (RemoteException | ServiceSpecificException ee) {
- mLog.e(ee);
- transitionTo(mStartTetheringErrorState);
- return false;
- }
- }
- mLog.log("SET main tether settings: ON");
- return true;
- }
-
- protected boolean turnOffMainTetherSettings() {
- try {
- mNetd.tetherStop();
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e(e);
- transitionTo(mStopTetheringErrorState);
- return false;
- }
- try {
- mNetd.ipfwdDisableForwarding(TAG);
- } catch (RemoteException | ServiceSpecificException e) {
- mLog.e(e);
- transitionTo(mSetIpForwardingDisabledErrorState);
- return false;
- }
- transitionTo(mInitialState);
- mLog.log("SET main tether settings: OFF");
- return true;
- }
-
- protected void chooseUpstreamType(boolean tryCell) {
- // We rebuild configuration on ACTION_CONFIGURATION_CHANGED, but we
- // do not currently know how to watch for changes in DUN settings.
- maybeDunSettingChanged();
-
- final TetheringConfiguration config = mConfig;
- final UpstreamNetworkState ns = (config.chooseUpstreamAutomatically)
- ? mUpstreamNetworkMonitor.getCurrentPreferredUpstream()
- : mUpstreamNetworkMonitor.selectPreferredUpstreamType(
- config.preferredUpstreamIfaceTypes);
- if (ns == null) {
- if (tryCell) {
- mUpstreamNetworkMonitor.registerMobileNetworkRequest();
- // We think mobile should be coming up; don't set a retry.
- } else {
- sendMessageDelayed(CMD_RETRY_UPSTREAM, UPSTREAM_SETTLE_TIME_MS);
- }
- }
- setUpstreamNetwork(ns);
- final Network newUpstream = (ns != null) ? ns.network : null;
- if (mTetherUpstream != newUpstream) {
- mTetherUpstream = newUpstream;
- mUpstreamNetworkMonitor.setCurrentUpstream(mTetherUpstream);
- reportUpstreamChanged(ns);
- }
- }
-
- protected void setUpstreamNetwork(UpstreamNetworkState ns) {
- InterfaceSet ifaces = null;
- if (ns != null) {
- // Find the interface with the default IPv4 route. It may be the
- // interface described by linkProperties, or one of the interfaces
- // stacked on top of it.
- mLog.i("Looking for default routes on: " + ns.linkProperties);
- ifaces = TetheringInterfaceUtils.getTetheringInterfaces(ns);
- mLog.i("Found upstream interface(s): " + ifaces);
- }
-
- if (ifaces != null) {
- setDnsForwarders(ns.network, ns.linkProperties);
- }
- notifyDownstreamsOfNewUpstreamIface(ifaces);
- if (ns != null && pertainsToCurrentUpstream(ns)) {
- // If we already have UpstreamNetworkState for this network update it immediately.
- handleNewUpstreamNetworkState(ns);
- } else if (mCurrentUpstreamIfaceSet == null) {
- // There are no available upstream networks.
- handleNewUpstreamNetworkState(null);
- }
- }
-
- protected void setDnsForwarders(final Network network, final LinkProperties lp) {
- // TODO: Set v4 and/or v6 DNS per available connectivity.
- final Collection dnses = lp.getDnsServers();
- // TODO: Properly support the absence of DNS servers.
- final String[] dnsServers;
- if (dnses != null && !dnses.isEmpty()) {
- dnsServers = new String[dnses.size()];
- int i = 0;
- for (InetAddress dns : dnses) {
- dnsServers[i++] = dns.getHostAddress();
- }
- } else {
- dnsServers = mConfig.defaultIPv4DNS;
- }
- final int netId = (network != null) ? network.getNetId() : NETID_UNSET;
- try {
- mNetd.tetherDnsSet(netId, dnsServers);
- mLog.log(String.format(
- "SET DNS forwarders: network=%s dnsServers=%s",
- network, Arrays.toString(dnsServers)));
- } catch (RemoteException | ServiceSpecificException e) {
- // TODO: Investigate how this can fail and what exactly
- // happens if/when such failures occur.
- mLog.e("setting DNS forwarders failed, " + e);
- transitionTo(mSetDnsForwardersErrorState);
- }
- }
-
- protected void notifyDownstreamsOfNewUpstreamIface(InterfaceSet ifaces) {
- mCurrentUpstreamIfaceSet = ifaces;
- for (IpServer ipServer : mNotifyList) {
- ipServer.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED, ifaces);
- }
- }
-
- protected void handleNewUpstreamNetworkState(UpstreamNetworkState ns) {
- mIPv6TetheringCoordinator.updateUpstreamNetworkState(ns);
- mOffload.updateUpstreamNetworkState(ns);
- }
-
- private void handleInterfaceServingStateActive(int mode, IpServer who) {
- if (mNotifyList.indexOf(who) < 0) {
- mNotifyList.add(who);
- mIPv6TetheringCoordinator.addActiveDownstream(who, mode);
- }
-
- if (mode == IpServer.STATE_TETHERED) {
- // No need to notify OffloadController just yet as there are no
- // "offload-able" prefixes to pass along. This will handled
- // when the TISM informs Tethering of its LinkProperties.
- mForwardedDownstreams.add(who);
- } else {
- mOffload.excludeDownstreamInterface(who.interfaceName());
- mForwardedDownstreams.remove(who);
- }
-
- // If this is a Wi-Fi interface, notify WifiManager of the active serving state.
- if (who.interfaceType() == TETHERING_WIFI) {
- final WifiManager mgr = getWifiManager();
- final String iface = who.interfaceName();
- switch (mode) {
- case IpServer.STATE_TETHERED:
- mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_TETHERED);
- break;
- case IpServer.STATE_LOCAL_ONLY:
- mgr.updateInterfaceIpState(iface, IFACE_IP_MODE_LOCAL_ONLY);
- break;
- default:
- Log.wtf(TAG, "Unknown active serving mode: " + mode);
- break;
- }
- }
- }
-
- private void handleInterfaceServingStateInactive(IpServer who) {
- mNotifyList.remove(who);
- mIPv6TetheringCoordinator.removeActiveDownstream(who);
- mOffload.excludeDownstreamInterface(who.interfaceName());
- mForwardedDownstreams.remove(who);
- updateConnectedClients(null /* wifiClients */);
-
- // If this is a Wi-Fi interface, tell WifiManager of any errors
- // or the inactive serving state.
- if (who.interfaceType() == TETHERING_WIFI) {
- if (who.lastError() != TETHER_ERROR_NO_ERROR) {
- getWifiManager().updateInterfaceIpState(
- who.interfaceName(), IFACE_IP_MODE_CONFIGURATION_ERROR);
- } else {
- getWifiManager().updateInterfaceIpState(
- who.interfaceName(), IFACE_IP_MODE_UNSPECIFIED);
- }
- }
- }
-
- @VisibleForTesting
- void handleUpstreamNetworkMonitorCallback(int arg1, Object o) {
- if (arg1 == UpstreamNetworkMonitor.NOTIFY_LOCAL_PREFIXES) {
- mOffload.sendOffloadExemptPrefixes((Set) o);
- return;
- }
-
- final UpstreamNetworkState ns = (UpstreamNetworkState) o;
- switch (arg1) {
- case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
- mPrivateAddressCoordinator.updateUpstreamPrefix(ns);
- break;
- case UpstreamNetworkMonitor.EVENT_ON_LOST:
- mPrivateAddressCoordinator.removeUpstreamPrefix(ns.network);
- break;
- }
-
- if (ns == null || !pertainsToCurrentUpstream(ns)) {
- // TODO: In future, this is where upstream evaluation and selection
- // could be handled for notifications which include sufficient data.
- // For example, after CONNECTIVITY_ACTION listening is removed, here
- // is where we could observe a Wi-Fi network becoming available and
- // passing validation.
- if (mCurrentUpstreamIfaceSet == null) {
- // If we have no upstream interface, try to run through upstream
- // selection again. If, for example, IPv4 connectivity has shown up
- // after IPv6 (e.g., 464xlat became available) we want the chance to
- // notice and act accordingly.
- chooseUpstreamType(false);
- }
- return;
- }
-
- switch (arg1) {
- case UpstreamNetworkMonitor.EVENT_ON_CAPABILITIES:
- if (ns.network.equals(mTetherUpstream)) {
- mNotificationUpdater.onUpstreamCapabilitiesChanged(ns.networkCapabilities);
- }
- handleNewUpstreamNetworkState(ns);
- break;
- case UpstreamNetworkMonitor.EVENT_ON_LINKPROPERTIES:
- chooseUpstreamType(false);
- break;
- case UpstreamNetworkMonitor.EVENT_ON_LOST:
- // TODO: Re-evaluate possible upstreams. Currently upstream
- // reevaluation is triggered via received CONNECTIVITY_ACTION
- // broadcasts that result in being passed a
- // TetherMainSM.CMD_UPSTREAM_CHANGED.
- handleNewUpstreamNetworkState(null);
- break;
- default:
- mLog.e("Unknown arg1 value: " + arg1);
- break;
- }
- }
-
- class TetherModeAliveState extends State {
- boolean mUpstreamWanted = false;
- boolean mTryCell = true;
-
- @Override
- public void enter() {
- // If turning on main tether settings fails, we have already
- // transitioned to an error state; exit early.
- if (!turnOnMainTetherSettings()) {
- return;
- }
-
- mPrivateAddressCoordinator.maybeRemoveDeprecatedUpstreams();
- mUpstreamNetworkMonitor.startObserveAllNetworks();
-
- // TODO: De-duplicate with updateUpstreamWanted() below.
- if (upstreamWanted()) {
- mUpstreamWanted = true;
- mOffload.start();
- chooseUpstreamType(true);
- mTryCell = false;
- }
-
- // TODO: Check the upstream interface if it is managed by BPF offload.
- mBpfCoordinator.startPolling();
- }
-
- @Override
- public void exit() {
- mOffload.stop();
- mUpstreamNetworkMonitor.stop();
- notifyDownstreamsOfNewUpstreamIface(null);
- handleNewUpstreamNetworkState(null);
- if (mTetherUpstream != null) {
- mTetherUpstream = null;
- reportUpstreamChanged(null);
- }
- mBpfCoordinator.stopPolling();
- }
-
- private boolean updateUpstreamWanted() {
- final boolean previousUpstreamWanted = mUpstreamWanted;
- mUpstreamWanted = upstreamWanted();
- if (mUpstreamWanted != previousUpstreamWanted) {
- if (mUpstreamWanted) {
- mOffload.start();
- } else {
- mOffload.stop();
- }
- }
- return previousUpstreamWanted;
- }
-
- @Override
- public boolean processMessage(Message message) {
- logMessage(this, message.what);
- boolean retValue = true;
- switch (message.what) {
- case EVENT_IFACE_SERVING_STATE_ACTIVE: {
- IpServer who = (IpServer) message.obj;
- if (VDBG) Log.d(TAG, "Tether Mode requested by " + who);
- handleInterfaceServingStateActive(message.arg1, who);
- who.sendMessage(IpServer.CMD_TETHER_CONNECTION_CHANGED,
- mCurrentUpstreamIfaceSet);
- // If there has been a change and an upstream is now
- // desired, kick off the selection process.
- final boolean previousUpstreamWanted = updateUpstreamWanted();
- if (!previousUpstreamWanted && mUpstreamWanted) {
- chooseUpstreamType(true);
- }
- break;
- }
- case EVENT_IFACE_SERVING_STATE_INACTIVE: {
- IpServer who = (IpServer) message.obj;
- if (VDBG) Log.d(TAG, "Tether Mode unrequested by " + who);
- handleInterfaceServingStateInactive(who);
-
- if (mNotifyList.isEmpty()) {
- // This transitions us out of TetherModeAliveState,
- // either to InitialState or an error state.
- turnOffMainTetherSettings();
- break;
- }
-
- if (DBG) {
- Log.d(TAG, "TetherModeAlive still has " + mNotifyList.size()
- + " live requests:");
- for (IpServer o : mNotifyList) {
- Log.d(TAG, " " + o);
- }
- }
- // If there has been a change and an upstream is no
- // longer desired, release any mobile requests.
- final boolean previousUpstreamWanted = updateUpstreamWanted();
- if (previousUpstreamWanted && !mUpstreamWanted) {
- mUpstreamNetworkMonitor.releaseMobileNetworkRequest();
- }
- break;
- }
- case EVENT_IFACE_UPDATE_LINKPROPERTIES: {
- final LinkProperties newLp = (LinkProperties) message.obj;
- if (message.arg1 == IpServer.STATE_TETHERED) {
- mOffload.updateDownstreamLinkProperties(newLp);
- } else {
- mOffload.excludeDownstreamInterface(newLp.getInterfaceName());
- }
- break;
- }
- case EVENT_UPSTREAM_PERMISSION_CHANGED:
- case CMD_UPSTREAM_CHANGED:
- updateUpstreamWanted();
- if (!mUpstreamWanted) break;
-
- // Need to try DUN immediately if Wi-Fi goes down.
- chooseUpstreamType(true);
- mTryCell = false;
- break;
- case CMD_RETRY_UPSTREAM:
- updateUpstreamWanted();
- if (!mUpstreamWanted) break;
-
- chooseUpstreamType(mTryCell);
- mTryCell = !mTryCell;
- break;
- case EVENT_UPSTREAM_CALLBACK: {
- updateUpstreamWanted();
- if (mUpstreamWanted) {
- handleUpstreamNetworkMonitorCallback(message.arg1, message.obj);
- }
- break;
- }
- default:
- retValue = false;
- break;
- }
- return retValue;
- }
- }
-
- class ErrorState extends State {
- private int mErrorNotification;
-
- @Override
- public boolean processMessage(Message message) {
- boolean retValue = true;
- switch (message.what) {
- case EVENT_IFACE_SERVING_STATE_ACTIVE:
- IpServer who = (IpServer) message.obj;
- who.sendMessage(mErrorNotification);
- break;
- case CMD_CLEAR_ERROR:
- mErrorNotification = TETHER_ERROR_NO_ERROR;
- transitionTo(mInitialState);
- break;
- default:
- retValue = false;
- }
- return retValue;
- }
-
- void notify(int msgType) {
- mErrorNotification = msgType;
- for (IpServer ipServer : mNotifyList) {
- ipServer.sendMessage(msgType);
- }
- }
-
- }
-
- class SetIpForwardingEnabledErrorState extends ErrorState {
- @Override
- public void enter() {
- Log.e(TAG, "Error in setIpForwardingEnabled");
- notify(IpServer.CMD_IP_FORWARDING_ENABLE_ERROR);
- }
- }
-
- class SetIpForwardingDisabledErrorState extends ErrorState {
- @Override
- public void enter() {
- Log.e(TAG, "Error in setIpForwardingDisabled");
- notify(IpServer.CMD_IP_FORWARDING_DISABLE_ERROR);
- }
- }
-
- class StartTetheringErrorState extends ErrorState {
- @Override
- public void enter() {
- Log.e(TAG, "Error in startTethering");
- notify(IpServer.CMD_START_TETHERING_ERROR);
- try {
- mNetd.ipfwdDisableForwarding(TAG);
- } catch (RemoteException | ServiceSpecificException e) { }
- }
- }
-
- class StopTetheringErrorState extends ErrorState {
- @Override
- public void enter() {
- Log.e(TAG, "Error in stopTethering");
- notify(IpServer.CMD_STOP_TETHERING_ERROR);
- try {
- mNetd.ipfwdDisableForwarding(TAG);
- } catch (RemoteException | ServiceSpecificException e) { }
- }
- }
-
- class SetDnsForwardersErrorState extends ErrorState {
- @Override
- public void enter() {
- Log.e(TAG, "Error in setDnsForwarders");
- notify(IpServer.CMD_SET_DNS_FORWARDERS_ERROR);
- try {
- mNetd.tetherStop();
- } catch (RemoteException | ServiceSpecificException e) { }
- try {
- mNetd.ipfwdDisableForwarding(TAG);
- } catch (RemoteException | ServiceSpecificException e) { }
- }
- }
-
- // A wrapper class to handle multiple situations where several calls to
- // the OffloadController need to happen together.
- //
- // TODO: This suggests that the interface between OffloadController and
- // Tethering is in need of improvement. Refactor these calls into the
- // OffloadController implementation.
- class OffloadWrapper {
- public void start() {
- final int status = mOffloadController.start() ? TETHER_HARDWARE_OFFLOAD_STARTED
- : TETHER_HARDWARE_OFFLOAD_FAILED;
- updateOffloadStatus(status);
- sendOffloadExemptPrefixes();
- }
-
- public void stop() {
- mOffloadController.stop();
- updateOffloadStatus(TETHER_HARDWARE_OFFLOAD_STOPPED);
- }
-
- public void updateUpstreamNetworkState(UpstreamNetworkState ns) {
- mOffloadController.setUpstreamLinkProperties(
- (ns != null) ? ns.linkProperties : null);
- }
-
- public void updateDownstreamLinkProperties(LinkProperties newLp) {
- // Update the list of offload-exempt prefixes before adding
- // new prefixes on downstream interfaces to the offload HAL.
- sendOffloadExemptPrefixes();
- mOffloadController.notifyDownstreamLinkProperties(newLp);
- }
-
- public void excludeDownstreamInterface(String ifname) {
- // This and other interfaces may be in local-only hotspot mode;
- // resend all local prefixes to the OffloadController.
- sendOffloadExemptPrefixes();
- mOffloadController.removeDownstreamInterface(ifname);
- }
-
- public void sendOffloadExemptPrefixes() {
- sendOffloadExemptPrefixes(mUpstreamNetworkMonitor.getLocalPrefixes());
- }
-
- public void sendOffloadExemptPrefixes(final Set localPrefixes) {
- // Add in well-known minimum set.
- PrefixUtils.addNonForwardablePrefixes(localPrefixes);
- // Add tragically hardcoded prefixes.
- localPrefixes.add(PrefixUtils.DEFAULT_WIFI_P2P_PREFIX);
-
- // Maybe add prefixes or addresses for downstreams, depending on
- // the IP serving mode of each.
- for (IpServer ipServer : mNotifyList) {
- final LinkProperties lp = ipServer.linkProperties();
-
- switch (ipServer.servingMode()) {
- case IpServer.STATE_UNAVAILABLE:
- case IpServer.STATE_AVAILABLE:
- // No usable LinkProperties in these states.
- continue;
- case IpServer.STATE_TETHERED:
- // Only add IPv4 /32 and IPv6 /128 prefixes. The
- // directly-connected prefixes will be sent as
- // downstream "offload-able" prefixes.
- for (LinkAddress addr : lp.getAllLinkAddresses()) {
- final InetAddress ip = addr.getAddress();
- if (ip.isLinkLocalAddress()) continue;
- localPrefixes.add(PrefixUtils.ipAddressAsPrefix(ip));
- }
- break;
- case IpServer.STATE_LOCAL_ONLY:
- // Add prefixes covering all local IPs.
- localPrefixes.addAll(PrefixUtils.localPrefixesFrom(lp));
- break;
- }
- }
-
- mOffloadController.setLocalPrefixes(localPrefixes);
- }
-
- private void updateOffloadStatus(final int newStatus) {
- if (newStatus == mOffloadStatus) return;
-
- mOffloadStatus = newStatus;
- reportOffloadStatusChanged(mOffloadStatus);
- }
- }
- }
-
- private void startTrackDefaultNetwork() {
- mUpstreamNetworkMonitor.startTrackDefaultNetwork(mDeps.getDefaultNetworkRequest(),
- mEntitlementMgr);
- }
-
- /** Get the latest value of the tethering entitlement check. */
- void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
- boolean showEntitlementUi) {
- if (receiver == null) return;
-
- mHandler.post(() -> {
- mEntitlementMgr.requestLatestTetheringEntitlementResult(type, receiver,
- showEntitlementUi);
- });
- }
-
- /** Register tethering event callback */
- void registerTetheringEventCallback(ITetheringEventCallback callback) {
- final boolean hasListPermission =
- hasCallingPermission(NETWORK_SETTINGS)
- || hasCallingPermission(PERMISSION_MAINLINE_NETWORK_STACK)
- || hasCallingPermission(NETWORK_STACK);
- mHandler.post(() -> {
- mTetheringEventCallbacks.register(callback, new CallbackCookie(hasListPermission));
- final TetheringCallbackStartedParcel parcel = new TetheringCallbackStartedParcel();
- parcel.tetheringSupported = isTetheringSupported();
- parcel.upstreamNetwork = mTetherUpstream;
- parcel.config = mConfig.toStableParcelable();
- parcel.states =
- mTetherStatesParcel != null ? mTetherStatesParcel : emptyTetherStatesParcel();
- parcel.tetheredClients = hasListPermission
- ? mConnectedClientsTracker.getLastTetheredClients()
- : Collections.emptyList();
- parcel.offloadStatus = mOffloadStatus;
- try {
- callback.onCallbackStarted(parcel);
- } catch (RemoteException e) {
- // Not really very much to do here.
- }
- });
- }
-
- private TetherStatesParcel emptyTetherStatesParcel() {
- final TetherStatesParcel parcel = new TetherStatesParcel();
- parcel.availableList = new String[0];
- parcel.tetheredList = new String[0];
- parcel.localOnlyList = new String[0];
- parcel.erroredIfaceList = new String[0];
- parcel.lastErrorList = new int[0];
-
- return parcel;
- }
-
- private boolean hasCallingPermission(@NonNull String permission) {
- return mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
- }
-
- /** Unregister tethering event callback */
- void unregisterTetheringEventCallback(ITetheringEventCallback callback) {
- mHandler.post(() -> {
- mTetheringEventCallbacks.unregister(callback);
- });
- }
-
- private void reportUpstreamChanged(UpstreamNetworkState ns) {
- final int length = mTetheringEventCallbacks.beginBroadcast();
- final Network network = (ns != null) ? ns.network : null;
- final NetworkCapabilities capabilities = (ns != null) ? ns.networkCapabilities : null;
- try {
- for (int i = 0; i < length; i++) {
- try {
- mTetheringEventCallbacks.getBroadcastItem(i).onUpstreamChanged(network);
- } catch (RemoteException e) {
- // Not really very much to do here.
- }
- }
- } finally {
- mTetheringEventCallbacks.finishBroadcast();
- }
- // Need to notify capabilities change after upstream network changed because new network's
- // capabilities should be checked every time.
- mNotificationUpdater.onUpstreamCapabilitiesChanged(capabilities);
- }
-
- private void reportConfigurationChanged(TetheringConfigurationParcel config) {
- final int length = mTetheringEventCallbacks.beginBroadcast();
- try {
- for (int i = 0; i < length; i++) {
- try {
- mTetheringEventCallbacks.getBroadcastItem(i).onConfigurationChanged(config);
- // TODO(b/148139325): send tetheringSupported on configuration change
- } catch (RemoteException e) {
- // Not really very much to do here.
- }
- }
- } finally {
- mTetheringEventCallbacks.finishBroadcast();
- }
- }
-
- private void reportTetherStateChanged(TetherStatesParcel states) {
- final int length = mTetheringEventCallbacks.beginBroadcast();
- try {
- for (int i = 0; i < length; i++) {
- try {
- mTetheringEventCallbacks.getBroadcastItem(i).onTetherStatesChanged(states);
- } catch (RemoteException e) {
- // Not really very much to do here.
- }
- }
- } finally {
- mTetheringEventCallbacks.finishBroadcast();
- }
- }
-
- private void reportTetherClientsChanged(List clients) {
- final int length = mTetheringEventCallbacks.beginBroadcast();
- try {
- for (int i = 0; i < length; i++) {
- try {
- final CallbackCookie cookie =
- (CallbackCookie) mTetheringEventCallbacks.getBroadcastCookie(i);
- if (!cookie.hasListClientsPermission) continue;
- mTetheringEventCallbacks.getBroadcastItem(i).onTetherClientsChanged(clients);
- } catch (RemoteException e) {
- // Not really very much to do here.
- }
- }
- } finally {
- mTetheringEventCallbacks.finishBroadcast();
- }
- }
-
- private void reportOffloadStatusChanged(final int status) {
- final int length = mTetheringEventCallbacks.beginBroadcast();
- try {
- for (int i = 0; i < length; i++) {
- try {
- mTetheringEventCallbacks.getBroadcastItem(i).onOffloadStatusChanged(status);
- } catch (RemoteException e) {
- // Not really very much to do here.
- }
- }
- } finally {
- mTetheringEventCallbacks.finishBroadcast();
- }
- }
-
- // if ro.tether.denied = true we default to no tethering
- // gservices could set the secure setting to 1 though to enable it on a build where it
- // had previously been turned off.
- boolean isTetheringSupported() {
- final int defaultVal = mDeps.isTetheringDenied() ? 0 : 1;
- final boolean tetherSupported = Settings.Global.getInt(mContext.getContentResolver(),
- Settings.Global.TETHER_SUPPORTED, defaultVal) != 0;
- final boolean tetherEnabledInSettings = tetherSupported
- && !mUserManager.hasUserRestriction(UserManager.DISALLOW_CONFIG_TETHERING);
-
- return tetherEnabledInSettings && hasTetherableConfiguration()
- && !isProvisioningNeededButUnavailable();
- }
-
- void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer, @Nullable String[] args) {
- // Binder.java closes the resource for us.
- @SuppressWarnings("resource")
- final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
- if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
- != PERMISSION_GRANTED) {
- pw.println("Permission Denial: can't dump.");
- return;
- }
-
- pw.println("Tethering:");
- pw.increaseIndent();
-
- pw.println("Configuration:");
- pw.increaseIndent();
- final TetheringConfiguration cfg = mConfig;
- cfg.dump(pw);
- pw.decreaseIndent();
-
- pw.println("Entitlement:");
- pw.increaseIndent();
- mEntitlementMgr.dump(pw);
- pw.decreaseIndent();
-
- synchronized (mPublicSync) {
- pw.println("Tether state:");
- pw.increaseIndent();
- for (int i = 0; i < mTetherStates.size(); i++) {
- final String iface = mTetherStates.keyAt(i);
- final TetherState tetherState = mTetherStates.valueAt(i);
- pw.print(iface + " - ");
-
- switch (tetherState.lastState) {
- case IpServer.STATE_UNAVAILABLE:
- pw.print("UnavailableState");
- break;
- case IpServer.STATE_AVAILABLE:
- pw.print("AvailableState");
- break;
- case IpServer.STATE_TETHERED:
- pw.print("TetheredState");
- break;
- case IpServer.STATE_LOCAL_ONLY:
- pw.print("LocalHotspotState");
- break;
- default:
- pw.print("UnknownState");
- break;
- }
- pw.println(" - lastError = " + tetherState.lastError);
- }
- pw.println("Upstream wanted: " + upstreamWanted());
- pw.println("Current upstream interface(s): " + mCurrentUpstreamIfaceSet);
- pw.decreaseIndent();
- }
-
- pw.println("Hardware offload:");
- pw.increaseIndent();
- mOffloadController.dump(pw);
- pw.decreaseIndent();
-
- pw.println("BPF offload:");
- pw.increaseIndent();
- mBpfCoordinator.dump(pw);
- pw.decreaseIndent();
-
- pw.println("Private address coordinator:");
- pw.increaseIndent();
- mPrivateAddressCoordinator.dump(pw);
- pw.decreaseIndent();
-
- pw.println("Log:");
- pw.increaseIndent();
- if (argsContain(args, "--short")) {
- pw.println("");
- } else {
- mLog.dump(fd, pw, args);
- }
- pw.decreaseIndent();
-
- pw.decreaseIndent();
- }
-
- private static boolean argsContain(String[] args, String target) {
- for (String arg : args) {
- if (target.equals(arg)) return true;
- }
- return false;
- }
-
- private void updateConnectedClients(final List wifiClients) {
- if (mConnectedClientsTracker.updateConnectedClients(mForwardedDownstreams, wifiClients)) {
- reportTetherClientsChanged(mConnectedClientsTracker.getLastTetheredClients());
- }
- }
-
- private IpServer.Callback makeControlCallback() {
- return new IpServer.Callback() {
- @Override
- public void updateInterfaceState(IpServer who, int state, int lastError) {
- notifyInterfaceStateChange(who, state, lastError);
- }
-
- @Override
- public void updateLinkProperties(IpServer who, LinkProperties newLp) {
- notifyLinkPropertiesChanged(who, newLp);
- }
-
- @Override
- public void dhcpLeasesChanged() {
- updateConnectedClients(null /* wifiClients */);
- }
-
- @Override
- public void requestEnableTethering(int tetheringType, boolean enabled) {
- enableTetheringInternal(tetheringType, enabled, null);
- }
- };
- }
-
- // TODO: Move into TetherMainSM.
- private void notifyInterfaceStateChange(IpServer who, int state, int error) {
- final String iface = who.interfaceName();
- synchronized (mPublicSync) {
- final TetherState tetherState = mTetherStates.get(iface);
- if (tetherState != null && tetherState.ipServer.equals(who)) {
- tetherState.lastState = state;
- tetherState.lastError = error;
- } else {
- if (DBG) Log.d(TAG, "got notification from stale iface " + iface);
- }
- }
-
- mLog.log(String.format("OBSERVED iface=%s state=%s error=%s", iface, state, error));
-
- // If TetherMainSM is in ErrorState, TetherMainSM stays there.
- // Thus we give a chance for TetherMainSM to recover to InitialState
- // by sending CMD_CLEAR_ERROR
- if (error == TETHER_ERROR_INTERNAL_ERROR) {
- mTetherMainSM.sendMessage(TetherMainSM.CMD_CLEAR_ERROR, who);
- }
- int which;
- switch (state) {
- case IpServer.STATE_UNAVAILABLE:
- case IpServer.STATE_AVAILABLE:
- which = TetherMainSM.EVENT_IFACE_SERVING_STATE_INACTIVE;
- break;
- case IpServer.STATE_TETHERED:
- case IpServer.STATE_LOCAL_ONLY:
- which = TetherMainSM.EVENT_IFACE_SERVING_STATE_ACTIVE;
- break;
- default:
- Log.wtf(TAG, "Unknown interface state: " + state);
- return;
- }
- mTetherMainSM.sendMessage(which, state, 0, who);
- sendTetherStateChangedBroadcast();
- }
-
- private void notifyLinkPropertiesChanged(IpServer who, LinkProperties newLp) {
- final String iface = who.interfaceName();
- final int state;
- synchronized (mPublicSync) {
- final TetherState tetherState = mTetherStates.get(iface);
- if (tetherState != null && tetherState.ipServer.equals(who)) {
- state = tetherState.lastState;
- } else {
- mLog.log("got notification from stale iface " + iface);
- return;
- }
- }
-
- mLog.log(String.format(
- "OBSERVED LinkProperties update iface=%s state=%s lp=%s",
- iface, IpServer.getStateString(state), newLp));
- final int which = TetherMainSM.EVENT_IFACE_UPDATE_LINKPROPERTIES;
- mTetherMainSM.sendMessage(which, state, 0, newLp);
- }
-
- private void maybeTrackNewInterfaceLocked(final String iface) {
- // If we don't care about this type of interface, ignore.
- final int interfaceType = ifaceNameToType(iface);
- if (interfaceType == TETHERING_INVALID) {
- mLog.log(iface + " is not a tetherable iface, ignoring");
- return;
- }
- maybeTrackNewInterfaceLocked(iface, interfaceType);
- }
-
- private void maybeTrackNewInterfaceLocked(final String iface, int interfaceType) {
- // If we have already started a TISM for this interface, skip.
- if (mTetherStates.containsKey(iface)) {
- mLog.log("active iface (" + iface + ") reported as added, ignoring");
- return;
- }
-
- mLog.log("adding TetheringInterfaceStateMachine for: " + iface);
- final TetherState tetherState = new TetherState(
- new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mBpfCoordinator,
- makeControlCallback(), mConfig.enableLegacyDhcpServer,
- mConfig.isBpfOffloadEnabled(), mPrivateAddressCoordinator,
- mDeps.getIpServerDependencies()));
- mTetherStates.put(iface, tetherState);
- tetherState.ipServer.start();
- }
-
- private void stopTrackingInterfaceLocked(final String iface) {
- final TetherState tetherState = mTetherStates.get(iface);
- if (tetherState == null) {
- mLog.log("attempting to remove unknown iface (" + iface + "), ignoring");
- return;
- }
- tetherState.ipServer.stop();
- mLog.log("removing TetheringInterfaceStateMachine for: " + iface);
- mTetherStates.remove(iface);
- }
-
- private static String[] copy(String[] strarray) {
- return Arrays.copyOf(strarray, strarray.length);
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
deleted file mode 100644
index 799637c9b1c58..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringConfiguration.java
+++ /dev/null
@@ -1,521 +0,0 @@
-/*
- * Copyright (C) 2017 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 static android.content.Context.TELEPHONY_SERVICE;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
-import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
-import static android.provider.DeviceConfig.NAMESPACE_CONNECTIVITY;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.net.TetheringConfigurationParcel;
-import android.net.util.SharedLog;
-import android.provider.DeviceConfig;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.text.TextUtils;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.StringJoiner;
-
-/**
- * A utility class to encapsulate the various tethering configuration elements.
- *
- * This configuration data includes elements describing upstream properties
- * (preferred and required types of upstream connectivity as well as default
- * DNS servers to use if none are available) and downstream properties (such
- * as regular expressions use to match suitable downstream interfaces and the
- * DHCPv4 ranges to use).
- *
- * @hide
- */
-public class TetheringConfiguration {
- private static final String TAG = TetheringConfiguration.class.getSimpleName();
-
- private static final String[] EMPTY_STRING_ARRAY = new String[0];
-
- // Default ranges used for the legacy DHCP server.
- // USB is 192.168.42.1 and 255.255.255.0
- // Wifi is 192.168.43.1 and 255.255.255.0
- // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
- // with 255.255.255.0
- // P2P is 192.168.49.1 and 255.255.255.0
- private static final String[] LEGACY_DHCP_DEFAULT_RANGE = {
- "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254",
- "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254",
- "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254",
- "192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254",
- };
-
- private static final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"};
-
- /**
- * Override enabling BPF offload configuration for tethering.
- */
- public static final String OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD =
- "override_tether_enable_bpf_offload";
-
- /**
- * Use the old dnsmasq DHCP server for tethering instead of the framework implementation.
- */
- public static final String TETHER_ENABLE_LEGACY_DHCP_SERVER =
- "tether_enable_legacy_dhcp_server";
-
- public static final String USE_LEGACY_WIFI_P2P_DEDICATED_IP =
- "use_legacy_wifi_p2p_dedicated_ip";
-
- /**
- * Flag use to enable select all prefix ranges feature.
- * TODO: Remove this flag if there are no problems after M-2020-12 rolls out.
- */
- public static final String TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES =
- "tether_enable_select_all_prefix_ranges";
-
- /**
- * Default value that used to periodic polls tether offload stats from tethering offload HAL
- * to make the data warnings work.
- */
- public static final int DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS = 5000;
-
- public final String[] tetherableUsbRegexs;
- public final String[] tetherableWifiRegexs;
- public final String[] tetherableWigigRegexs;
- public final String[] tetherableWifiP2pRegexs;
- public final String[] tetherableBluetoothRegexs;
- public final String[] tetherableNcmRegexs;
- public final boolean isDunRequired;
- public final boolean chooseUpstreamAutomatically;
- public final Collection preferredUpstreamIfaceTypes;
- public final String[] legacyDhcpRanges;
- public final String[] defaultIPv4DNS;
- public final boolean enableLegacyDhcpServer;
-
- public final String[] provisioningApp;
- public final String provisioningAppNoUi;
- public final int provisioningCheckPeriod;
- public final String provisioningResponse;
-
- public final int activeDataSubId;
-
- private final int mOffloadPollInterval;
- // TODO: Add to TetheringConfigurationParcel if required.
- private final boolean mEnableBpfOffload;
- private final boolean mEnableWifiP2pDedicatedIp;
-
- private final boolean mEnableSelectAllPrefixRange;
-
- public TetheringConfiguration(Context ctx, SharedLog log, int id) {
- final SharedLog configLog = log.forSubComponent("config");
-
- activeDataSubId = id;
- Resources res = getResources(ctx, activeDataSubId);
-
- tetherableUsbRegexs = getResourceStringArray(res, R.array.config_tether_usb_regexs);
- tetherableNcmRegexs = getResourceStringArray(res, R.array.config_tether_ncm_regexs);
- // TODO: Evaluate deleting this altogether now that Wi-Fi always passes
- // us an interface name. Careful consideration needs to be given to
- // implications for Settings and for provisioning checks.
- tetherableWifiRegexs = getResourceStringArray(res, R.array.config_tether_wifi_regexs);
- tetherableWigigRegexs = getResourceStringArray(res, R.array.config_tether_wigig_regexs);
- tetherableWifiP2pRegexs = getResourceStringArray(
- res, R.array.config_tether_wifi_p2p_regexs);
- tetherableBluetoothRegexs = getResourceStringArray(
- res, R.array.config_tether_bluetooth_regexs);
-
- isDunRequired = checkDunRequired(ctx);
-
- chooseUpstreamAutomatically = getResourceBoolean(
- res, R.bool.config_tether_upstream_automatic, false /** defaultValue */);
- preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(res, isDunRequired);
-
- legacyDhcpRanges = getLegacyDhcpRanges(res);
- defaultIPv4DNS = copy(DEFAULT_IPV4_DNS);
- mEnableBpfOffload = getEnableBpfOffload(res);
- enableLegacyDhcpServer = getEnableLegacyDhcpServer(res);
-
- provisioningApp = getResourceStringArray(res, R.array.config_mobile_hotspot_provision_app);
- provisioningAppNoUi = getResourceString(res,
- R.string.config_mobile_hotspot_provision_app_no_ui);
- provisioningCheckPeriod = getResourceInteger(res,
- R.integer.config_mobile_hotspot_provision_check_period,
- 0 /* No periodic re-check */);
- provisioningResponse = getResourceString(res,
- R.string.config_mobile_hotspot_provision_response);
-
- mOffloadPollInterval = getResourceInteger(res,
- R.integer.config_tether_offload_poll_interval,
- DEFAULT_TETHER_OFFLOAD_POLL_INTERVAL_MS);
-
- mEnableWifiP2pDedicatedIp = getResourceBoolean(res,
- R.bool.config_tether_enable_legacy_wifi_p2p_dedicated_ip,
- false /* defaultValue */);
-
- // Flags should normally not be booleans, but this is a kill-switch flag that is only used
- // to turn off the feature, so binary rollback problems do not apply.
- mEnableSelectAllPrefixRange = getDeviceConfigBoolean(
- TETHER_ENABLE_SELECT_ALL_PREFIX_RANGES, true /* defaultValue */);
-
- configLog.log(toString());
- }
-
- /** Check whether input interface belong to usb.*/
- public boolean isUsb(String iface) {
- return matchesDownstreamRegexs(iface, tetherableUsbRegexs);
- }
-
- /** Check whether input interface belong to wifi.*/
- public boolean isWifi(String iface) {
- return matchesDownstreamRegexs(iface, tetherableWifiRegexs);
- }
-
- /** Check whether input interface belong to wigig.*/
- public boolean isWigig(String iface) {
- return matchesDownstreamRegexs(iface, tetherableWigigRegexs);
- }
-
- /** Check whether this interface is Wifi P2P interface. */
- public boolean isWifiP2p(String iface) {
- return matchesDownstreamRegexs(iface, tetherableWifiP2pRegexs);
- }
-
- /** Check whether using legacy mode for wifi P2P. */
- public boolean isWifiP2pLegacyTetheringMode() {
- return (tetherableWifiP2pRegexs == null || tetherableWifiP2pRegexs.length == 0);
- }
-
- /** Check whether input interface belong to bluetooth.*/
- public boolean isBluetooth(String iface) {
- return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs);
- }
-
- /** Check if interface is ncm */
- public boolean isNcm(String iface) {
- return matchesDownstreamRegexs(iface, tetherableNcmRegexs);
- }
-
- /** Check whether no ui entitlement application is available.*/
- public boolean hasMobileHotspotProvisionApp() {
- return !TextUtils.isEmpty(provisioningAppNoUi);
- }
-
- /** Check whether dedicated wifi p2p address is enabled. */
- public boolean shouldEnableWifiP2pDedicatedIp() {
- return mEnableWifiP2pDedicatedIp;
- }
-
- /** Does the dumping.*/
- public void dump(PrintWriter pw) {
- pw.print("activeDataSubId: ");
- pw.println(activeDataSubId);
-
- dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs);
- dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
- dumpStringArray(pw, "tetherableWifiP2pRegexs", tetherableWifiP2pRegexs);
- dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
- dumpStringArray(pw, "tetherableNcmRegexs", tetherableNcmRegexs);
-
- pw.print("isDunRequired: ");
- pw.println(isDunRequired);
-
- pw.print("chooseUpstreamAutomatically: ");
- pw.println(chooseUpstreamAutomatically);
- pw.print("legacyPreredUpstreamIfaceTypes: ");
- pw.println(Arrays.toString(toIntArray(preferredUpstreamIfaceTypes)));
-
- dumpStringArray(pw, "legacyDhcpRanges", legacyDhcpRanges);
- dumpStringArray(pw, "defaultIPv4DNS", defaultIPv4DNS);
-
- pw.print("offloadPollInterval: ");
- pw.println(mOffloadPollInterval);
-
- dumpStringArray(pw, "provisioningApp", provisioningApp);
- pw.print("provisioningAppNoUi: ");
- pw.println(provisioningAppNoUi);
-
- pw.print("enableBpfOffload: ");
- pw.println(mEnableBpfOffload);
-
- pw.print("enableLegacyDhcpServer: ");
- pw.println(enableLegacyDhcpServer);
-
- pw.print("enableWifiP2pDedicatedIp: ");
- pw.println(mEnableWifiP2pDedicatedIp);
-
- pw.print("mEnableSelectAllPrefixRange: ");
- pw.println(mEnableSelectAllPrefixRange);
- }
-
- /** Returns the string representation of this object.*/
- public String toString() {
- final StringJoiner sj = new StringJoiner(" ");
- sj.add(String.format("activeDataSubId:%d", activeDataSubId));
- sj.add(String.format("tetherableUsbRegexs:%s", makeString(tetherableUsbRegexs)));
- sj.add(String.format("tetherableWifiRegexs:%s", makeString(tetherableWifiRegexs)));
- sj.add(String.format("tetherableWifiP2pRegexs:%s", makeString(tetherableWifiP2pRegexs)));
- sj.add(String.format("tetherableBluetoothRegexs:%s",
- makeString(tetherableBluetoothRegexs)));
- sj.add(String.format("isDunRequired:%s", isDunRequired));
- sj.add(String.format("chooseUpstreamAutomatically:%s", chooseUpstreamAutomatically));
- sj.add(String.format("offloadPollInterval:%d", mOffloadPollInterval));
- sj.add(String.format("preferredUpstreamIfaceTypes:%s",
- toIntArray(preferredUpstreamIfaceTypes)));
- sj.add(String.format("provisioningApp:%s", makeString(provisioningApp)));
- sj.add(String.format("provisioningAppNoUi:%s", provisioningAppNoUi));
- sj.add(String.format("enableBpfOffload:%s", mEnableBpfOffload));
- sj.add(String.format("enableLegacyDhcpServer:%s", enableLegacyDhcpServer));
- return String.format("TetheringConfiguration{%s}", sj.toString());
- }
-
- private static void dumpStringArray(PrintWriter pw, String label, String[] values) {
- pw.print(label);
- pw.print(": ");
-
- if (values != null) {
- final StringJoiner sj = new StringJoiner(", ", "[", "]");
- for (String value : values) sj.add(value);
- pw.print(sj.toString());
- } else {
- pw.print("null");
- }
-
- pw.println();
- }
-
- private static String makeString(String[] strings) {
- if (strings == null) return "null";
- final StringJoiner sj = new StringJoiner(",", "[", "]");
- for (String s : strings) sj.add(s);
- return sj.toString();
- }
-
- /** Check whether dun is required. */
- public static boolean checkDunRequired(Context ctx) {
- final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE);
- // TelephonyManager would uses the active data subscription, which should be the one used
- // by tethering.
- return (tm != null) ? tm.isTetheringApnRequired() : false;
- }
-
- public int getOffloadPollInterval() {
- return mOffloadPollInterval;
- }
-
- public boolean isBpfOffloadEnabled() {
- return mEnableBpfOffload;
- }
-
- public boolean isSelectAllPrefixRangeEnabled() {
- return mEnableSelectAllPrefixRange;
- }
-
- private static Collection getUpstreamIfaceTypes(Resources res, boolean dunRequired) {
- final int[] ifaceTypes = res.getIntArray(R.array.config_tether_upstream_types);
- final ArrayList upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length);
- for (int i : ifaceTypes) {
- switch (i) {
- case TYPE_MOBILE:
- case TYPE_MOBILE_HIPRI:
- if (dunRequired) continue;
- break;
- case TYPE_MOBILE_DUN:
- if (!dunRequired) continue;
- break;
- }
- upstreamIfaceTypes.add(i);
- }
-
- // Fix up upstream interface types for DUN or mobile. NOTE: independent
- // of the value of |dunRequired|, cell data of one form or another is
- // *always* an upstream, regardless of the upstream interface types
- // specified by configuration resources.
- if (dunRequired) {
- appendIfNotPresent(upstreamIfaceTypes, TYPE_MOBILE_DUN);
- } else {
- // Do not modify if a cellular interface type is already present in the
- // upstream interface types. Add TYPE_MOBILE and TYPE_MOBILE_HIPRI if no
- // cellular interface types are found in the upstream interface types.
- // This preserves backwards compatibility and prevents the DUN and default
- // mobile types incorrectly appearing together, which could happen on
- // previous releases in the common case where checkDunRequired returned
- // DUN_UNSPECIFIED.
- if (!containsOneOf(upstreamIfaceTypes, TYPE_MOBILE, TYPE_MOBILE_HIPRI)) {
- upstreamIfaceTypes.add(TYPE_MOBILE);
- upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI);
- }
- }
-
- // Always make sure our good friend Ethernet is present.
- // TODO: consider unilaterally forcing this at the front.
- prependIfNotPresent(upstreamIfaceTypes, TYPE_ETHERNET);
-
- return upstreamIfaceTypes;
- }
-
- private static boolean matchesDownstreamRegexs(String iface, String[] regexs) {
- for (String regex : regexs) {
- if (iface.matches(regex)) return true;
- }
- return false;
- }
-
- private static String[] getLegacyDhcpRanges(Resources res) {
- final String[] fromResource = getResourceStringArray(res, R.array.config_tether_dhcp_range);
- if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) {
- return fromResource;
- }
- return copy(LEGACY_DHCP_DEFAULT_RANGE);
- }
-
- private static String getResourceString(Resources res, final int resId) {
- try {
- return res.getString(resId);
- } catch (Resources.NotFoundException e) {
- return "";
- }
- }
-
- private static boolean getResourceBoolean(Resources res, int resId, boolean defaultValue) {
- try {
- return res.getBoolean(resId);
- } catch (Resources.NotFoundException e404) {
- return defaultValue;
- }
- }
-
- private static String[] getResourceStringArray(Resources res, int resId) {
- try {
- final String[] strArray = res.getStringArray(resId);
- return (strArray != null) ? strArray : EMPTY_STRING_ARRAY;
- } catch (Resources.NotFoundException e404) {
- return EMPTY_STRING_ARRAY;
- }
- }
-
- private static int getResourceInteger(Resources res, int resId, int defaultValue) {
- try {
- return res.getInteger(resId);
- } catch (Resources.NotFoundException e404) {
- return defaultValue;
- }
- }
-
- private boolean getEnableBpfOffload(final Resources res) {
- // Get BPF offload config
- // Priority 1: Device config
- // Priority 2: Resource config
- // Priority 3: Default value
- final boolean defaultValue = getResourceBoolean(
- res, R.bool.config_tether_enable_bpf_offload, true /** default value */);
-
- return getDeviceConfigBoolean(OVERRIDE_TETHER_ENABLE_BPF_OFFLOAD, defaultValue);
- }
-
- private boolean getEnableLegacyDhcpServer(final Resources res) {
- return getResourceBoolean(
- res, R.bool.config_tether_enable_legacy_dhcp_server, false /** defaultValue */)
- || getDeviceConfigBoolean(
- TETHER_ENABLE_LEGACY_DHCP_SERVER, false /** defaultValue */);
- }
-
- private boolean getDeviceConfigBoolean(final String name, final boolean defaultValue) {
- // Due to the limitation of static mock for testing, using #getDeviceConfigProperty instead
- // of DeviceConfig#getBoolean. If using #getBoolean here, the test can't know that the
- // returned boolean value comes from device config or default value (because of null
- // property string). See the test case testBpfOffload{*} in TetheringConfigurationTest.java.
- final String value = getDeviceConfigProperty(name);
- return value != null ? Boolean.parseBoolean(value) : defaultValue;
- }
-
- @VisibleForTesting
- protected String getDeviceConfigProperty(String name) {
- return DeviceConfig.getProperty(NAMESPACE_CONNECTIVITY, name);
- }
-
- private Resources getResources(Context ctx, int subId) {
- if (subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
- return getResourcesForSubIdWrapper(ctx, subId);
- } else {
- return ctx.getResources();
- }
- }
-
- @VisibleForTesting
- protected Resources getResourcesForSubIdWrapper(Context ctx, int subId) {
- return SubscriptionManager.getResourcesForSubId(ctx, subId);
- }
-
- private static String[] copy(String[] strarray) {
- return Arrays.copyOf(strarray, strarray.length);
- }
-
- private static void prependIfNotPresent(ArrayList list, int value) {
- if (list.contains(value)) return;
- list.add(0, value);
- }
-
- private static void appendIfNotPresent(ArrayList list, int value) {
- if (list.contains(value)) return;
- list.add(value);
- }
-
- private static boolean containsOneOf(ArrayList list, Integer... values) {
- for (Integer value : values) {
- if (list.contains(value)) return true;
- }
- return false;
- }
-
- private static int[] toIntArray(Collection values) {
- final int[] result = new int[values.size()];
- int index = 0;
- for (Integer value : values) {
- result[index++] = value;
- }
- return result;
- }
-
- /**
- * Convert this TetheringConfiguration to a TetheringConfigurationParcel.
- */
- public TetheringConfigurationParcel toStableParcelable() {
- final TetheringConfigurationParcel parcel = new TetheringConfigurationParcel();
- parcel.subId = activeDataSubId;
- parcel.tetherableUsbRegexs = tetherableUsbRegexs;
- parcel.tetherableWifiRegexs = tetherableWifiRegexs;
- parcel.tetherableBluetoothRegexs = tetherableBluetoothRegexs;
- parcel.isDunRequired = isDunRequired;
- parcel.chooseUpstreamAutomatically = chooseUpstreamAutomatically;
-
- parcel.preferredUpstreamIfaceTypes = toIntArray(preferredUpstreamIfaceTypes);
-
- parcel.legacyDhcpRanges = legacyDhcpRanges;
- parcel.defaultIPv4DNS = defaultIPv4DNS;
- parcel.enableLegacyDhcpServer = enableLegacyDhcpServer;
- parcel.provisioningApp = provisioningApp;
- parcel.provisioningAppNoUi = provisioningAppNoUi;
- parcel.provisioningCheckPeriod = provisioningCheckPeriod;
- return parcel;
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
deleted file mode 100644
index 45b914178e977..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * Copyright (C) 2017 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 android.app.usage.NetworkStatsManager;
-import android.bluetooth.BluetoothAdapter;
-import android.content.Context;
-import android.net.INetd;
-import android.net.NetworkRequest;
-import android.net.ip.IpServer;
-import android.net.util.SharedLog;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.SystemProperties;
-import android.text.TextUtils;
-
-import androidx.annotation.NonNull;
-
-import com.android.internal.util.StateMachine;
-
-import java.util.ArrayList;
-
-
-/**
- * Capture tethering dependencies, for injection.
- *
- * @hide
- */
-public abstract class TetheringDependencies {
- /**
- * Get a reference to the BpfCoordinator to be used by tethering.
- */
- public @NonNull BpfCoordinator getBpfCoordinator(
- @NonNull BpfCoordinator.Dependencies deps) {
- return new BpfCoordinator(deps);
- }
-
- /**
- * Get a reference to the offload hardware interface to be used by tethering.
- */
- public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) {
- return new OffloadHardwareInterface(h, log);
- }
-
- /**
- * Get a reference to the offload controller to be used by tethering.
- */
- @NonNull
- public OffloadController getOffloadController(@NonNull Handler h,
- @NonNull SharedLog log, @NonNull OffloadController.Dependencies deps) {
- final NetworkStatsManager statsManager =
- (NetworkStatsManager) getContext().getSystemService(Context.NETWORK_STATS_SERVICE);
- return new OffloadController(h, getOffloadHardwareInterface(h, log),
- getContext().getContentResolver(), statsManager, log, deps);
- }
-
-
- /**
- * Get a reference to the UpstreamNetworkMonitor to be used by tethering.
- */
- public UpstreamNetworkMonitor getUpstreamNetworkMonitor(Context ctx, StateMachine target,
- SharedLog log, int what) {
- return new UpstreamNetworkMonitor(ctx, target, log, what);
- }
-
- /**
- * Get a reference to the IPv6TetheringCoordinator to be used by tethering.
- */
- public IPv6TetheringCoordinator getIPv6TetheringCoordinator(
- ArrayList notifyList, SharedLog log) {
- return new IPv6TetheringCoordinator(notifyList, log);
- }
-
- /**
- * Get dependencies to be used by IpServer.
- */
- public abstract IpServer.Dependencies getIpServerDependencies();
-
- /**
- * Indicates whether tethering is supported on the device.
- */
- public boolean isTetheringSupported() {
- return true;
- }
-
- /**
- * Get the NetworkRequest that should be fulfilled by the default network.
- */
- public abstract NetworkRequest getDefaultNetworkRequest();
-
- /**
- * Get a reference to the EntitlementManager to be used by tethering.
- */
- public EntitlementManager getEntitlementManager(Context ctx, Handler h, SharedLog log,
- Runnable callback) {
- return new EntitlementManager(ctx, h, log, callback);
- }
-
- /**
- * Generate a new TetheringConfiguration according to input sub Id.
- */
- public TetheringConfiguration generateTetheringConfiguration(Context ctx, SharedLog log,
- int subId) {
- return new TetheringConfiguration(ctx, log, subId);
- }
-
- /**
- * Get a reference to INetd to be used by tethering.
- */
- public INetd getINetd(Context context) {
- return INetd.Stub.asInterface(
- (IBinder) context.getSystemService(Context.NETD_SERVICE));
- }
-
- /**
- * Get a reference to the TetheringNotificationUpdater to be used by tethering.
- */
- public TetheringNotificationUpdater getNotificationUpdater(@NonNull final Context ctx,
- @NonNull final Looper looper) {
- return new TetheringNotificationUpdater(ctx, looper);
- }
-
- /**
- * Get tethering thread looper.
- */
- public abstract Looper getTetheringLooper();
-
- /**
- * Get Context of TetheringSerice.
- */
- public abstract Context getContext();
-
- /**
- * Get a reference to BluetoothAdapter to be used by tethering.
- */
- public abstract BluetoothAdapter getBluetoothAdapter();
-
- /**
- * Get SystemProperties which indicate whether tethering is denied.
- */
- public boolean isTetheringDenied() {
- return TextUtils.equals(SystemProperties.get("ro.tether.denied"), "true");
- }
-
- /**
- * Get a reference to PrivateAddressCoordinator to be used by Tethering.
- */
- public PrivateAddressCoordinator getPrivateAddressCoordinator(Context ctx,
- TetheringConfiguration cfg) {
- return new PrivateAddressCoordinator(ctx, cfg);
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringInterfaceUtils.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringInterfaceUtils.java
deleted file mode 100644
index ff38f717a121e..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringInterfaceUtils.java
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2018 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 android.annotation.Nullable;
-import android.net.LinkProperties;
-import android.net.NetworkCapabilities;
-import android.net.RouteInfo;
-import android.net.util.InterfaceSet;
-
-import com.android.net.module.util.NetUtils;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-
-/**
- * @hide
- */
-public final class TetheringInterfaceUtils {
- private static final InetAddress IN6ADDR_ANY = getByAddress(
- new byte[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0});
- private static final InetAddress INADDR_ANY = getByAddress(new byte[] {0, 0, 0, 0});
-
- /**
- * Get upstream interfaces for tethering based on default routes for IPv4/IPv6.
- * @return null if there is no usable interface, or a set of at least one interface otherwise.
- */
- public static @Nullable InterfaceSet getTetheringInterfaces(UpstreamNetworkState ns) {
- if (ns == null) {
- return null;
- }
-
- final LinkProperties lp = ns.linkProperties;
- final String if4 = getInterfaceForDestination(lp, INADDR_ANY);
- final String if6 = getIPv6Interface(ns);
-
- return (if4 == null && if6 == null) ? null : new InterfaceSet(if4, if6);
- }
-
- /**
- * Get the upstream interface for IPv6 tethering.
- * @return null if there is no usable interface, or the interface name otherwise.
- */
- public static @Nullable String getIPv6Interface(UpstreamNetworkState ns) {
- // Broadly speaking:
- //
- // [1] does the upstream have an IPv6 default route?
- //
- // and
- //
- // [2] does the upstream have one or more global IPv6 /64s
- // dedicated to this device?
- //
- // In lieu of Prefix Delegation and other evaluation of whether a
- // prefix may or may not be dedicated to this device, for now just
- // check whether the upstream is TRANSPORT_CELLULAR. This works
- // because "[t]he 3GPP network allocates each default bearer a unique
- // /64 prefix", per RFC 6459, Section 5.2.
- final boolean canTether =
- (ns != null) && (ns.network != null)
- && (ns.linkProperties != null) && (ns.networkCapabilities != null)
- // At least one upstream DNS server:
- && ns.linkProperties.hasIpv6DnsServer()
- // Minimal amount of IPv6 provisioning:
- && ns.linkProperties.hasGlobalIpv6Address()
- // Temporary approximation of "dedicated prefix":
- && ns.networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR);
-
- return canTether
- ? getInterfaceForDestination(ns.linkProperties, IN6ADDR_ANY)
- : null;
- }
-
- private static String getInterfaceForDestination(LinkProperties lp, InetAddress dst) {
- final RouteInfo ri = (lp != null)
- ? NetUtils.selectBestRoute(lp.getAllRoutes(), dst)
- : null;
- return (ri != null) ? ri.getInterface() : null;
- }
-
- private static InetAddress getByAddress(final byte[] addr) {
- try {
- return InetAddress.getByAddress(null, addr);
- } catch (UnknownHostException e) {
- throw new AssertionError("illegal address length" + addr.length);
- }
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
deleted file mode 100644
index a0198cc9c1268..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringNotificationUpdater.java
+++ /dev/null
@@ -1,362 +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 static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
-import static android.text.TextUtils.isEmpty;
-
-import android.app.Notification;
-import android.app.Notification.Action;
-import android.app.NotificationChannel;
-import android.app.NotificationManager;
-import android.app.PendingIntent;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
-import android.content.res.Resources;
-import android.net.NetworkCapabilities;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.telephony.SubscriptionManager;
-import android.telephony.TelephonyManager;
-import android.util.SparseArray;
-
-import androidx.annotation.DrawableRes;
-import androidx.annotation.IntDef;
-import androidx.annotation.IntRange;
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * A class to display tethering-related notifications.
- *
- *
This class is not thread safe, it is intended to be used only from the tethering handler
- * thread. However the constructor is an exception, as it is called on another thread ;
- * therefore for thread safety all members of this class MUST either be final or initialized
- * to their default value (0, false or null).
- *
- * @hide
- */
-public class TetheringNotificationUpdater {
- private static final String TAG = TetheringNotificationUpdater.class.getSimpleName();
- private static final String CHANNEL_ID = "TETHERING_STATUS";
- private static final String WIFI_DOWNSTREAM = "WIFI";
- private static final String USB_DOWNSTREAM = "USB";
- private static final String BLUETOOTH_DOWNSTREAM = "BT";
- @VisibleForTesting
- static final String ACTION_DISABLE_TETHERING =
- "com.android.server.connectivity.tethering.DISABLE_TETHERING";
- private static final boolean NOTIFY_DONE = true;
- private static final boolean NO_NOTIFY = false;
- @VisibleForTesting
- static final int EVENT_SHOW_NO_UPSTREAM = 1;
- // Id to update and cancel restricted notification. Must be unique within the tethering app.
- @VisibleForTesting
- static final int RESTRICTED_NOTIFICATION_ID = 1001;
- // Id to update and cancel no upstream notification. Must be unique within the tethering app.
- @VisibleForTesting
- static final int NO_UPSTREAM_NOTIFICATION_ID = 1002;
- // Id to update and cancel roaming notification. Must be unique within the tethering app.
- @VisibleForTesting
- static final int ROAMING_NOTIFICATION_ID = 1003;
- @VisibleForTesting
- static final int NO_ICON_ID = 0;
- @VisibleForTesting
- static final int DOWNSTREAM_NONE = 0;
- // Refer to TelephonyManager#getSimCarrierId for more details about carrier id.
- @VisibleForTesting
- static final int VERIZON_CARRIER_ID = 1839;
- private final Context mContext;
- private final NotificationManager mNotificationManager;
- private final NotificationChannel mChannel;
- private final Handler mHandler;
-
- // WARNING : the constructor is called on a different thread. Thread safety therefore
- // relies on these values being initialized to 0, false or null, and not any other value. If you
- // need to change this, you will need to change the thread where the constructor is invoked, or
- // to introduce synchronization.
- // Downstream type is one of ConnectivityManager.TETHERING_* constants, 0 1 or 2.
- // This value has to be made 1 2 and 4, and OR'd with the others.
- private int mDownstreamTypesMask = DOWNSTREAM_NONE;
- private boolean mNoUpstream = false;
- private boolean mRoaming = false;
-
- // WARNING : this value is not able to being initialized to 0 and must have volatile because
- // telephony service is not guaranteed that is up before tethering service starts. If telephony
- // is up later than tethering, TetheringNotificationUpdater will use incorrect and valid
- // subscription id(0) to query resources. Therefore, initialized subscription id must be
- // INVALID_SUBSCRIPTION_ID.
- private volatile int mActiveDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {
- RESTRICTED_NOTIFICATION_ID,
- NO_UPSTREAM_NOTIFICATION_ID,
- ROAMING_NOTIFICATION_ID
- })
- @interface NotificationId {}
-
- private static final class MccMncOverrideInfo {
- public final String visitedMccMnc;
- public final int homeMcc;
- public final int homeMnc;
- MccMncOverrideInfo(String visitedMccMnc, int mcc, int mnc) {
- this.visitedMccMnc = visitedMccMnc;
- this.homeMcc = mcc;
- this.homeMnc = mnc;
- }
- }
-
- private static final SparseArray sCarrierIdToMccMnc = new SparseArray<>();
-
- static {
- sCarrierIdToMccMnc.put(VERIZON_CARRIER_ID, new MccMncOverrideInfo("20404", 311, 480));
- }
-
- public TetheringNotificationUpdater(@NonNull final Context context,
- @NonNull final Looper looper) {
- mContext = context;
- mNotificationManager = (NotificationManager) context.createContextAsUser(UserHandle.ALL, 0)
- .getSystemService(Context.NOTIFICATION_SERVICE);
- mChannel = new NotificationChannel(
- CHANNEL_ID,
- context.getResources().getString(R.string.notification_channel_tethering_status),
- NotificationManager.IMPORTANCE_LOW);
- mNotificationManager.createNotificationChannel(mChannel);
- mHandler = new NotificationHandler(looper);
- }
-
- private class NotificationHandler extends Handler {
- NotificationHandler(Looper looper) {
- super(looper);
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch(msg.what) {
- case EVENT_SHOW_NO_UPSTREAM:
- notifyTetheringNoUpstream();
- break;
- }
- }
- }
-
- /** Called when downstream has changed */
- public void onDownstreamChanged(@IntRange(from = 0, to = 7) final int downstreamTypesMask) {
- updateActiveNotifications(
- mActiveDataSubId, downstreamTypesMask, mNoUpstream, mRoaming);
- }
-
- /** Called when active data subscription id changed */
- public void onActiveDataSubscriptionIdChanged(final int subId) {
- updateActiveNotifications(subId, mDownstreamTypesMask, mNoUpstream, mRoaming);
- }
-
- /** Called when upstream network capabilities changed */
- public void onUpstreamCapabilitiesChanged(@Nullable final NetworkCapabilities capabilities) {
- final boolean isNoUpstream = (capabilities == null);
- final boolean isRoaming = capabilities != null
- && !capabilities.hasCapability(NET_CAPABILITY_NOT_ROAMING);
- updateActiveNotifications(
- mActiveDataSubId, mDownstreamTypesMask, isNoUpstream, isRoaming);
- }
-
- @NonNull
- @VisibleForTesting
- final Handler getHandler() {
- return mHandler;
- }
-
- @NonNull
- @VisibleForTesting
- Resources getResourcesForSubId(@NonNull final Context context, final int subId) {
- final Resources res = SubscriptionManager.getResourcesForSubId(context, subId);
- final TelephonyManager tm =
- ((TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE))
- .createForSubscriptionId(mActiveDataSubId);
- final int carrierId = tm.getSimCarrierId();
- final String mccmnc = tm.getSimOperator();
- final MccMncOverrideInfo overrideInfo = sCarrierIdToMccMnc.get(carrierId);
- if (overrideInfo != null && overrideInfo.visitedMccMnc.equals(mccmnc)) {
- // Re-configure MCC/MNC value to specific carrier to get right resources.
- final Configuration config = res.getConfiguration();
- config.mcc = overrideInfo.homeMcc;
- config.mnc = overrideInfo.homeMnc;
- return context.createConfigurationContext(config).getResources();
- }
- return res;
- }
-
- private void updateActiveNotifications(final int subId, final int downstreamTypes,
- final boolean noUpstream, final boolean isRoaming) {
- final boolean tetheringActiveChanged =
- (downstreamTypes == DOWNSTREAM_NONE) != (mDownstreamTypesMask == DOWNSTREAM_NONE);
- final boolean subIdChanged = subId != mActiveDataSubId;
- final boolean upstreamChanged = noUpstream != mNoUpstream;
- final boolean roamingChanged = isRoaming != mRoaming;
- final boolean updateAll = tetheringActiveChanged || subIdChanged;
- mActiveDataSubId = subId;
- mDownstreamTypesMask = downstreamTypes;
- mNoUpstream = noUpstream;
- mRoaming = isRoaming;
-
- if (updateAll || upstreamChanged) updateNoUpstreamNotification();
- if (updateAll || roamingChanged) updateRoamingNotification();
- }
-
- private void updateNoUpstreamNotification() {
- final boolean tetheringInactive = mDownstreamTypesMask == DOWNSTREAM_NONE;
-
- if (tetheringInactive || !mNoUpstream || setupNoUpstreamNotification() == NO_NOTIFY) {
- clearNotification(NO_UPSTREAM_NOTIFICATION_ID);
- mHandler.removeMessages(EVENT_SHOW_NO_UPSTREAM);
- }
- }
-
- private void updateRoamingNotification() {
- final boolean tetheringInactive = mDownstreamTypesMask == DOWNSTREAM_NONE;
-
- if (tetheringInactive || !mRoaming || setupRoamingNotification() == NO_NOTIFY) {
- clearNotification(ROAMING_NOTIFICATION_ID);
- }
- }
-
- @VisibleForTesting
- void tetheringRestrictionLifted() {
- clearNotification(RESTRICTED_NOTIFICATION_ID);
- }
-
- private void clearNotification(@NotificationId final int id) {
- mNotificationManager.cancel(null /* tag */, id);
- }
-
- @VisibleForTesting
- static String getSettingsPackageName(@NonNull final PackageManager pm) {
- final Intent settingsIntent = new Intent(Settings.ACTION_SETTINGS);
- final ComponentName settingsComponent = settingsIntent.resolveActivity(pm);
- return settingsComponent != null
- ? settingsComponent.getPackageName() : "com.android.settings";
- }
-
- @VisibleForTesting
- void notifyTetheringDisabledByRestriction() {
- final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
- final String title = res.getString(R.string.disable_tether_notification_title);
- final String message = res.getString(R.string.disable_tether_notification_message);
- if (isEmpty(title) || isEmpty(message)) return;
-
- final PendingIntent pi = PendingIntent.getActivity(
- mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
- 0 /* requestCode */,
- new Intent(Settings.ACTION_TETHER_SETTINGS)
- .setPackage(getSettingsPackageName(mContext.getPackageManager()))
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
- PendingIntent.FLAG_IMMUTABLE,
- null /* options */);
-
- showNotification(R.drawable.stat_sys_tether_general, title, message,
- RESTRICTED_NOTIFICATION_ID, false /* ongoing */, pi, new Action[0]);
- }
-
- private void notifyTetheringNoUpstream() {
- final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
- final String title = res.getString(R.string.no_upstream_notification_title);
- final String message = res.getString(R.string.no_upstream_notification_message);
- final String disableButton =
- res.getString(R.string.no_upstream_notification_disable_button);
- if (isEmpty(title) || isEmpty(message) || isEmpty(disableButton)) return;
-
- final Intent intent = new Intent(ACTION_DISABLE_TETHERING);
- intent.setPackage(mContext.getPackageName());
- final PendingIntent pi = PendingIntent.getBroadcast(
- mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
- 0 /* requestCode */,
- intent,
- PendingIntent.FLAG_IMMUTABLE);
- final Action action = new Action.Builder(NO_ICON_ID, disableButton, pi).build();
-
- showNotification(R.drawable.stat_sys_tether_general, title, message,
- NO_UPSTREAM_NOTIFICATION_ID, true /* ongoing */, null /* pendingIntent */, action);
- }
-
- private boolean setupRoamingNotification() {
- final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
- final boolean upstreamRoamingNotification =
- res.getBoolean(R.bool.config_upstream_roaming_notification);
-
- if (!upstreamRoamingNotification) return NO_NOTIFY;
-
- final String title = res.getString(R.string.upstream_roaming_notification_title);
- final String message = res.getString(R.string.upstream_roaming_notification_message);
- if (isEmpty(title) || isEmpty(message)) return NO_NOTIFY;
-
- final PendingIntent pi = PendingIntent.getActivity(
- mContext.createContextAsUser(UserHandle.CURRENT, 0 /* flags */),
- 0 /* requestCode */,
- new Intent(Settings.ACTION_TETHER_SETTINGS)
- .setPackage(getSettingsPackageName(mContext.getPackageManager()))
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),
- PendingIntent.FLAG_IMMUTABLE,
- null /* options */);
-
- showNotification(R.drawable.stat_sys_tether_general, title, message,
- ROAMING_NOTIFICATION_ID, true /* ongoing */, pi, new Action[0]);
- return NOTIFY_DONE;
- }
-
- private boolean setupNoUpstreamNotification() {
- final Resources res = getResourcesForSubId(mContext, mActiveDataSubId);
- final int delayToShowUpstreamNotification =
- res.getInteger(R.integer.delay_to_show_no_upstream_after_no_backhaul);
-
- if (delayToShowUpstreamNotification < 0) return NO_NOTIFY;
-
- mHandler.sendMessageDelayed(mHandler.obtainMessage(EVENT_SHOW_NO_UPSTREAM),
- delayToShowUpstreamNotification);
- return NOTIFY_DONE;
- }
-
- private void showNotification(@DrawableRes final int iconId, @NonNull final String title,
- @NonNull final String message, @NotificationId final int id, final boolean ongoing,
- @Nullable PendingIntent pi, @NonNull final Action... actions) {
- final Notification notification =
- new Notification.Builder(mContext, mChannel.getId())
- .setSmallIcon(iconId)
- .setContentTitle(title)
- .setContentText(message)
- .setOngoing(ongoing)
- .setColor(mContext.getColor(
- android.R.color.system_notification_accent_color))
- .setVisibility(Notification.VISIBILITY_PUBLIC)
- .setCategory(Notification.CATEGORY_STATUS)
- .setContentIntent(pi)
- .setActions(actions)
- .build();
-
- mNotificationManager.notify(null /* tag */, id, notification);
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
deleted file mode 100644
index 613328d1c1486..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringService.java
+++ /dev/null
@@ -1,389 +0,0 @@
-/*
- * Copyright (C) 2019 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 static android.Manifest.permission.ACCESS_NETWORK_STATE;
-import static android.Manifest.permission.NETWORK_STACK;
-import static android.Manifest.permission.TETHER_PRIVILEGED;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
-import static android.net.TetheringManager.TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION;
-import static android.net.TetheringManager.TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION;
-import static android.net.TetheringManager.TETHER_ERROR_NO_ERROR;
-import static android.net.TetheringManager.TETHER_ERROR_UNSUPPORTED;
-import static android.net.dhcp.IDhcpServer.STATUS_UNKNOWN_ERROR;
-
-import android.app.Service;
-import android.bluetooth.BluetoothAdapter;
-import android.content.Context;
-import android.content.Intent;
-import android.net.IIntResultListener;
-import android.net.INetworkStackConnector;
-import android.net.ITetheringConnector;
-import android.net.ITetheringEventCallback;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.net.NetworkStack;
-import android.net.TetheringRequestParcel;
-import android.net.dhcp.DhcpServerCallbacks;
-import android.net.dhcp.DhcpServingParamsParcel;
-import android.net.ip.IpServer;
-import android.os.Binder;
-import android.os.HandlerThread;
-import android.os.IBinder;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.os.ResultReceiver;
-import android.provider.Settings;
-import android.util.Log;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.internal.annotations.VisibleForTesting;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-
-/**
- * Android service used to manage tethering.
- *
- *
The service returns a binder for the system server to communicate with the tethering.
- */
-public class TetheringService extends Service {
- private static final String TAG = TetheringService.class.getSimpleName();
-
- private TetheringConnector mConnector;
-
- @Override
- public void onCreate() {
- final TetheringDependencies deps = makeTetheringDependencies();
- // The Tethering object needs a fully functional context to start, so this can't be done
- // in the constructor.
- mConnector = new TetheringConnector(makeTethering(deps), TetheringService.this);
- }
-
- /**
- * Make a reference to Tethering object.
- */
- @VisibleForTesting
- public Tethering makeTethering(TetheringDependencies deps) {
- System.loadLibrary("tetherutilsjni");
- return new Tethering(deps);
- }
-
- @NonNull
- @Override
- public IBinder onBind(Intent intent) {
- return mConnector;
- }
-
- private static class TetheringConnector extends ITetheringConnector.Stub {
- private final TetheringService mService;
- private final Tethering mTethering;
-
- TetheringConnector(Tethering tether, TetheringService service) {
- mTethering = tether;
- mService = service;
- }
-
- @Override
- public void tether(String iface, String callerPkg, String callingAttributionTag,
- IIntResultListener listener) {
- if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
-
- try {
- listener.onResult(mTethering.tether(iface));
- } catch (RemoteException e) { }
- }
-
- @Override
- public void untether(String iface, String callerPkg, String callingAttributionTag,
- IIntResultListener listener) {
- if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
-
- try {
- listener.onResult(mTethering.untether(iface));
- } catch (RemoteException e) { }
- }
-
- @Override
- public void setUsbTethering(boolean enable, String callerPkg, String callingAttributionTag,
- IIntResultListener listener) {
- if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
-
- try {
- listener.onResult(mTethering.setUsbTethering(enable));
- } catch (RemoteException e) { }
- }
-
- @Override
- public void startTethering(TetheringRequestParcel request, String callerPkg,
- String callingAttributionTag, IIntResultListener listener) {
- if (checkAndNotifyCommonError(callerPkg,
- callingAttributionTag,
- request.exemptFromEntitlementCheck /* onlyAllowPrivileged */,
- listener)) {
- return;
- }
-
- mTethering.startTethering(request, listener);
- }
-
- @Override
- public void stopTethering(int type, String callerPkg, String callingAttributionTag,
- IIntResultListener listener) {
- if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
-
- try {
- mTethering.stopTethering(type);
- listener.onResult(TETHER_ERROR_NO_ERROR);
- } catch (RemoteException e) { }
- }
-
- @Override
- public void requestLatestTetheringEntitlementResult(int type, ResultReceiver receiver,
- boolean showEntitlementUi, String callerPkg, String callingAttributionTag) {
- if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, receiver)) return;
-
- mTethering.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi);
- }
-
- @Override
- public void registerTetheringEventCallback(ITetheringEventCallback callback,
- String callerPkg) {
- try {
- if (!hasTetherAccessPermission()) {
- callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION);
- return;
- }
- mTethering.registerTetheringEventCallback(callback);
- } catch (RemoteException e) { }
- }
-
- @Override
- public void unregisterTetheringEventCallback(ITetheringEventCallback callback,
- String callerPkg) {
- try {
- if (!hasTetherAccessPermission()) {
- callback.onCallbackStopped(TETHER_ERROR_NO_ACCESS_TETHERING_PERMISSION);
- return;
- }
- mTethering.unregisterTetheringEventCallback(callback);
- } catch (RemoteException e) { }
- }
-
- @Override
- public void stopAllTethering(String callerPkg, String callingAttributionTag,
- IIntResultListener listener) {
- if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
-
- try {
- mTethering.untetherAll();
- listener.onResult(TETHER_ERROR_NO_ERROR);
- } catch (RemoteException e) { }
- }
-
- @Override
- public void isTetheringSupported(String callerPkg, String callingAttributionTag,
- IIntResultListener listener) {
- if (checkAndNotifyCommonError(callerPkg, callingAttributionTag, listener)) return;
-
- try {
- listener.onResult(TETHER_ERROR_NO_ERROR);
- } catch (RemoteException e) { }
- }
-
- @Override
- protected void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
- @Nullable String[] args) {
- mTethering.dump(fd, writer, args);
- }
-
- private boolean checkAndNotifyCommonError(final String callerPkg,
- final String callingAttributionTag, final IIntResultListener listener) {
- return checkAndNotifyCommonError(callerPkg, callingAttributionTag,
- false /* onlyAllowPrivileged */, listener);
- }
-
- private boolean checkAndNotifyCommonError(final String callerPkg,
- final String callingAttributionTag, final boolean onlyAllowPrivileged,
- final IIntResultListener listener) {
- try {
- if (!hasTetherChangePermission(callerPkg, callingAttributionTag,
- onlyAllowPrivileged)) {
- listener.onResult(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION);
- return true;
- }
- if (!mTethering.isTetheringSupported()) {
- listener.onResult(TETHER_ERROR_UNSUPPORTED);
- return true;
- }
- } catch (RemoteException e) {
- return true;
- }
-
- return false;
- }
-
- private boolean checkAndNotifyCommonError(final String callerPkg,
- final String callingAttributionTag, final ResultReceiver receiver) {
- if (!hasTetherChangePermission(callerPkg, callingAttributionTag,
- false /* onlyAllowPrivileged */)) {
- receiver.send(TETHER_ERROR_NO_CHANGE_TETHERING_PERMISSION, null);
- return true;
- }
- if (!mTethering.isTetheringSupported()) {
- receiver.send(TETHER_ERROR_UNSUPPORTED, null);
- return true;
- }
-
- return false;
- }
-
- private boolean hasNetworkStackPermission() {
- return checkCallingOrSelfPermission(NETWORK_STACK)
- || checkCallingOrSelfPermission(PERMISSION_MAINLINE_NETWORK_STACK);
- }
-
- private boolean hasTetherPrivilegedPermission() {
- return checkCallingOrSelfPermission(TETHER_PRIVILEGED);
- }
-
- private boolean checkCallingOrSelfPermission(final String permission) {
- return mService.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED;
- }
-
- private boolean hasTetherChangePermission(final String callerPkg,
- final String callingAttributionTag, final boolean onlyAllowPrivileged) {
- if (onlyAllowPrivileged && !hasNetworkStackPermission()) return false;
-
- if (hasTetherPrivilegedPermission()) return true;
-
- if (mTethering.isTetherProvisioningRequired()) return false;
-
- int uid = Binder.getCallingUid();
-
- // If callerPkg's uid is not same as Binder.getCallingUid(),
- // checkAndNoteWriteSettingsOperation will return false and the operation will be
- // denied.
- return mService.checkAndNoteWriteSettingsOperation(mService, uid, callerPkg,
- callingAttributionTag, false /* throwException */);
- }
-
- private boolean hasTetherAccessPermission() {
- if (hasTetherPrivilegedPermission()) return true;
-
- return mService.checkCallingOrSelfPermission(
- ACCESS_NETWORK_STATE) == PERMISSION_GRANTED;
- }
- }
-
- /**
- * Check if the package is a allowed to write settings. This also accounts that such an access
- * happened.
- *
- * @return {@code true} iff the package is allowed to write settings.
- */
- @VisibleForTesting
- boolean checkAndNoteWriteSettingsOperation(@NonNull Context context, int uid,
- @NonNull String callingPackage, @Nullable String callingAttributionTag,
- boolean throwException) {
- return Settings.checkAndNoteWriteSettingsOperation(context, uid, callingPackage,
- throwException);
- }
-
- /**
- * An injection method for testing.
- */
- @VisibleForTesting
- public TetheringDependencies makeTetheringDependencies() {
- return new TetheringDependencies() {
- @Override
- public NetworkRequest getDefaultNetworkRequest() {
- // TODO: b/147280869, add a proper system API to replace this.
- final NetworkRequest trackDefaultRequest = new NetworkRequest.Builder()
- .clearCapabilities()
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
- .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
- .build();
- return trackDefaultRequest;
- }
-
- @Override
- public Looper getTetheringLooper() {
- final HandlerThread tetherThread = new HandlerThread("android.tethering");
- tetherThread.start();
- return tetherThread.getLooper();
- }
-
- @Override
- public Context getContext() {
- return TetheringService.this;
- }
-
- @Override
- public IpServer.Dependencies getIpServerDependencies() {
- return new IpServer.Dependencies() {
- @Override
- public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
- DhcpServerCallbacks cb) {
- try {
- final INetworkStackConnector service = getNetworkStackConnector();
- if (service == null) return;
-
- service.makeDhcpServer(ifName, params, cb);
- } catch (RemoteException e) {
- Log.e(TAG, "Fail to make dhcp server");
- try {
- cb.onDhcpServerCreated(STATUS_UNKNOWN_ERROR, null);
- } catch (RemoteException re) { }
- }
- }
- };
- }
-
- // TODO: replace this by NetworkStackClient#getRemoteConnector after refactoring
- // networkStackClient.
- static final int NETWORKSTACK_TIMEOUT_MS = 60_000;
- private INetworkStackConnector getNetworkStackConnector() {
- IBinder connector;
- try {
- final long before = System.currentTimeMillis();
- while ((connector = NetworkStack.getService()) == null) {
- if (System.currentTimeMillis() - before > NETWORKSTACK_TIMEOUT_MS) {
- Log.wtf(TAG, "Timeout, fail to get INetworkStackConnector");
- return null;
- }
- Thread.sleep(200);
- }
- } catch (InterruptedException e) {
- Log.wtf(TAG, "Interrupted, fail to get INetworkStackConnector");
- return null;
- }
- return INetworkStackConnector.Stub.asInterface(connector);
- }
-
- @Override
- public BluetoothAdapter getBluetoothAdapter() {
- return BluetoothAdapter.getDefaultAdapter();
- }
- };
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java b/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
deleted file mode 100644
index b17065cb78041..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkMonitor.java
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * Copyright (C) 2017 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 static android.net.ConnectivityManager.TYPE_BLUETOOTH;
-import static android.net.ConnectivityManager.TYPE_ETHERNET;
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
-import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
-import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
-import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-
-import android.content.Context;
-import android.net.ConnectivityManager;
-import android.net.ConnectivityManager.NetworkCallback;
-import android.net.IpPrefix;
-import android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-import android.net.NetworkRequest;
-import android.net.util.PrefixUtils;
-import android.net.util.SharedLog;
-import android.os.Handler;
-import android.util.Log;
-import android.util.SparseIntArray;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.StateMachine;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Set;
-
-
-/**
- * A class to centralize all the network and link properties information
- * pertaining to the current and any potential upstream network.
- *
- * The owner of UNM gets it to register network callbacks by calling the
- * following methods :
- * Calling #startTrackDefaultNetwork() to track the system default network.
- * Calling #startObserveAllNetworks() to observe all networks. Listening all
- * networks is necessary while the expression of preferred upstreams remains
- * a list of legacy connectivity types. In future, this can be revisited.
- * Calling #registerMobileNetworkRequest() to bring up mobile DUN/HIPRI network.
- *
- * The methods and data members of this class are only to be accessed and
- * modified from the tethering main state machine thread. Any other
- * access semantics would necessitate the addition of locking.
- *
- * TODO: Move upstream selection logic here.
- *
- * All callback methods are run on the same thread as the specified target
- * state machine. This class does not require locking when accessed from this
- * thread. Access from other threads is not advised.
- *
- * @hide
- */
-public class UpstreamNetworkMonitor {
- private static final String TAG = UpstreamNetworkMonitor.class.getSimpleName();
- private static final boolean DBG = false;
- private static final boolean VDBG = false;
-
- public static final int EVENT_ON_CAPABILITIES = 1;
- public static final int EVENT_ON_LINKPROPERTIES = 2;
- public static final int EVENT_ON_LOST = 3;
- public static final int NOTIFY_LOCAL_PREFIXES = 10;
- // This value is used by deprecated preferredUpstreamIfaceTypes selection which is default
- // disabled.
- @VisibleForTesting
- public static final int TYPE_NONE = -1;
-
- private static final int CALLBACK_LISTEN_ALL = 1;
- private static final int CALLBACK_DEFAULT_INTERNET = 2;
- private static final int CALLBACK_MOBILE_REQUEST = 3;
-
- private static final SparseIntArray sLegacyTypeToTransport = new SparseIntArray();
- static {
- sLegacyTypeToTransport.put(TYPE_MOBILE, NetworkCapabilities.TRANSPORT_CELLULAR);
- sLegacyTypeToTransport.put(TYPE_MOBILE_DUN, NetworkCapabilities.TRANSPORT_CELLULAR);
- sLegacyTypeToTransport.put(TYPE_MOBILE_HIPRI, NetworkCapabilities.TRANSPORT_CELLULAR);
- sLegacyTypeToTransport.put(TYPE_WIFI, NetworkCapabilities.TRANSPORT_WIFI);
- sLegacyTypeToTransport.put(TYPE_BLUETOOTH, NetworkCapabilities.TRANSPORT_BLUETOOTH);
- sLegacyTypeToTransport.put(TYPE_ETHERNET, NetworkCapabilities.TRANSPORT_ETHERNET);
- }
-
- private final Context mContext;
- private final SharedLog mLog;
- private final StateMachine mTarget;
- private final Handler mHandler;
- private final int mWhat;
- private final HashMap mNetworkMap = new HashMap<>();
- private HashSet mLocalPrefixes;
- private ConnectivityManager mCM;
- private EntitlementManager mEntitlementMgr;
- private NetworkCallback mListenAllCallback;
- private NetworkCallback mDefaultNetworkCallback;
- private NetworkCallback mMobileNetworkCallback;
- private boolean mDunRequired;
- // Whether the current default upstream is mobile or not.
- private boolean mIsDefaultCellularUpstream;
- // The current system default network (not really used yet).
- private Network mDefaultInternetNetwork;
- // The current upstream network used for tethering.
- private Network mTetheringUpstreamNetwork;
-
- public UpstreamNetworkMonitor(Context ctx, StateMachine tgt, SharedLog log, int what) {
- mContext = ctx;
- mTarget = tgt;
- mHandler = mTarget.getHandler();
- mLog = log.forSubComponent(TAG);
- mWhat = what;
- mLocalPrefixes = new HashSet<>();
- mIsDefaultCellularUpstream = false;
- }
-
- @VisibleForTesting
- public UpstreamNetworkMonitor(
- ConnectivityManager cm, StateMachine tgt, SharedLog log, int what) {
- this((Context) null, tgt, log, what);
- mCM = cm;
- }
-
- /**
- * Tracking the system default network. This method should be called when system is ready.
- *
- * @param defaultNetworkRequest should be the same as ConnectivityService default request
- * @param entitle a EntitlementManager object to communicate between EntitlementManager and
- * UpstreamNetworkMonitor
- */
- public void startTrackDefaultNetwork(NetworkRequest defaultNetworkRequest,
- EntitlementManager entitle) {
-
- // defaultNetworkRequest is not really a "request", just a way of tracking the system
- // default network. It's guaranteed not to actually bring up any networks because it's
- // the should be the same request as the ConnectivityService default request, and thus
- // shares fate with it. We can't use registerDefaultNetworkCallback because it will not
- // track the system default network if there is a VPN that applies to our UID.
- if (mDefaultNetworkCallback == null) {
- mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET);
- cm().requestNetwork(defaultNetworkRequest, mDefaultNetworkCallback, mHandler);
- }
- if (mEntitlementMgr == null) {
- mEntitlementMgr = entitle;
- }
- }
-
- /** Listen all networks. */
- public void startObserveAllNetworks() {
- stop();
-
- final NetworkRequest listenAllRequest = new NetworkRequest.Builder()
- .clearCapabilities().build();
- mListenAllCallback = new UpstreamNetworkCallback(CALLBACK_LISTEN_ALL);
- cm().registerNetworkCallback(listenAllRequest, mListenAllCallback, mHandler);
- }
-
- /**
- * Stop tracking candidate tethering upstreams and release mobile network request.
- * Note: this function is used when tethering is stopped because tethering do not need to
- * choose upstream anymore. But it would not stop default network tracking because
- * EntitlementManager may need to know default network to decide whether to request entitlement
- * check even tethering is not active yet.
- */
- public void stop() {
- releaseMobileNetworkRequest();
-
- releaseCallback(mListenAllCallback);
- mListenAllCallback = null;
-
- mTetheringUpstreamNetwork = null;
- mNetworkMap.clear();
- }
-
- /** Setup or teardown DUN connection according to |dunRequired|. */
- public void updateMobileRequiresDun(boolean dunRequired) {
- final boolean valueChanged = (mDunRequired != dunRequired);
- mDunRequired = dunRequired;
- if (valueChanged && mobileNetworkRequested()) {
- releaseMobileNetworkRequest();
- registerMobileNetworkRequest();
- }
- }
-
- /** Whether mobile network is requested. */
- public boolean mobileNetworkRequested() {
- return (mMobileNetworkCallback != null);
- }
-
- /** Request mobile network if mobile upstream is permitted. */
- public void registerMobileNetworkRequest() {
- if (!isCellularUpstreamPermitted()) {
- mLog.i("registerMobileNetworkRequest() is not permitted");
- releaseMobileNetworkRequest();
- return;
- }
- if (mMobileNetworkCallback != null) {
- mLog.e("registerMobileNetworkRequest() already registered");
- return;
- }
-
- final NetworkRequest mobileUpstreamRequest;
- if (mDunRequired) {
- mobileUpstreamRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_DUN)
- .removeCapability(NET_CAPABILITY_NOT_RESTRICTED)
- .addTransportType(TRANSPORT_CELLULAR).build();
- } else {
- mobileUpstreamRequest = new NetworkRequest.Builder()
- .addCapability(NET_CAPABILITY_INTERNET)
- .addTransportType(TRANSPORT_CELLULAR).build();
- }
-
- // The existing default network and DUN callbacks will be notified.
- // Therefore, to avoid duplicate notifications, we only register a no-op.
- mMobileNetworkCallback = new UpstreamNetworkCallback(CALLBACK_MOBILE_REQUEST);
-
- // The following use of the legacy type system cannot be removed until
- // upstream selection no longer finds networks by legacy type.
- // See also http://b/34364553 .
- final int legacyType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
-
- // TODO: Change the timeout from 0 (no onUnavailable callback) to some
- // moderate callback timeout. This might be useful for updating some UI.
- // Additionally, we log a message to aid in any subsequent debugging.
- mLog.i("requesting mobile upstream network: " + mobileUpstreamRequest);
-
- cm().requestNetwork(mobileUpstreamRequest, 0, legacyType, mHandler,
- mMobileNetworkCallback);
- }
-
- /** Release mobile network request. */
- public void releaseMobileNetworkRequest() {
- if (mMobileNetworkCallback == null) return;
-
- cm().unregisterNetworkCallback(mMobileNetworkCallback);
- mMobileNetworkCallback = null;
- }
-
- // So many TODOs here, but chief among them is: make this functionality an
- // integral part of this class such that whenever a higher priority network
- // becomes available and useful we (a) file a request to keep it up as
- // necessary and (b) change all upstream tracking state accordingly (by
- // passing LinkProperties up to Tethering).
- /**
- * Select the first available network from |perferredTypes|.
- */
- public UpstreamNetworkState selectPreferredUpstreamType(Iterable preferredTypes) {
- final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType(
- mNetworkMap.values(), preferredTypes, isCellularUpstreamPermitted());
-
- mLog.log("preferred upstream type: " + typeStatePair.type);
-
- switch (typeStatePair.type) {
- case TYPE_MOBILE_DUN:
- case TYPE_MOBILE_HIPRI:
- // Tethering just selected mobile upstream in spite of the default network being
- // not mobile. This can happen because of the priority list.
- // Notify EntitlementManager to check permission for using mobile upstream.
- if (!mIsDefaultCellularUpstream) {
- mEntitlementMgr.maybeRunProvisioning();
- }
- // If we're on DUN, put our own grab on it.
- registerMobileNetworkRequest();
- break;
- case TYPE_NONE:
- // If we found NONE and mobile upstream is permitted we don't want to do this
- // as we want any previous requests to keep trying to bring up something we can use.
- if (!isCellularUpstreamPermitted()) releaseMobileNetworkRequest();
- break;
- default:
- // If we've found an active upstream connection that's not DUN/HIPRI
- // we should stop any outstanding DUN/HIPRI requests.
- releaseMobileNetworkRequest();
- break;
- }
-
- return typeStatePair.ns;
- }
-
- /**
- * Get current preferred upstream network. If default network is cellular and DUN is required,
- * preferred upstream would be DUN otherwise preferred upstream is the same as default network.
- * Returns null if no current upstream is available.
- */
- public UpstreamNetworkState getCurrentPreferredUpstream() {
- final UpstreamNetworkState dfltState = (mDefaultInternetNetwork != null)
- ? mNetworkMap.get(mDefaultInternetNetwork)
- : null;
- if (isNetworkUsableAndNotCellular(dfltState)) return dfltState;
-
- if (!isCellularUpstreamPermitted()) return null;
-
- if (!mDunRequired) return dfltState;
-
- // Find a DUN network. Note that code in Tethering causes a DUN request
- // to be filed, but this might be moved into this class in future.
- return findFirstDunNetwork(mNetworkMap.values());
- }
-
- /** Tell UpstreamNetworkMonitor which network is the current upstream of tethering. */
- public void setCurrentUpstream(Network upstream) {
- mTetheringUpstreamNetwork = upstream;
- }
-
- /** Return local prefixes. */
- public Set getLocalPrefixes() {
- return (Set) mLocalPrefixes.clone();
- }
-
- private boolean isCellularUpstreamPermitted() {
- if (mEntitlementMgr != null) {
- return mEntitlementMgr.isCellularUpstreamPermitted();
- } else {
- // This flow should only happens in testing.
- return true;
- }
- }
-
- private void handleAvailable(Network network) {
- if (mNetworkMap.containsKey(network)) return;
-
- if (VDBG) Log.d(TAG, "onAvailable for " + network);
- mNetworkMap.put(network, new UpstreamNetworkState(null, null, network));
- }
-
- private void handleNetCap(Network network, NetworkCapabilities newNc) {
- final UpstreamNetworkState prev = mNetworkMap.get(network);
- if (prev == null || newNc.equals(prev.networkCapabilities)) {
- // Ignore notifications about networks for which we have not yet
- // received onAvailable() (should never happen) and any duplicate
- // notifications (e.g. matching more than one of our callbacks).
- return;
- }
-
- if (VDBG) {
- Log.d(TAG, String.format("EVENT_ON_CAPABILITIES for %s: %s",
- network, newNc));
- }
-
- mNetworkMap.put(network, new UpstreamNetworkState(
- prev.linkProperties, newNc, network));
- // TODO: If sufficient information is available to select a more
- // preferable upstream, do so now and notify the target.
- notifyTarget(EVENT_ON_CAPABILITIES, network);
- }
-
- private void handleLinkProp(Network network, LinkProperties newLp) {
- final UpstreamNetworkState prev = mNetworkMap.get(network);
- if (prev == null || newLp.equals(prev.linkProperties)) {
- // Ignore notifications about networks for which we have not yet
- // received onAvailable() (should never happen) and any duplicate
- // notifications (e.g. matching more than one of our callbacks).
- return;
- }
-
- if (VDBG) {
- Log.d(TAG, String.format("EVENT_ON_LINKPROPERTIES for %s: %s",
- network, newLp));
- }
-
- mNetworkMap.put(network, new UpstreamNetworkState(
- newLp, prev.networkCapabilities, network));
- // TODO: If sufficient information is available to select a more
- // preferable upstream, do so now and notify the target.
- notifyTarget(EVENT_ON_LINKPROPERTIES, network);
- }
-
- private void handleLost(Network network) {
- // There are few TODOs within ConnectivityService's rematching code
- // pertaining to spurious onLost() notifications.
- //
- // TODO: simplify this, probably if favor of code that:
- // - selects a new upstream if mTetheringUpstreamNetwork has
- // been lost (by any callback)
- // - deletes the entry from the map only when the LISTEN_ALL
- // callback gets notified.
-
- if (!mNetworkMap.containsKey(network)) {
- // Ignore loss of networks about which we had not previously
- // learned any information or for which we have already processed
- // an onLost() notification.
- return;
- }
-
- if (VDBG) Log.d(TAG, "EVENT_ON_LOST for " + network);
-
- // TODO: If sufficient information is available to select a more
- // preferable upstream, do so now and notify the target. Likewise,
- // if the current upstream network is gone, notify the target of the
- // fact that we now have no upstream at all.
- notifyTarget(EVENT_ON_LOST, mNetworkMap.remove(network));
- }
-
- private void recomputeLocalPrefixes() {
- final HashSet localPrefixes = allLocalPrefixes(mNetworkMap.values());
- if (!mLocalPrefixes.equals(localPrefixes)) {
- mLocalPrefixes = localPrefixes;
- notifyTarget(NOTIFY_LOCAL_PREFIXES, localPrefixes.clone());
- }
- }
-
- // Fetch (and cache) a ConnectivityManager only if and when we need one.
- private ConnectivityManager cm() {
- if (mCM == null) {
- // MUST call the String variant to be able to write unittests.
- mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
- }
- return mCM;
- }
-
- /**
- * A NetworkCallback class that handles information of interest directly
- * in the thread on which it is invoked. To avoid locking, this MUST be
- * run on the same thread as the target state machine's handler.
- */
- private class UpstreamNetworkCallback extends NetworkCallback {
- private final int mCallbackType;
-
- UpstreamNetworkCallback(int callbackType) {
- mCallbackType = callbackType;
- }
-
- @Override
- public void onAvailable(Network network) {
- handleAvailable(network);
- }
-
- @Override
- public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
- if (mCallbackType == CALLBACK_DEFAULT_INTERNET) {
- mDefaultInternetNetwork = network;
- final boolean newIsCellular = isCellular(newNc);
- if (mIsDefaultCellularUpstream != newIsCellular) {
- mIsDefaultCellularUpstream = newIsCellular;
- mEntitlementMgr.notifyUpstream(newIsCellular);
- }
- return;
- }
-
- handleNetCap(network, newNc);
- }
-
- @Override
- public void onLinkPropertiesChanged(Network network, LinkProperties newLp) {
- if (mCallbackType == CALLBACK_DEFAULT_INTERNET) return;
-
- handleLinkProp(network, newLp);
- // Any non-LISTEN_ALL callback will necessarily concern a network that will
- // also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback.
- // So it's not useful to do this work for non-LISTEN_ALL callbacks.
- if (mCallbackType == CALLBACK_LISTEN_ALL) {
- recomputeLocalPrefixes();
- }
- }
-
- @Override
- public void onLost(Network network) {
- if (mCallbackType == CALLBACK_DEFAULT_INTERNET) {
- mDefaultInternetNetwork = null;
- mIsDefaultCellularUpstream = false;
- mEntitlementMgr.notifyUpstream(false);
- return;
- }
-
- handleLost(network);
- // Any non-LISTEN_ALL callback will necessarily concern a network that will
- // also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback.
- // So it's not useful to do this work for non-LISTEN_ALL callbacks.
- if (mCallbackType == CALLBACK_LISTEN_ALL) {
- recomputeLocalPrefixes();
- }
- }
- }
-
- private void releaseCallback(NetworkCallback cb) {
- if (cb != null) cm().unregisterNetworkCallback(cb);
- }
-
- private void notifyTarget(int which, Network network) {
- notifyTarget(which, mNetworkMap.get(network));
- }
-
- private void notifyTarget(int which, Object obj) {
- mTarget.sendMessage(mWhat, which, 0, obj);
- }
-
- private static class TypeStatePair {
- public int type = TYPE_NONE;
- public UpstreamNetworkState ns = null;
- }
-
- private static TypeStatePair findFirstAvailableUpstreamByType(
- Iterable netStates, Iterable preferredTypes,
- boolean isCellularUpstreamPermitted) {
- final TypeStatePair result = new TypeStatePair();
-
- for (int type : preferredTypes) {
- NetworkCapabilities nc;
- try {
- nc = networkCapabilitiesForType(type);
- } catch (IllegalArgumentException iae) {
- Log.e(TAG, "No NetworkCapabilities mapping for legacy type: " + type);
- continue;
- }
- if (!isCellularUpstreamPermitted && isCellular(nc)) {
- continue;
- }
-
- for (UpstreamNetworkState value : netStates) {
- if (!nc.satisfiedByNetworkCapabilities(value.networkCapabilities)) {
- continue;
- }
-
- result.type = type;
- result.ns = value;
- return result;
- }
- }
-
- return result;
- }
-
- private static HashSet allLocalPrefixes(Iterable netStates) {
- final HashSet prefixSet = new HashSet<>();
-
- for (UpstreamNetworkState ns : netStates) {
- final LinkProperties lp = ns.linkProperties;
- if (lp == null) continue;
- prefixSet.addAll(PrefixUtils.localPrefixesFrom(lp));
- }
-
- return prefixSet;
- }
-
- private static boolean isCellular(UpstreamNetworkState ns) {
- return (ns != null) && isCellular(ns.networkCapabilities);
- }
-
- private static boolean isCellular(NetworkCapabilities nc) {
- return (nc != null) && nc.hasTransport(TRANSPORT_CELLULAR)
- && nc.hasCapability(NET_CAPABILITY_NOT_VPN);
- }
-
- private static boolean hasCapability(UpstreamNetworkState ns, int netCap) {
- return (ns != null) && (ns.networkCapabilities != null)
- && ns.networkCapabilities.hasCapability(netCap);
- }
-
- private static boolean isNetworkUsableAndNotCellular(UpstreamNetworkState ns) {
- return (ns != null) && (ns.networkCapabilities != null) && (ns.linkProperties != null)
- && !isCellular(ns.networkCapabilities);
- }
-
- private static UpstreamNetworkState findFirstDunNetwork(
- Iterable netStates) {
- for (UpstreamNetworkState ns : netStates) {
- if (isCellular(ns) && hasCapability(ns, NET_CAPABILITY_DUN)) return ns;
- }
-
- return null;
- }
-
- /**
- * Given a legacy type (TYPE_WIFI, ...) returns the corresponding NetworkCapabilities instance.
- * This function is used for deprecated legacy type and be disabled by default.
- */
- @VisibleForTesting
- public static NetworkCapabilities networkCapabilitiesForType(int type) {
- final NetworkCapabilities.Builder builder = new NetworkCapabilities.Builder();
-
- // Map from type to transports.
- final int notFound = -1;
- final int transport = sLegacyTypeToTransport.get(type, notFound);
- if (transport == notFound) {
- throw new IllegalArgumentException("unknown legacy type: " + type);
- }
- builder.addTransportType(transport);
-
- if (type == TYPE_MOBILE_DUN) {
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_DUN);
- // DUN is restricted network, see NetworkCapabilities#FORCE_RESTRICTED_CAPABILITIES.
- builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED);
- } else {
- builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET);
- }
- return builder.build();
- }
-}
diff --git a/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java b/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java
deleted file mode 100644
index bab9f84cf7628..0000000000000
--- a/packages/Tethering/src/com/android/networkstack/tethering/UpstreamNetworkState.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019 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 android.net.LinkProperties;
-import android.net.Network;
-import android.net.NetworkCapabilities;
-
-import androidx.annotation.NonNull;
-
-/**
- * Snapshot of tethering upstream network state.
- */
-public class UpstreamNetworkState {
- /** {@link LinkProperties}. */
- public final LinkProperties linkProperties;
- /** {@link NetworkCapabilities}. */
- public final NetworkCapabilities networkCapabilities;
- /** {@link Network}. */
- public final Network network;
-
- /** Constructs a new UpstreamNetworkState. */
- public UpstreamNetworkState(LinkProperties linkProperties,
- NetworkCapabilities networkCapabilities, Network network) {
- this.linkProperties = linkProperties;
- this.networkCapabilities = networkCapabilities;
- this.network = network;
- }
-
- @NonNull
- @Override
- public String toString() {
- return String.format("UpstreamNetworkState{%s, %s, %s}",
- network == null ? "null" : network,
- networkCapabilities == null ? "null" : networkCapabilities,
- linkProperties == null ? "null" : linkProperties);
- }
-}
diff --git a/packages/Tethering/tests/Android.bp b/packages/Tethering/tests/Android.bp
deleted file mode 100644
index 731144cee0fb0..0000000000000
--- a/packages/Tethering/tests/Android.bp
+++ /dev/null
@@ -1,24 +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.
-//
-
-filegroup {
- name: "TetheringTestsJarJarRules",
- srcs: ["jarjar-rules.txt"],
- visibility: [
- "//frameworks/base/packages/Tethering/tests:__subpackages__",
- "//packages/modules/Connectivity/Tethering/tests:__subpackages__",
- ]
-}
diff --git a/packages/Tethering/tests/integration/Android.bp b/packages/Tethering/tests/integration/Android.bp
deleted file mode 100644
index 5765c01c43f3c..0000000000000
--- a/packages/Tethering/tests/integration/Android.bp
+++ /dev/null
@@ -1,85 +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.
-//
-java_defaults {
- name: "TetheringIntegrationTestsDefaults",
- srcs: [
- "src/**/*.java",
- "src/**/*.kt",
- ],
- static_libs: [
- "NetworkStackApiStableLib",
- "androidx.test.rules",
- "mockito-target-extended-minus-junit4",
- "net-tests-utils",
- "testables",
- ],
- libs: [
- "android.test.runner",
- "android.test.base",
- "android.test.mock",
- ],
- jni_libs: [
- // For mockito extended
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- ],
- jarjar_rules: ":NetworkStackJarJarRules",
-}
-
-android_library {
- name: "TetheringIntegrationTestsLib",
- platform_apis: true,
- defaults: ["TetheringIntegrationTestsDefaults"],
- visibility: ["//cts/tests/tests/tethering"]
-}
-
-android_test {
- name: "TetheringIntegrationTests",
- platform_apis: true,
- defaults: ["TetheringIntegrationTestsDefaults"],
- test_suites: [
- "device-tests",
- "mts",
- ],
- compile_multilib: "both",
-}
-
-// Special version of the tethering tests that includes all tests necessary for code coverage
-// purposes. This is currently the union of TetheringTests, TetheringIntegrationTests and
-// NetworkStackTests.
-android_test {
- name: "TetheringCoverageTests",
- platform_apis: true,
- test_suites: ["device-tests", "mts"],
- test_config: "AndroidTest_Coverage.xml",
- defaults: ["libnetworkstackutilsjni_deps"],
- static_libs: [
- "NetworkStaticLibTestsLib",
- "NetworkStackTestsLib",
- "TetheringTestsLib",
- "TetheringIntegrationTestsLib",
- ],
- jni_libs: [
- // For mockito extended
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- // For NetworkStackUtils included in NetworkStackBase
- "libnetworkstackutilsjni",
- ],
- jarjar_rules: ":TetheringTestsJarJarRules",
- compile_multilib: "both",
- manifest: "AndroidManifest_coverage.xml",
-}
diff --git a/packages/Tethering/tests/integration/AndroidManifest.xml b/packages/Tethering/tests/integration/AndroidManifest.xml
deleted file mode 100644
index fddfaad29f0f5..0000000000000
--- a/packages/Tethering/tests/integration/AndroidManifest.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/Tethering/tests/integration/AndroidManifest_coverage.xml b/packages/Tethering/tests/integration/AndroidManifest_coverage.xml
deleted file mode 100644
index 06de00d785587..0000000000000
--- a/packages/Tethering/tests/integration/AndroidManifest_coverage.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/packages/Tethering/tests/integration/AndroidTest_Coverage.xml b/packages/Tethering/tests/integration/AndroidTest_Coverage.xml
deleted file mode 100644
index 3def2099e45f0..0000000000000
--- a/packages/Tethering/tests/integration/AndroidTest_Coverage.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java b/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
deleted file mode 100644
index d206ea0b4d452..0000000000000
--- a/packages/Tethering/tests/integration/src/android/net/EthernetTetheringTest.java
+++ /dev/null
@@ -1,566 +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 android.net;
-
-import static android.Manifest.permission.MANAGE_TEST_NETWORKS;
-import static android.Manifest.permission.NETWORK_SETTINGS;
-import static android.Manifest.permission.TETHER_PRIVILEGED;
-import static android.net.TetheringManager.TETHERING_ETHERNET;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-import static org.junit.Assume.assumeFalse;
-import static org.junit.Assume.assumeTrue;
-
-import android.app.UiAutomation;
-import android.content.Context;
-import android.net.EthernetManager.TetheredInterfaceCallback;
-import android.net.EthernetManager.TetheredInterfaceRequest;
-import android.net.TetheringManager.StartTetheringCallback;
-import android.net.TetheringManager.TetheringEventCallback;
-import android.net.TetheringManager.TetheringRequest;
-import android.net.dhcp.DhcpAckPacket;
-import android.net.dhcp.DhcpOfferPacket;
-import android.net.dhcp.DhcpPacket;
-import android.os.Handler;
-import android.os.HandlerThread;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.system.Os;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.MediumTest;
-import androidx.test.runner.AndroidJUnit4;
-
-import com.android.testutils.HandlerUtils;
-import com.android.testutils.TapPacketReader;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.FileDescriptor;
-import java.net.Inet4Address;
-import java.net.InterfaceAddress;
-import java.net.NetworkInterface;
-import java.net.SocketException;
-import java.nio.ByteBuffer;
-import java.util.Collection;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-@RunWith(AndroidJUnit4.class)
-@MediumTest
-public class EthernetTetheringTest {
-
- private static final String TAG = EthernetTetheringTest.class.getSimpleName();
- private static final int TIMEOUT_MS = 5000;
- private static final int PACKET_READ_TIMEOUT_MS = 100;
- private static final int DHCP_DISCOVER_ATTEMPTS = 10;
- private static final byte[] DHCP_REQUESTED_PARAMS = new byte[] {
- DhcpPacket.DHCP_SUBNET_MASK,
- DhcpPacket.DHCP_ROUTER,
- DhcpPacket.DHCP_DNS_SERVER,
- DhcpPacket.DHCP_LEASE_TIME,
- };
- private static final String DHCP_HOSTNAME = "testhostname";
-
- private final Context mContext = InstrumentationRegistry.getContext();
- private final EthernetManager mEm = mContext.getSystemService(EthernetManager.class);
- private final TetheringManager mTm = mContext.getSystemService(TetheringManager.class);
-
- private TestNetworkInterface mTestIface;
- private HandlerThread mHandlerThread;
- private Handler mHandler;
- private TapPacketReader mTapPacketReader;
-
- private TetheredInterfaceRequester mTetheredInterfaceRequester;
- private MyTetheringEventCallback mTetheringEventCallback;
-
- private UiAutomation mUiAutomation =
- InstrumentationRegistry.getInstrumentation().getUiAutomation();
- private boolean mRunTests;
-
- @Before
- public void setUp() throws Exception {
- // Needed to create a TestNetworkInterface, to call requestTetheredInterface, and to receive
- // tethered client callbacks.
- mUiAutomation.adoptShellPermissionIdentity(
- MANAGE_TEST_NETWORKS, NETWORK_SETTINGS, TETHER_PRIVILEGED);
- mRunTests = mTm.isTetheringSupported() && mEm != null;
- assumeTrue(mRunTests);
-
- mHandlerThread = new HandlerThread(getClass().getSimpleName());
- mHandlerThread.start();
- mHandler = new Handler(mHandlerThread.getLooper());
- mTetheredInterfaceRequester = new TetheredInterfaceRequester(mHandler, mEm);
- }
-
- private void cleanUp() throws Exception {
- mTm.stopTethering(TETHERING_ETHERNET);
- if (mTetheringEventCallback != null) {
- mTetheringEventCallback.awaitInterfaceUntethered();
- mTetheringEventCallback.unregister();
- mTetheringEventCallback = null;
- }
- if (mTapPacketReader != null) {
- TapPacketReader reader = mTapPacketReader;
- mHandler.post(() -> reader.stop());
- mTapPacketReader = null;
- }
- mHandlerThread.quitSafely();
- mTetheredInterfaceRequester.release();
- mEm.setIncludeTestInterfaces(false);
- maybeDeleteTestInterface();
- }
-
- @After
- public void tearDown() throws Exception {
- try {
- if (mRunTests) cleanUp();
- } finally {
- mUiAutomation.dropShellPermissionIdentity();
- }
- }
-
- @Test
- public void testVirtualEthernetAlreadyExists() throws Exception {
- // This test requires manipulating packets. Skip if there is a physical Ethernet connected.
- assumeFalse(mEm.isAvailable());
-
- mTestIface = createTestInterface();
- // This must be done now because as soon as setIncludeTestInterfaces(true) is called, the
- // interface will be placed in client mode, which will delete the link-local address.
- // At that point NetworkInterface.getByName() will cease to work on the interface, because
- // starting in R NetworkInterface can no longer see interfaces without IP addresses.
- int mtu = getMTU(mTestIface);
-
- Log.d(TAG, "Including test interfaces");
- mEm.setIncludeTestInterfaces(true);
-
- final String iface = mTetheredInterfaceRequester.getInterface();
- assertEquals("TetheredInterfaceCallback for unexpected interface",
- mTestIface.getInterfaceName(), iface);
-
- checkVirtualEthernet(mTestIface, mtu);
- }
-
- @Test
- public void testVirtualEthernet() throws Exception {
- // This test requires manipulating packets. Skip if there is a physical Ethernet connected.
- assumeFalse(mEm.isAvailable());
-
- CompletableFuture futureIface = mTetheredInterfaceRequester.requestInterface();
-
- mEm.setIncludeTestInterfaces(true);
-
- mTestIface = createTestInterface();
-
- final String iface = futureIface.get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- assertEquals("TetheredInterfaceCallback for unexpected interface",
- mTestIface.getInterfaceName(), iface);
-
- checkVirtualEthernet(mTestIface, getMTU(mTestIface));
- }
-
- @Test
- public void testStaticIpv4() throws Exception {
- assumeFalse(mEm.isAvailable());
-
- mEm.setIncludeTestInterfaces(true);
-
- mTestIface = createTestInterface();
-
- final String iface = mTetheredInterfaceRequester.getInterface();
- assertEquals("TetheredInterfaceCallback for unexpected interface",
- mTestIface.getInterfaceName(), iface);
-
- assertInvalidStaticIpv4Request(iface, null, null);
- assertInvalidStaticIpv4Request(iface, "2001:db8::1/64", "2001:db8:2::/64");
- assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", "2001:db8:2::/28");
- assertInvalidStaticIpv4Request(iface, "2001:db8:2::/28", "192.0.2.2/28");
- assertInvalidStaticIpv4Request(iface, "192.0.2.2/28", null);
- assertInvalidStaticIpv4Request(iface, null, "192.0.2.2/28");
- assertInvalidStaticIpv4Request(iface, "192.0.2.3/27", "192.0.2.2/28");
-
- final String localAddr = "192.0.2.3/28";
- final String clientAddr = "192.0.2.2/28";
- mTetheringEventCallback = enableEthernetTethering(iface,
- requestWithStaticIpv4(localAddr, clientAddr));
-
- mTetheringEventCallback.awaitInterfaceTethered();
- assertInterfaceHasIpAddress(iface, localAddr);
-
- byte[] client1 = MacAddress.fromString("1:2:3:4:5:6").toByteArray();
- byte[] client2 = MacAddress.fromString("a:b:c:d:e:f").toByteArray();
-
- FileDescriptor fd = mTestIface.getFileDescriptor().getFileDescriptor();
- mTapPacketReader = makePacketReader(fd, getMTU(mTestIface));
- DhcpResults dhcpResults = runDhcp(fd, client1);
- assertEquals(new LinkAddress(clientAddr), dhcpResults.ipAddress);
-
- try {
- runDhcp(fd, client2);
- fail("Only one client should get an IP address");
- } catch (TimeoutException expected) { }
-
- }
-
- private boolean isAdbOverNetwork() {
- // If adb TCP port opened, this test may running by adb over network.
- return (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1)
- || (SystemProperties.getInt("service.adb.tcp.port", -1) > -1);
- }
-
- @Test
- public void testPhysicalEthernet() throws Exception {
- assumeTrue(mEm.isAvailable());
- // Do not run this test if adb is over network and ethernet is connected.
- // It is likely the adb run over ethernet, the adb would break when ethernet is switching
- // from client mode to server mode. See b/160389275.
- assumeFalse(isAdbOverNetwork());
-
- // Get an interface to use.
- final String iface = mTetheredInterfaceRequester.getInterface();
-
- // Enable Ethernet tethering and check that it starts.
- mTetheringEventCallback = enableEthernetTethering(iface);
-
- // There is nothing more we can do on a physical interface without connecting an actual
- // client, which is not possible in this test.
- }
-
- private static final class MyTetheringEventCallback implements TetheringEventCallback {
- private final TetheringManager mTm;
- private final CountDownLatch mTetheringStartedLatch = new CountDownLatch(1);
- private final CountDownLatch mTetheringStoppedLatch = new CountDownLatch(1);
- private final CountDownLatch mClientConnectedLatch = new CountDownLatch(1);
- private final String mIface;
-
- private volatile boolean mInterfaceWasTethered = false;
- private volatile boolean mUnregistered = false;
- private volatile Collection mClients = null;
-
- MyTetheringEventCallback(TetheringManager tm, String iface) {
- mTm = tm;
- mIface = iface;
- }
-
- public void unregister() {
- mTm.unregisterTetheringEventCallback(this);
- mUnregistered = true;
- }
-
- @Override
- public void onTetheredInterfacesChanged(List interfaces) {
- // Ignore stale callbacks registered by previous test cases.
- if (mUnregistered) return;
-
- final boolean wasTethered = mTetheringStartedLatch.getCount() == 0;
- if (!mInterfaceWasTethered && (mIface == null || interfaces.contains(mIface))) {
- // This interface is being tethered for the first time.
- Log.d(TAG, "Tethering started: " + interfaces);
- mInterfaceWasTethered = true;
- mTetheringStartedLatch.countDown();
- } else if (mInterfaceWasTethered && !interfaces.contains(mIface)) {
- Log.d(TAG, "Tethering stopped: " + interfaces);
- mTetheringStoppedLatch.countDown();
- }
- }
-
- public void awaitInterfaceTethered() throws Exception {
- assertTrue("Ethernet not tethered after " + TIMEOUT_MS + "ms",
- mTetheringStartedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- }
-
- public void awaitInterfaceUntethered() throws Exception {
- // Don't block teardown if the interface was never tethered.
- // This is racy because the interface might become tethered right after this check, but
- // that can only happen in tearDown if startTethering timed out, which likely means
- // the test has already failed.
- if (!mInterfaceWasTethered) return;
-
- assertTrue(mIface + " not untethered after " + TIMEOUT_MS + "ms",
- mTetheringStoppedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- }
-
- @Override
- public void onError(String ifName, int error) {
- // Ignore stale callbacks registered by previous test cases.
- if (mUnregistered) return;
-
- fail("TetheringEventCallback got error:" + error + " on iface " + ifName);
- }
-
- @Override
- public void onClientsChanged(Collection clients) {
- // Ignore stale callbacks registered by previous test cases.
- if (mUnregistered) return;
-
- Log.d(TAG, "Got clients changed: " + clients);
- mClients = clients;
- if (clients.size() > 0) {
- mClientConnectedLatch.countDown();
- }
- }
-
- public Collection awaitClientConnected() throws Exception {
- assertTrue("Did not receive client connected callback after " + TIMEOUT_MS + "ms",
- mClientConnectedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
- return mClients;
- }
- }
-
- private MyTetheringEventCallback enableEthernetTethering(String iface,
- TetheringRequest request) throws Exception {
- MyTetheringEventCallback callback = new MyTetheringEventCallback(mTm, iface);
- mTm.registerTetheringEventCallback(mHandler::post, callback);
-
- StartTetheringCallback startTetheringCallback = new StartTetheringCallback() {
- @Override
- public void onTetheringFailed(int resultCode) {
- fail("Unexpectedly got onTetheringFailed");
- }
- };
- Log.d(TAG, "Starting Ethernet tethering");
- mTm.startTethering(request, mHandler::post /* executor */, startTetheringCallback);
- callback.awaitInterfaceTethered();
- return callback;
- }
-
- private MyTetheringEventCallback enableEthernetTethering(String iface) throws Exception {
- return enableEthernetTethering(iface,
- new TetheringRequest.Builder(TETHERING_ETHERNET)
- .setShouldShowEntitlementUi(false).build());
- }
-
- private int getMTU(TestNetworkInterface iface) throws SocketException {
- NetworkInterface nif = NetworkInterface.getByName(iface.getInterfaceName());
- assertNotNull("Can't get NetworkInterface object for " + iface.getInterfaceName(), nif);
- return nif.getMTU();
- }
-
- private TapPacketReader makePacketReader(FileDescriptor fd, int mtu) {
- final TapPacketReader reader = new TapPacketReader(mHandler, fd, mtu);
- mHandler.post(() -> reader.start());
- HandlerUtils.waitForIdle(mHandler, TIMEOUT_MS);
- return reader;
- }
-
- private void checkVirtualEthernet(TestNetworkInterface iface, int mtu) throws Exception {
- FileDescriptor fd = iface.getFileDescriptor().getFileDescriptor();
- mTapPacketReader = makePacketReader(fd, mtu);
- mTetheringEventCallback = enableEthernetTethering(iface.getInterfaceName());
- checkTetheredClientCallbacks(fd);
- }
-
- private DhcpResults runDhcp(FileDescriptor fd, byte[] clientMacAddr) throws Exception {
- // We have to retransmit DHCP requests because IpServer declares itself to be ready before
- // its DhcpServer is actually started. TODO: fix this race and remove this loop.
- DhcpPacket offerPacket = null;
- for (int i = 0; i < DHCP_DISCOVER_ATTEMPTS; i++) {
- Log.d(TAG, "Sending DHCP discover");
- sendDhcpDiscover(fd, clientMacAddr);
- offerPacket = getNextDhcpPacket();
- if (offerPacket instanceof DhcpOfferPacket) break;
- }
- if (!(offerPacket instanceof DhcpOfferPacket)) {
- throw new TimeoutException("No DHCPOFFER received on interface within timeout");
- }
-
- sendDhcpRequest(fd, offerPacket, clientMacAddr);
- DhcpPacket ackPacket = getNextDhcpPacket();
- if (!(ackPacket instanceof DhcpAckPacket)) {
- throw new TimeoutException("No DHCPACK received on interface within timeout");
- }
-
- return ackPacket.toDhcpResults();
- }
-
- private void checkTetheredClientCallbacks(FileDescriptor fd) throws Exception {
- // Create a fake client.
- byte[] clientMacAddr = new byte[6];
- new Random().nextBytes(clientMacAddr);
-
- DhcpResults dhcpResults = runDhcp(fd, clientMacAddr);
-
- final Collection clients = mTetheringEventCallback.awaitClientConnected();
- assertEquals(1, clients.size());
- final TetheredClient client = clients.iterator().next();
-
- // Check the MAC address.
- assertEquals(MacAddress.fromBytes(clientMacAddr), client.getMacAddress());
- assertEquals(TETHERING_ETHERNET, client.getTetheringType());
-
- // Check the hostname.
- assertEquals(1, client.getAddresses().size());
- TetheredClient.AddressInfo info = client.getAddresses().get(0);
- assertEquals(DHCP_HOSTNAME, info.getHostname());
-
- // Check the address is the one that was handed out in the DHCP ACK.
- assertLinkAddressMatches(dhcpResults.ipAddress, info.getAddress());
-
- // Check that the lifetime is correct +/- 10s.
- final long now = SystemClock.elapsedRealtime();
- final long actualLeaseDuration = (info.getAddress().getExpirationTime() - now) / 1000;
- final String msg = String.format("IP address should have lifetime of %d, got %d",
- dhcpResults.leaseDuration, actualLeaseDuration);
- assertTrue(msg, Math.abs(dhcpResults.leaseDuration - actualLeaseDuration) < 10);
- }
-
- private DhcpPacket getNextDhcpPacket() throws ParseException {
- byte[] packet;
- while ((packet = mTapPacketReader.popPacket(PACKET_READ_TIMEOUT_MS)) != null) {
- try {
- return DhcpPacket.decodeFullPacket(packet, packet.length, DhcpPacket.ENCAP_L2);
- } catch (DhcpPacket.ParseException e) {
- // Not a DHCP packet. Continue.
- }
- }
- return null;
- }
-
- private static final class TetheredInterfaceRequester implements TetheredInterfaceCallback {
- private final CountDownLatch mInterfaceAvailableLatch = new CountDownLatch(1);
- private final Handler mHandler;
- private final EthernetManager mEm;
-
- private TetheredInterfaceRequest mRequest;
- private final CompletableFuture mFuture = new CompletableFuture<>();
-
- TetheredInterfaceRequester(Handler handler, EthernetManager em) {
- mHandler = handler;
- mEm = em;
- }
-
- @Override
- public void onAvailable(String iface) {
- Log.d(TAG, "Ethernet interface available: " + iface);
- mFuture.complete(iface);
- }
-
- @Override
- public void onUnavailable() {
- mFuture.completeExceptionally(new IllegalStateException("onUnavailable received"));
- }
-
- public CompletableFuture requestInterface() {
- assertNull("BUG: more than one tethered interface request", mRequest);
- Log.d(TAG, "Requesting tethered interface");
- mRequest = mEm.requestTetheredInterface(mHandler::post, this);
- return mFuture;
- }
-
- public String getInterface() throws Exception {
- return requestInterface().get(TIMEOUT_MS, TimeUnit.MILLISECONDS);
- }
-
- public void release() {
- if (mRequest != null) {
- mFuture.obtrudeException(new IllegalStateException("Request already released"));
- mRequest.release();
- mRequest = null;
- }
- }
- }
-
- private void sendDhcpDiscover(FileDescriptor fd, byte[] macAddress) throws Exception {
- ByteBuffer packet = DhcpPacket.buildDiscoverPacket(DhcpPacket.ENCAP_L2,
- new Random().nextInt() /* transactionId */, (short) 0 /* secs */,
- macAddress, false /* unicast */, DHCP_REQUESTED_PARAMS,
- false /* rapid commit */, DHCP_HOSTNAME);
- sendPacket(fd, packet);
- }
-
- private void sendDhcpRequest(FileDescriptor fd, DhcpPacket offerPacket, byte[] macAddress)
- throws Exception {
- DhcpResults results = offerPacket.toDhcpResults();
- Inet4Address clientIp = (Inet4Address) results.ipAddress.getAddress();
- Inet4Address serverIdentifier = results.serverAddress;
- ByteBuffer packet = DhcpPacket.buildRequestPacket(DhcpPacket.ENCAP_L2,
- 0 /* transactionId */, (short) 0 /* secs */, DhcpPacket.INADDR_ANY /* clientIp */,
- false /* broadcast */, macAddress, clientIp /* requestedIpAddress */,
- serverIdentifier, DHCP_REQUESTED_PARAMS, DHCP_HOSTNAME);
- sendPacket(fd, packet);
- }
-
- private void sendPacket(FileDescriptor fd, ByteBuffer packet) throws Exception {
- assertNotNull("Only tests on virtual interfaces can send packets", fd);
- Os.write(fd, packet);
- }
-
- public void assertLinkAddressMatches(LinkAddress l1, LinkAddress l2) {
- // Check all fields except the deprecation and expiry times.
- String msg = String.format("LinkAddresses do not match. expected: %s actual: %s", l1, l2);
- assertTrue(msg, l1.isSameAddressAs(l2));
- assertEquals("LinkAddress flags do not match", l1.getFlags(), l2.getFlags());
- assertEquals("LinkAddress scope does not match", l1.getScope(), l2.getScope());
- }
-
- private TetheringRequest requestWithStaticIpv4(String local, String client) {
- LinkAddress localAddr = local == null ? null : new LinkAddress(local);
- LinkAddress clientAddr = client == null ? null : new LinkAddress(client);
- return new TetheringRequest.Builder(TETHERING_ETHERNET)
- .setStaticIpv4Addresses(localAddr, clientAddr)
- .setShouldShowEntitlementUi(false).build();
- }
-
- private void assertInvalidStaticIpv4Request(String iface, String local, String client)
- throws Exception {
- try {
- enableEthernetTethering(iface, requestWithStaticIpv4(local, client));
- fail("Unexpectedly accepted invalid IPv4 configuration: " + local + ", " + client);
- } catch (IllegalArgumentException | NullPointerException expected) { }
- }
-
- private void assertInterfaceHasIpAddress(String iface, String expected) throws Exception {
- LinkAddress expectedAddr = new LinkAddress(expected);
- NetworkInterface nif = NetworkInterface.getByName(iface);
- for (InterfaceAddress ia : nif.getInterfaceAddresses()) {
- final LinkAddress addr = new LinkAddress(ia.getAddress(), ia.getNetworkPrefixLength());
- if (expectedAddr.equals(addr)) {
- return;
- }
- }
- fail("Expected " + iface + " to have IP address " + expected + ", found "
- + nif.getInterfaceAddresses());
- }
-
- private TestNetworkInterface createTestInterface() throws Exception {
- TestNetworkManager tnm = mContext.getSystemService(TestNetworkManager.class);
- TestNetworkInterface iface = tnm.createTapInterface();
- Log.d(TAG, "Created test interface " + iface.getInterfaceName());
- return iface;
- }
-
- private void maybeDeleteTestInterface() throws Exception {
- if (mTestIface != null) {
- mTestIface.getFileDescriptor().close();
- Log.d(TAG, "Deleted test interface " + mTestIface.getInterfaceName());
- mTestIface = null;
- }
- }
-}
diff --git a/packages/Tethering/tests/jarjar-rules.txt b/packages/Tethering/tests/jarjar-rules.txt
deleted file mode 100644
index c99ff7f818775..0000000000000
--- a/packages/Tethering/tests/jarjar-rules.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-# Don't jar-jar the entire package because this test use some
-# internal classes (like ArrayUtils in com.android.internal.util)
-rule com.android.internal.util.BitUtils* com.android.networkstack.tethering.util.BitUtils@1
-rule com.android.internal.util.IndentingPrintWriter.java* com.android.networkstack.tethering.util.IndentingPrintWriter.java@1
-rule com.android.internal.util.IState.java* com.android.networkstack.tethering.util.IState.java@1
-rule com.android.internal.util.MessageUtils* com.android.networkstack.tethering.util.MessageUtils@1
-rule com.android.internal.util.State* com.android.networkstack.tethering.util.State@1
-rule com.android.internal.util.StateMachine* com.android.networkstack.tethering.util.StateMachine@1
-rule com.android.internal.util.TrafficStatsConstants* com.android.networkstack.tethering.util.TrafficStatsConstants@1
-
-rule android.util.LocalLog* com.android.networkstack.tethering.util.LocalLog@1
-
-# Classes from net-utils-framework-common
-rule com.android.net.module.util.** com.android.networkstack.tethering.util.@1
-
-# TODO: either stop using frameworks-base-testutils or remove the unit test classes it contains.
-# TestableLooper from "testables" can be used instead of TestLooper from frameworks-base-testutils.
-zap android.os.test.TestLooperTest*
-zap com.android.test.filters.SelectTestTests*
diff --git a/packages/Tethering/tests/mts/Android.bp b/packages/Tethering/tests/mts/Android.bp
deleted file mode 100644
index f925b0a53f32d..0000000000000
--- a/packages/Tethering/tests/mts/Android.bp
+++ /dev/null
@@ -1,56 +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.
-
-android_test {
- // This tests for functionality that is not required for devices that
- // don't use Tethering mainline module.
- name: "MtsTetheringTest",
-
- libs: [
- "android.test.base",
- ],
-
- srcs: [
- "src/**/*.java",
- ],
-
- static_libs: [
- "androidx.test.rules",
- // mockito-target-extended-minus-junit4 used in this lib have dependency with
- // jni_libs libdexmakerjvmtiagent and libstaticjvmtiagent.
- "cts-net-utils",
- // This is needed for androidx.test.runner.AndroidJUnitRunner.
- "ctstestrunner-axt",
- "junit",
- "junit-params",
- ],
-
- jni_libs: [
- // For mockito extended which is pulled in from -net-utils -> net-tests-utils
- // (mockito-target-extended-minus-junit4).
- "libdexmakerjvmtiagent",
- "libstaticjvmtiagent",
- ],
-
- platform_apis: true,
-
- // Tag this module as a mts test artifact
- test_suites: [
- "general-tests",
- "mts",
- ],
-
- // Include both the 32 and 64 bit versions
- compile_multilib: "both",
-}
diff --git a/packages/Tethering/tests/mts/AndroidManifest.xml b/packages/Tethering/tests/mts/AndroidManifest.xml
deleted file mode 100644
index 6d2abcad42a38..0000000000000
--- a/packages/Tethering/tests/mts/AndroidManifest.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
-
-
-
-
-
-