1 /* 2 * Copyright (C) 2018 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.ethernet; 18 19 import static android.net.TestNetworkManager.TEST_TAP_PREFIX; 20 21 import android.annotation.Nullable; 22 import android.content.Context; 23 import android.net.IEthernetServiceListener; 24 import android.net.INetd; 25 import android.net.ITetheredInterfaceCallback; 26 import android.net.InterfaceConfiguration; 27 import android.net.IpConfiguration; 28 import android.net.IpConfiguration.IpAssignment; 29 import android.net.IpConfiguration.ProxySettings; 30 import android.net.LinkAddress; 31 import android.net.NetworkCapabilities; 32 import android.net.NetworkStack; 33 import android.net.StaticIpConfiguration; 34 import android.os.Handler; 35 import android.os.IBinder; 36 import android.os.INetworkManagementService; 37 import android.os.RemoteCallbackList; 38 import android.os.RemoteException; 39 import android.os.ServiceManager; 40 import android.text.TextUtils; 41 import android.util.ArrayMap; 42 import android.util.Log; 43 import android.net.util.NetdService; 44 45 import com.android.internal.annotations.VisibleForTesting; 46 import com.android.internal.util.IndentingPrintWriter; 47 import com.android.net.module.util.NetdUtils; 48 import com.android.server.net.BaseNetworkObserver; 49 50 import java.io.FileDescriptor; 51 import java.net.InetAddress; 52 import java.util.ArrayList; 53 import java.util.Objects; 54 import java.util.concurrent.ConcurrentHashMap; 55 56 /** 57 * Tracks Ethernet interfaces and manages interface configurations. 58 * 59 * <p>Interfaces may have different {@link android.net.NetworkCapabilities}. This mapping is defined 60 * in {@code config_ethernet_interfaces}. Notably, some interfaces could be marked as restricted by 61 * not specifying {@link android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED} flag. 62 * Interfaces could have associated {@link android.net.IpConfiguration}. 63 * Ethernet Interfaces may be present at boot time or appear after boot (e.g., for Ethernet adapters 64 * connected over USB). This class supports multiple interfaces. When an interface appears on the 65 * system (or is present at boot time) this class will start tracking it and bring it up. Only 66 * interfaces whose names match the {@code config_ethernet_iface_regex} regular expression are 67 * tracked. 68 * 69 * <p>All public or package private methods must be thread-safe unless stated otherwise. 70 */ 71 final class EthernetTracker { 72 private static final int INTERFACE_MODE_CLIENT = 1; 73 private static final int INTERFACE_MODE_SERVER = 2; 74 75 private final static String TAG = EthernetTracker.class.getSimpleName(); 76 private final static boolean DBG = EthernetNetworkFactory.DBG; 77 78 private static final String TEST_IFACE_REGEXP = TEST_TAP_PREFIX + "\\d+"; 79 80 /** 81 * Interface names we track. This is a product-dependent regular expression, plus, 82 * if setIncludeTestInterfaces is true, any test interfaces. 83 */ 84 private String mIfaceMatch; 85 private boolean mIncludeTestInterfaces = false; 86 87 /** Mapping between {iface name | mac address} -> {NetworkCapabilities} */ 88 private final ConcurrentHashMap<String, NetworkCapabilities> mNetworkCapabilities = 89 new ConcurrentHashMap<>(); 90 private final ConcurrentHashMap<String, IpConfiguration> mIpConfigurations = 91 new ConcurrentHashMap<>(); 92 93 private final Context mContext; 94 private final INetworkManagementService mNMService; 95 private final INetd mNetd; 96 private final Handler mHandler; 97 private final EthernetNetworkFactory mFactory; 98 private final EthernetConfigStore mConfigStore; 99 100 private final RemoteCallbackList<IEthernetServiceListener> mListeners = 101 new RemoteCallbackList<>(); 102 private final TetheredInterfaceRequestList mTetheredInterfaceRequests = 103 new TetheredInterfaceRequestList(); 104 105 // Used only on the handler thread 106 private String mDefaultInterface; 107 private int mDefaultInterfaceMode = INTERFACE_MODE_CLIENT; 108 // Tracks whether clients were notified that the tethered interface is available 109 private boolean mTetheredInterfaceWasAvailable = false; 110 private volatile IpConfiguration mIpConfigForDefaultInterface; 111 112 private class TetheredInterfaceRequestList extends RemoteCallbackList<ITetheredInterfaceCallback> { 113 @Override onCallbackDied(ITetheredInterfaceCallback cb, Object cookie)114 public void onCallbackDied(ITetheredInterfaceCallback cb, Object cookie) { 115 mHandler.post(EthernetTracker.this::maybeUntetherDefaultInterface); 116 } 117 } 118 EthernetTracker(Context context, Handler handler)119 EthernetTracker(Context context, Handler handler) { 120 mContext = context; 121 mHandler = handler; 122 123 // The services we use. 124 IBinder b = ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE); 125 mNMService = INetworkManagementService.Stub.asInterface(b); 126 mNetd = Objects.requireNonNull(NetdService.getInstance(), "could not get netd instance"); 127 128 // Interface match regex. 129 updateIfaceMatchRegexp(); 130 131 // Read default Ethernet interface configuration from resources 132 final String[] interfaceConfigs = context.getResources().getStringArray( 133 com.android.internal.R.array.config_ethernet_interfaces); 134 for (String strConfig : interfaceConfigs) { 135 parseEthernetConfig(strConfig); 136 } 137 138 mConfigStore = new EthernetConfigStore(); 139 140 NetworkCapabilities nc = createNetworkCapabilities(true /* clear default capabilities */); 141 mFactory = new EthernetNetworkFactory(handler, context, nc); 142 mFactory.register(); 143 } 144 start()145 void start() { 146 mConfigStore.read(); 147 148 // Default interface is just the first one we want to track. 149 mIpConfigForDefaultInterface = mConfigStore.getIpConfigurationForDefaultInterface(); 150 final ArrayMap<String, IpConfiguration> configs = mConfigStore.getIpConfigurations(); 151 for (int i = 0; i < configs.size(); i++) { 152 mIpConfigurations.put(configs.keyAt(i), configs.valueAt(i)); 153 } 154 155 try { 156 mNMService.registerObserver(new InterfaceObserver()); 157 } catch (RemoteException e) { 158 Log.e(TAG, "Could not register InterfaceObserver " + e); 159 } 160 161 mHandler.post(this::trackAvailableInterfaces); 162 } 163 updateIpConfiguration(String iface, IpConfiguration ipConfiguration)164 void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) { 165 if (DBG) { 166 Log.i(TAG, "updateIpConfiguration, iface: " + iface + ", cfg: " + ipConfiguration); 167 } 168 169 mConfigStore.write(iface, ipConfiguration); 170 mIpConfigurations.put(iface, ipConfiguration); 171 172 mHandler.post(() -> mFactory.updateIpConfiguration(iface, ipConfiguration)); 173 } 174 getIpConfiguration(String iface)175 IpConfiguration getIpConfiguration(String iface) { 176 return mIpConfigurations.get(iface); 177 } 178 isTrackingInterface(String iface)179 boolean isTrackingInterface(String iface) { 180 return mFactory.hasInterface(iface); 181 } 182 getInterfaces(boolean includeRestricted)183 String[] getInterfaces(boolean includeRestricted) { 184 return mFactory.getAvailableInterfaces(includeRestricted); 185 } 186 187 /** 188 * Returns true if given interface was configured as restricted (doesn't have 189 * NET_CAPABILITY_NOT_RESTRICTED) capability. Otherwise, returns false. 190 */ isRestrictedInterface(String iface)191 boolean isRestrictedInterface(String iface) { 192 final NetworkCapabilities nc = mNetworkCapabilities.get(iface); 193 return nc != null && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 194 } 195 addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks)196 void addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks) { 197 mListeners.register(listener, new ListenerInfo(canUseRestrictedNetworks)); 198 } 199 removeListener(IEthernetServiceListener listener)200 void removeListener(IEthernetServiceListener listener) { 201 mListeners.unregister(listener); 202 } 203 setIncludeTestInterfaces(boolean include)204 public void setIncludeTestInterfaces(boolean include) { 205 mHandler.post(() -> { 206 mIncludeTestInterfaces = include; 207 updateIfaceMatchRegexp(); 208 mHandler.post(() -> trackAvailableInterfaces()); 209 }); 210 } 211 requestTetheredInterface(ITetheredInterfaceCallback callback)212 public void requestTetheredInterface(ITetheredInterfaceCallback callback) { 213 mHandler.post(() -> { 214 if (!mTetheredInterfaceRequests.register(callback)) { 215 // Remote process has already died 216 return; 217 } 218 if (mDefaultInterfaceMode == INTERFACE_MODE_SERVER) { 219 if (mTetheredInterfaceWasAvailable) { 220 notifyTetheredInterfaceAvailable(callback, mDefaultInterface); 221 } 222 return; 223 } 224 225 setDefaultInterfaceMode(INTERFACE_MODE_SERVER); 226 }); 227 } 228 releaseTetheredInterface(ITetheredInterfaceCallback callback)229 public void releaseTetheredInterface(ITetheredInterfaceCallback callback) { 230 mHandler.post(() -> { 231 mTetheredInterfaceRequests.unregister(callback); 232 maybeUntetherDefaultInterface(); 233 }); 234 } 235 notifyTetheredInterfaceAvailable(ITetheredInterfaceCallback cb, String iface)236 private void notifyTetheredInterfaceAvailable(ITetheredInterfaceCallback cb, String iface) { 237 try { 238 cb.onAvailable(iface); 239 } catch (RemoteException e) { 240 Log.e(TAG, "Error sending tethered interface available callback", e); 241 } 242 } 243 notifyTetheredInterfaceUnavailable(ITetheredInterfaceCallback cb)244 private void notifyTetheredInterfaceUnavailable(ITetheredInterfaceCallback cb) { 245 try { 246 cb.onUnavailable(); 247 } catch (RemoteException e) { 248 Log.e(TAG, "Error sending tethered interface available callback", e); 249 } 250 } 251 maybeUntetherDefaultInterface()252 private void maybeUntetherDefaultInterface() { 253 if (mTetheredInterfaceRequests.getRegisteredCallbackCount() > 0) return; 254 if (mDefaultInterfaceMode == INTERFACE_MODE_CLIENT) return; 255 setDefaultInterfaceMode(INTERFACE_MODE_CLIENT); 256 } 257 setDefaultInterfaceMode(int mode)258 private void setDefaultInterfaceMode(int mode) { 259 Log.d(TAG, "Setting default interface mode to " + mode); 260 mDefaultInterfaceMode = mode; 261 if (mDefaultInterface != null) { 262 removeInterface(mDefaultInterface); 263 addInterface(mDefaultInterface); 264 } 265 } 266 getInterfaceMode(final String iface)267 private int getInterfaceMode(final String iface) { 268 if (iface.equals(mDefaultInterface)) { 269 return mDefaultInterfaceMode; 270 } 271 return INTERFACE_MODE_CLIENT; 272 } 273 removeInterface(String iface)274 private void removeInterface(String iface) { 275 mFactory.removeInterface(iface); 276 maybeUpdateServerModeInterfaceState(iface, false); 277 } 278 stopTrackingInterface(String iface)279 private void stopTrackingInterface(String iface) { 280 removeInterface(iface); 281 if (iface.equals(mDefaultInterface)) { 282 mDefaultInterface = null; 283 } 284 } 285 addInterface(String iface)286 private void addInterface(String iface) { 287 InterfaceConfiguration config = null; 288 // Bring up the interface so we get link status indications. 289 try { 290 NetworkStack.checkNetworkStackPermission(mContext); 291 NetdUtils.setInterfaceUp(mNetd, iface); 292 config = mNMService.getInterfaceConfig(iface); 293 } catch (RemoteException | IllegalStateException e) { 294 // Either the system is crashing or the interface has disappeared. Just ignore the 295 // error; we haven't modified any state because we only do that if our calls succeed. 296 Log.e(TAG, "Error upping interface " + iface, e); 297 } 298 299 if (config == null) { 300 Log.e(TAG, "Null interface config for " + iface + ". Bailing out."); 301 return; 302 } 303 304 final String hwAddress = config.getHardwareAddress(); 305 306 NetworkCapabilities nc = mNetworkCapabilities.get(iface); 307 if (nc == null) { 308 // Try to resolve using mac address 309 nc = mNetworkCapabilities.get(hwAddress); 310 if (nc == null) { 311 final boolean isTestIface = iface.matches(TEST_IFACE_REGEXP); 312 nc = createDefaultNetworkCapabilities(isTestIface); 313 } 314 } 315 316 final int mode = getInterfaceMode(iface); 317 if (mode == INTERFACE_MODE_CLIENT) { 318 IpConfiguration ipConfiguration = mIpConfigurations.get(iface); 319 if (ipConfiguration == null) { 320 ipConfiguration = createDefaultIpConfiguration(); 321 } 322 323 Log.d(TAG, "Tracking interface in client mode: " + iface); 324 mFactory.addInterface(iface, hwAddress, nc, ipConfiguration); 325 } else { 326 maybeUpdateServerModeInterfaceState(iface, true); 327 } 328 329 // Note: if the interface already has link (e.g., if we crashed and got 330 // restarted while it was running), we need to fake a link up notification so we 331 // start configuring it. 332 if (config.hasFlag("running")) { 333 updateInterfaceState(iface, true); 334 } 335 } 336 updateInterfaceState(String iface, boolean up)337 private void updateInterfaceState(String iface, boolean up) { 338 final int mode = getInterfaceMode(iface); 339 final boolean factoryLinkStateUpdated = (mode == INTERFACE_MODE_CLIENT) 340 && mFactory.updateInterfaceLinkState(iface, up); 341 342 if (factoryLinkStateUpdated) { 343 boolean restricted = isRestrictedInterface(iface); 344 int n = mListeners.beginBroadcast(); 345 for (int i = 0; i < n; i++) { 346 try { 347 if (restricted) { 348 ListenerInfo listenerInfo = (ListenerInfo) mListeners.getBroadcastCookie(i); 349 if (!listenerInfo.canUseRestrictedNetworks) { 350 continue; 351 } 352 } 353 mListeners.getBroadcastItem(i).onAvailabilityChanged(iface, up); 354 } catch (RemoteException e) { 355 // Do nothing here. 356 } 357 } 358 mListeners.finishBroadcast(); 359 } 360 } 361 maybeUpdateServerModeInterfaceState(String iface, boolean available)362 private void maybeUpdateServerModeInterfaceState(String iface, boolean available) { 363 if (available == mTetheredInterfaceWasAvailable || !iface.equals(mDefaultInterface)) return; 364 365 Log.d(TAG, (available ? "Tracking" : "No longer tracking") 366 + " interface in server mode: " + iface); 367 368 final int pendingCbs = mTetheredInterfaceRequests.beginBroadcast(); 369 for (int i = 0; i < pendingCbs; i++) { 370 ITetheredInterfaceCallback item = mTetheredInterfaceRequests.getBroadcastItem(i); 371 if (available) { 372 notifyTetheredInterfaceAvailable(item, iface); 373 } else { 374 notifyTetheredInterfaceUnavailable(item); 375 } 376 } 377 mTetheredInterfaceRequests.finishBroadcast(); 378 mTetheredInterfaceWasAvailable = available; 379 } 380 maybeTrackInterface(String iface)381 private void maybeTrackInterface(String iface) { 382 if (!iface.matches(mIfaceMatch)) { 383 return; 384 } 385 386 // If we don't already track this interface, and if this interface matches 387 // our regex, start tracking it. 388 if (mFactory.hasInterface(iface) || iface.equals(mDefaultInterface)) { 389 if (DBG) Log.w(TAG, "Ignoring already-tracked interface " + iface); 390 return; 391 } 392 if (DBG) Log.i(TAG, "maybeTrackInterface: " + iface); 393 394 // TODO: avoid making an interface default if it has configured NetworkCapabilities. 395 if (mDefaultInterface == null) { 396 mDefaultInterface = iface; 397 } 398 399 if (mIpConfigForDefaultInterface != null) { 400 updateIpConfiguration(iface, mIpConfigForDefaultInterface); 401 mIpConfigForDefaultInterface = null; 402 } 403 404 addInterface(iface); 405 } 406 trackAvailableInterfaces()407 private void trackAvailableInterfaces() { 408 try { 409 final String[] ifaces = mNMService.listInterfaces(); 410 for (String iface : ifaces) { 411 maybeTrackInterface(iface); 412 } 413 } catch (RemoteException | IllegalStateException e) { 414 Log.e(TAG, "Could not get list of interfaces " + e); 415 } 416 } 417 418 419 private class InterfaceObserver extends BaseNetworkObserver { 420 421 @Override interfaceLinkStateChanged(String iface, boolean up)422 public void interfaceLinkStateChanged(String iface, boolean up) { 423 if (DBG) { 424 Log.i(TAG, "interfaceLinkStateChanged, iface: " + iface + ", up: " + up); 425 } 426 mHandler.post(() -> updateInterfaceState(iface, up)); 427 } 428 429 @Override interfaceAdded(String iface)430 public void interfaceAdded(String iface) { 431 mHandler.post(() -> maybeTrackInterface(iface)); 432 } 433 434 @Override interfaceRemoved(String iface)435 public void interfaceRemoved(String iface) { 436 mHandler.post(() -> stopTrackingInterface(iface)); 437 } 438 } 439 440 private static class ListenerInfo { 441 442 boolean canUseRestrictedNetworks = false; 443 ListenerInfo(boolean canUseRestrictedNetworks)444 ListenerInfo(boolean canUseRestrictedNetworks) { 445 this.canUseRestrictedNetworks = canUseRestrictedNetworks; 446 } 447 } 448 449 /** 450 * Parses an Ethernet interface configuration 451 * 452 * @param configString represents an Ethernet configuration in the following format: {@code 453 * <interface name|mac address>;[Network Capabilities];[IP config];[Override Transport]} 454 */ parseEthernetConfig(String configString)455 private void parseEthernetConfig(String configString) { 456 String[] tokens = configString.split(";", /* limit of tokens */ 4); 457 String name = tokens[0]; 458 String capabilities = tokens.length > 1 ? tokens[1] : null; 459 String transport = tokens.length > 3 ? tokens[3] : null; 460 NetworkCapabilities nc = createNetworkCapabilities( 461 !TextUtils.isEmpty(capabilities) /* clear default capabilities */, capabilities, 462 transport).build(); 463 mNetworkCapabilities.put(name, nc); 464 465 if (tokens.length > 2 && !TextUtils.isEmpty(tokens[2])) { 466 IpConfiguration ipConfig = parseStaticIpConfiguration(tokens[2]); 467 mIpConfigurations.put(name, ipConfig); 468 } 469 } 470 createDefaultNetworkCapabilities(boolean isTestIface)471 private static NetworkCapabilities createDefaultNetworkCapabilities(boolean isTestIface) { 472 NetworkCapabilities.Builder builder = createNetworkCapabilities( 473 false /* clear default capabilities */, null, null) 474 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) 475 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) 476 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) 477 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) 478 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) 479 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED); 480 481 if (isTestIface) { 482 builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST); 483 } else { 484 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 485 } 486 487 return builder.build(); 488 } 489 createNetworkCapabilities(boolean clearDefaultCapabilities)490 private static NetworkCapabilities createNetworkCapabilities(boolean clearDefaultCapabilities) { 491 return createNetworkCapabilities(clearDefaultCapabilities, null, null).build(); 492 } 493 494 /** 495 * Parses a static list of network capabilities 496 * 497 * @param clearDefaultCapabilities Indicates whether or not to clear any default capabilities 498 * @param commaSeparatedCapabilities A comma separated string list of integer encoded 499 * NetworkCapability.NET_CAPABILITY_* values 500 * @param overrideTransport A string representing a single integer encoded override transport 501 * type. Must be one of the NetworkCapability.TRANSPORT_* 502 * values. TRANSPORT_VPN is not supported. Errors with input 503 * will cause the override to be ignored. 504 */ 505 @VisibleForTesting createNetworkCapabilities( boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities, @Nullable String overrideTransport)506 static NetworkCapabilities.Builder createNetworkCapabilities( 507 boolean clearDefaultCapabilities, @Nullable String commaSeparatedCapabilities, 508 @Nullable String overrideTransport) { 509 510 final NetworkCapabilities.Builder builder = clearDefaultCapabilities 511 ? NetworkCapabilities.Builder.withoutDefaultCapabilities() 512 : new NetworkCapabilities.Builder(); 513 514 // Determine the transport type. If someone has tried to define an override transport then 515 // attempt to add it. Since we can only have one override, all errors with it will 516 // gracefully default back to TRANSPORT_ETHERNET and warn the user. VPN is not allowed as an 517 // override type. Wifi Aware and LoWPAN are currently unsupported as well. 518 int transport = NetworkCapabilities.TRANSPORT_ETHERNET; 519 if (!TextUtils.isEmpty(overrideTransport)) { 520 try { 521 int parsedTransport = Integer.valueOf(overrideTransport); 522 if (parsedTransport == NetworkCapabilities.TRANSPORT_VPN 523 || parsedTransport == NetworkCapabilities.TRANSPORT_WIFI_AWARE 524 || parsedTransport == NetworkCapabilities.TRANSPORT_LOWPAN) { 525 Log.e(TAG, "Override transport '" + parsedTransport + "' is not supported. " 526 + "Defaulting to TRANSPORT_ETHERNET"); 527 } else { 528 transport = parsedTransport; 529 } 530 } catch (NumberFormatException nfe) { 531 Log.e(TAG, "Override transport type '" + overrideTransport + "' " 532 + "could not be parsed. Defaulting to TRANSPORT_ETHERNET"); 533 } 534 } 535 536 // Apply the transport. If the user supplied a valid number that is not a valid transport 537 // then adding will throw an exception. Default back to TRANSPORT_ETHERNET if that happens 538 try { 539 builder.addTransportType(transport); 540 } catch (IllegalArgumentException iae) { 541 Log.e(TAG, transport + " is not a valid NetworkCapability.TRANSPORT_* value. " 542 + "Defaulting to TRANSPORT_ETHERNET"); 543 builder.addTransportType(NetworkCapabilities.TRANSPORT_ETHERNET); 544 } 545 546 builder.setLinkUpstreamBandwidthKbps(100 * 1000); 547 builder.setLinkDownstreamBandwidthKbps(100 * 1000); 548 549 if (!TextUtils.isEmpty(commaSeparatedCapabilities)) { 550 for (String strNetworkCapability : commaSeparatedCapabilities.split(",")) { 551 if (!TextUtils.isEmpty(strNetworkCapability)) { 552 try { 553 builder.addCapability(Integer.valueOf(strNetworkCapability)); 554 } catch (NumberFormatException nfe) { 555 Log.e(TAG, "Capability '" + strNetworkCapability + "' could not be parsed"); 556 } catch (IllegalArgumentException iae) { 557 Log.e(TAG, strNetworkCapability + " is not a valid " 558 + "NetworkCapability.NET_CAPABILITY_* value"); 559 } 560 } 561 } 562 } 563 // Ethernet networks have no way to update the following capabilities, so they always 564 // have them. 565 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); 566 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); 567 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); 568 569 return builder; 570 } 571 572 /** 573 * Parses static IP configuration. 574 * 575 * @param staticIpConfig represents static IP configuration in the following format: {@code 576 * ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses> 577 * domains=<comma-sep-domains>} 578 */ 579 @VisibleForTesting parseStaticIpConfiguration(String staticIpConfig)580 static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) { 581 final StaticIpConfiguration.Builder staticIpConfigBuilder = 582 new StaticIpConfiguration.Builder(); 583 584 for (String keyValueAsString : staticIpConfig.trim().split(" ")) { 585 if (TextUtils.isEmpty(keyValueAsString)) continue; 586 587 String[] pair = keyValueAsString.split("="); 588 if (pair.length != 2) { 589 throw new IllegalArgumentException("Unexpected token: " + keyValueAsString 590 + " in " + staticIpConfig); 591 } 592 593 String key = pair[0]; 594 String value = pair[1]; 595 596 switch (key) { 597 case "ip": 598 staticIpConfigBuilder.setIpAddress(new LinkAddress(value)); 599 break; 600 case "domains": 601 staticIpConfigBuilder.setDomains(value); 602 break; 603 case "gateway": 604 staticIpConfigBuilder.setGateway(InetAddress.parseNumericAddress(value)); 605 break; 606 case "dns": { 607 ArrayList<InetAddress> dnsAddresses = new ArrayList<>(); 608 for (String address: value.split(",")) { 609 dnsAddresses.add(InetAddress.parseNumericAddress(address)); 610 } 611 staticIpConfigBuilder.setDnsServers(dnsAddresses); 612 break; 613 } 614 default : { 615 throw new IllegalArgumentException("Unexpected key: " + key 616 + " in " + staticIpConfig); 617 } 618 } 619 } 620 final IpConfiguration ret = new IpConfiguration(); 621 ret.setIpAssignment(IpAssignment.STATIC); 622 ret.setProxySettings(ProxySettings.NONE); 623 ret.setStaticIpConfiguration(staticIpConfigBuilder.build()); 624 return ret; 625 } 626 createDefaultIpConfiguration()627 private static IpConfiguration createDefaultIpConfiguration() { 628 final IpConfiguration ret = new IpConfiguration(); 629 ret.setIpAssignment(IpAssignment.DHCP); 630 ret.setProxySettings(ProxySettings.NONE); 631 return ret; 632 } 633 updateIfaceMatchRegexp()634 private void updateIfaceMatchRegexp() { 635 final String match = mContext.getResources().getString( 636 com.android.internal.R.string.config_ethernet_iface_regex); 637 mIfaceMatch = mIncludeTestInterfaces 638 ? "(" + match + "|" + TEST_IFACE_REGEXP + ")" 639 : match; 640 Log.d(TAG, "Interface match regexp set to '" + mIfaceMatch + "'"); 641 } 642 postAndWaitForRunnable(Runnable r)643 private void postAndWaitForRunnable(Runnable r) { 644 mHandler.runWithScissors(r, 2000L /* timeout */); 645 } 646 dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args)647 void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { 648 postAndWaitForRunnable(() -> { 649 pw.println(getClass().getSimpleName()); 650 pw.println("Ethernet interface name filter: " + mIfaceMatch); 651 pw.println("Default interface: " + mDefaultInterface); 652 pw.println("Default interface mode: " + mDefaultInterfaceMode); 653 pw.println("Tethered interface requests: " 654 + mTetheredInterfaceRequests.getRegisteredCallbackCount()); 655 pw.println("Listeners: " + mListeners.getRegisteredCallbackCount()); 656 pw.println("IP Configurations:"); 657 pw.increaseIndent(); 658 for (String iface : mIpConfigurations.keySet()) { 659 pw.println(iface + ": " + mIpConfigurations.get(iface)); 660 } 661 pw.decreaseIndent(); 662 pw.println(); 663 664 pw.println("Network Capabilities:"); 665 pw.increaseIndent(); 666 for (String iface : mNetworkCapabilities.keySet()) { 667 pw.println(iface + ": " + mNetworkCapabilities.get(iface)); 668 } 669 pw.decreaseIndent(); 670 pw.println(); 671 672 mFactory.dump(fd, pw, args); 673 }); 674 } 675 } 676