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