• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.connectivity.tethering;
18 
19 import static android.content.Context.TELEPHONY_SERVICE;
20 import static android.net.ConnectivityManager.TYPE_MOBILE;
21 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
22 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
23 
24 import android.content.Context;
25 import android.content.res.Resources;
26 import android.net.ConnectivityManager;
27 import android.telephony.TelephonyManager;
28 import android.util.Log;
29 
30 import java.io.PrintWriter;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collection;
34 import java.util.StringJoiner;
35 
36 
37 /**
38  * A utility class to encapsulate the various tethering configuration elements.
39  *
40  * This configuration data includes elements describing upstream properties
41  * (preferred and required types of upstream connectivity as well as default
42  * DNS servers to use if none are available) and downstream properties (such
43  * as regular expressions use to match suitable downstream interfaces and the
44  * DHCPv4 ranges to use).
45  *
46  * @hide
47  */
48 public class TetheringConfiguration {
49     private static final String TAG = TetheringConfiguration.class.getSimpleName();
50 
51     public static final int DUN_NOT_REQUIRED = 0;
52     public static final int DUN_REQUIRED = 1;
53     public static final int DUN_UNSPECIFIED = 2;
54 
55     // USB is  192.168.42.1 and 255.255.255.0
56     // Wifi is 192.168.43.1 and 255.255.255.0
57     // BT is limited to max default of 5 connections. 192.168.44.1 to 192.168.48.1
58     // with 255.255.255.0
59     // P2P is 192.168.49.1 and 255.255.255.0
60     private static final String[] DHCP_DEFAULT_RANGE = {
61         "192.168.42.2", "192.168.42.254", "192.168.43.2", "192.168.43.254",
62         "192.168.44.2", "192.168.44.254", "192.168.45.2", "192.168.45.254",
63         "192.168.46.2", "192.168.46.254", "192.168.47.2", "192.168.47.254",
64         "192.168.48.2", "192.168.48.254", "192.168.49.2", "192.168.49.254",
65     };
66 
67     private final String[] DEFAULT_IPV4_DNS = {"8.8.4.4", "8.8.8.8"};
68 
69     public final String[] tetherableUsbRegexs;
70     public final String[] tetherableWifiRegexs;
71     public final String[] tetherableBluetoothRegexs;
72     public final boolean isDunRequired;
73     public final Collection<Integer> preferredUpstreamIfaceTypes;
74     public final String[] dhcpRanges;
75     public final String[] defaultIPv4DNS;
76 
TetheringConfiguration(Context ctx)77     public TetheringConfiguration(Context ctx) {
78         tetherableUsbRegexs = ctx.getResources().getStringArray(
79                 com.android.internal.R.array.config_tether_usb_regexs);
80         // TODO: Evaluate deleting this altogether now that Wi-Fi always passes
81         // us an interface name. Careful consideration needs to be given to
82         // implications for Settings and for provisioning checks.
83         tetherableWifiRegexs = ctx.getResources().getStringArray(
84                 com.android.internal.R.array.config_tether_wifi_regexs);
85         tetherableBluetoothRegexs = ctx.getResources().getStringArray(
86                 com.android.internal.R.array.config_tether_bluetooth_regexs);
87 
88         final int dunCheck = checkDunRequired(ctx);
89         preferredUpstreamIfaceTypes = getUpstreamIfaceTypes(ctx, dunCheck);
90         isDunRequired = preferredUpstreamIfaceTypes.contains(TYPE_MOBILE_DUN);
91 
92         dhcpRanges = getDhcpRanges(ctx);
93         defaultIPv4DNS = copy(DEFAULT_IPV4_DNS);
94     }
95 
isUsb(String iface)96     public boolean isUsb(String iface) {
97         return matchesDownstreamRegexs(iface, tetherableUsbRegexs);
98     }
99 
isWifi(String iface)100     public boolean isWifi(String iface) {
101         return matchesDownstreamRegexs(iface, tetherableWifiRegexs);
102     }
103 
isBluetooth(String iface)104     public boolean isBluetooth(String iface) {
105         return matchesDownstreamRegexs(iface, tetherableBluetoothRegexs);
106     }
107 
dump(PrintWriter pw)108     public void dump(PrintWriter pw) {
109         dumpStringArray(pw, "tetherableUsbRegexs", tetherableUsbRegexs);
110         dumpStringArray(pw, "tetherableWifiRegexs", tetherableWifiRegexs);
111         dumpStringArray(pw, "tetherableBluetoothRegexs", tetherableBluetoothRegexs);
112 
113         pw.print("isDunRequired: ");
114         pw.println(isDunRequired);
115 
116         String[] upstreamTypes = null;
117         if (preferredUpstreamIfaceTypes != null) {
118             upstreamTypes = new String[preferredUpstreamIfaceTypes.size()];
119             int i = 0;
120             for (Integer netType : preferredUpstreamIfaceTypes) {
121                 upstreamTypes[i] = ConnectivityManager.getNetworkTypeName(netType);
122                 i++;
123             }
124         }
125         dumpStringArray(pw, "preferredUpstreamIfaceTypes", upstreamTypes);
126 
127         dumpStringArray(pw, "dhcpRanges", dhcpRanges);
128         dumpStringArray(pw, "defaultIPv4DNS", defaultIPv4DNS);
129     }
130 
dumpStringArray(PrintWriter pw, String label, String[] values)131     private static void dumpStringArray(PrintWriter pw, String label, String[] values) {
132         pw.print(label);
133         pw.print(": ");
134 
135         if (values != null) {
136             final StringJoiner sj = new StringJoiner(", ", "[", "]");
137             for (String value : values) { sj.add(value); }
138             pw.print(sj.toString());
139         } else {
140             pw.print("null");
141         }
142 
143         pw.println();
144     }
145 
checkDunRequired(Context ctx)146     private static int checkDunRequired(Context ctx) {
147         final TelephonyManager tm = (TelephonyManager) ctx.getSystemService(TELEPHONY_SERVICE);
148         return (tm != null) ? tm.getTetherApnRequired() : DUN_UNSPECIFIED;
149     }
150 
getUpstreamIfaceTypes(Context ctx, int dunCheck)151     private static Collection<Integer> getUpstreamIfaceTypes(Context ctx, int dunCheck) {
152         final int ifaceTypes[] = ctx.getResources().getIntArray(
153                 com.android.internal.R.array.config_tether_upstream_types);
154         final ArrayList<Integer> upstreamIfaceTypes = new ArrayList<>(ifaceTypes.length);
155         for (int i : ifaceTypes) {
156             switch (i) {
157                 case TYPE_MOBILE:
158                 case TYPE_MOBILE_HIPRI:
159                     if (dunCheck == DUN_REQUIRED) continue;
160                     break;
161                 case TYPE_MOBILE_DUN:
162                     if (dunCheck == DUN_NOT_REQUIRED) continue;
163                     break;
164             }
165             upstreamIfaceTypes.add(i);
166         }
167 
168         // Fix up upstream interface types for DUN or mobile. NOTE: independent
169         // of the value of |dunCheck|, cell data of one form or another is
170         // *always* an upstream, regardless of the upstream interface types
171         // specified by configuration resources.
172         if (dunCheck == DUN_REQUIRED) {
173             if (!upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)) {
174                 upstreamIfaceTypes.add(TYPE_MOBILE_DUN);
175             }
176         } else if (dunCheck == DUN_NOT_REQUIRED) {
177             if (!upstreamIfaceTypes.contains(TYPE_MOBILE)) {
178                 upstreamIfaceTypes.add(TYPE_MOBILE);
179             }
180             if (!upstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI)) {
181                 upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI);
182             }
183         } else {
184             // Fix upstream interface types for case DUN_UNSPECIFIED.
185             // Do not modify if a cellular interface type is already present in the
186             // upstream interface types. Add TYPE_MOBILE and TYPE_MOBILE_HIPRI if no
187             // cellular interface types are found in the upstream interface types.
188             if (!(upstreamIfaceTypes.contains(TYPE_MOBILE_DUN)
189                     || upstreamIfaceTypes.contains(TYPE_MOBILE)
190                     || upstreamIfaceTypes.contains(TYPE_MOBILE_HIPRI))) {
191                 upstreamIfaceTypes.add(TYPE_MOBILE);
192                 upstreamIfaceTypes.add(TYPE_MOBILE_HIPRI);
193             }
194         }
195 
196         return upstreamIfaceTypes;
197     }
198 
matchesDownstreamRegexs(String iface, String[] regexs)199     private static boolean matchesDownstreamRegexs(String iface, String[] regexs) {
200         for (String regex : regexs) {
201             if (iface.matches(regex)) return true;
202         }
203         return false;
204     }
205 
getDhcpRanges(Context ctx)206     private static String[] getDhcpRanges(Context ctx) {
207         final String[] fromResource = ctx.getResources().getStringArray(
208                 com.android.internal.R.array.config_tether_dhcp_range);
209         if ((fromResource.length > 0) && (fromResource.length % 2 == 0)) {
210             return fromResource;
211         }
212         return copy(DHCP_DEFAULT_RANGE);
213     }
214 
copy(String[] strarray)215     private static String[] copy(String[] strarray) {
216         return Arrays.copyOf(strarray, strarray.length);
217     }
218 }
219