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.EthernetManager.ETHERNET_STATE_DISABLED; 20 import static android.net.EthernetManager.ETHERNET_STATE_ENABLED; 21 import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET; 22 import static android.net.NetworkCapabilities.TRANSPORT_LOWPAN; 23 import static android.net.NetworkCapabilities.TRANSPORT_VPN; 24 import static android.net.NetworkCapabilities.TRANSPORT_WIFI_AWARE; 25 import static android.net.TestNetworkManager.TEST_TAP_PREFIX; 26 27 import static com.android.internal.annotations.VisibleForTesting.Visibility.PACKAGE; 28 import static com.android.net.module.util.netlink.NetlinkConstants.IFF_UP; 29 30 import android.annotation.NonNull; 31 import android.annotation.Nullable; 32 import android.content.Context; 33 import android.net.EthernetManager; 34 import android.net.IEthernetServiceListener; 35 import android.net.INetd; 36 import android.net.ITetheredInterfaceCallback; 37 import android.net.InterfaceConfigurationParcel; 38 import android.net.IpConfiguration; 39 import android.net.IpConfiguration.IpAssignment; 40 import android.net.IpConfiguration.ProxySettings; 41 import android.net.LinkAddress; 42 import android.net.NetworkCapabilities; 43 import android.net.StaticIpConfiguration; 44 import android.os.ConditionVariable; 45 import android.os.Handler; 46 import android.os.RemoteCallbackList; 47 import android.os.RemoteException; 48 import android.system.OsConstants; 49 import android.text.TextUtils; 50 import android.util.ArrayMap; 51 import android.util.Log; 52 53 import com.android.internal.annotations.VisibleForTesting; 54 import com.android.internal.util.IndentingPrintWriter; 55 import com.android.modules.utils.build.SdkLevel; 56 import com.android.net.module.util.HandlerUtils; 57 import com.android.net.module.util.NetdUtils; 58 import com.android.net.module.util.SharedLog; 59 import com.android.net.module.util.ip.NetlinkMonitor; 60 import com.android.net.module.util.netlink.NetlinkConstants; 61 import com.android.net.module.util.netlink.NetlinkMessage; 62 import com.android.net.module.util.netlink.NetlinkUtils; 63 import com.android.net.module.util.netlink.RtNetlinkLinkMessage; 64 import com.android.net.module.util.netlink.StructIfinfoMsg; 65 import com.android.server.connectivity.ConnectivityResources; 66 67 import java.io.FileDescriptor; 68 import java.net.InetAddress; 69 import java.net.NetworkInterface; 70 import java.net.SocketException; 71 import java.util.ArrayList; 72 import java.util.Enumeration; 73 import java.util.Iterator; 74 import java.util.List; 75 import java.util.Objects; 76 import java.util.concurrent.ConcurrentHashMap; 77 78 /** 79 * Tracks Ethernet interfaces and manages interface configurations. 80 * 81 * <p>Interfaces may have different {@link android.net.NetworkCapabilities}. This mapping is defined 82 * in {@code config_ethernet_interfaces}. Notably, some interfaces could be marked as restricted by 83 * not specifying {@link android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED} flag. 84 * Interfaces could have associated {@link android.net.IpConfiguration}. 85 * Ethernet Interfaces may be present at boot time or appear after boot (e.g., for Ethernet adapters 86 * connected over USB). This class supports multiple interfaces. When an interface appears on the 87 * system (or is present at boot time) this class will start tracking it and bring it up. Only 88 * interfaces whose names match the {@code config_ethernet_iface_regex} regular expression are 89 * tracked. 90 * 91 * <p>All public or package private methods must be thread-safe unless stated otherwise. 92 */ 93 @VisibleForTesting(visibility = PACKAGE) 94 public class EthernetTracker { 95 private static final int INTERFACE_MODE_CLIENT = 1; 96 private static final int INTERFACE_MODE_SERVER = 2; 97 98 private static final String TAG = EthernetTracker.class.getSimpleName(); 99 private static final boolean DBG = EthernetNetworkFactory.DBG; 100 101 private static final String TEST_IFACE_REGEXP = TEST_TAP_PREFIX + "\\d+"; 102 103 // TODO: consider using SharedLog consistently across ethernet service. 104 private static final SharedLog sLog = new SharedLog(TAG); 105 106 @VisibleForTesting 107 public static final NetworkCapabilities DEFAULT_CAPABILITIES = new NetworkCapabilities.Builder() 108 .addTransportType(TRANSPORT_ETHERNET) 109 .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET) 110 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED) 111 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_METERED) 112 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED) 113 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING) 114 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED) 115 .addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED) 116 // TODO: do not hardcode link bandwidth. 117 .setLinkUpstreamBandwidthKbps(100 * 1000 /* 100 Mbps */) 118 .setLinkDownstreamBandwidthKbps(100 * 1000 /* 100 Mbps */) 119 .build(); 120 121 122 /** 123 * Interface names we track. This is a product-dependent regular expression. 124 * Use isValidEthernetInterface to check if a interface name is a valid ethernet interface (this 125 * includes test interfaces if setIncludeTestInterfaces is set to true). 126 */ 127 private final String mIfaceMatch; 128 129 /** 130 * Track test interfaces if true, don't track otherwise. 131 * Volatile is needed as getEthernetInterfaceList() does not run on the handler thread. 132 */ 133 private volatile boolean mIncludeTestInterfaces = false; 134 135 /** Mapping between {iface name | mac address} -> {NetworkCapabilities} */ 136 private final ConcurrentHashMap<String, NetworkCapabilities> mNetworkCapabilities = 137 new ConcurrentHashMap<>(); 138 private final ConcurrentHashMap<String, IpConfiguration> mIpConfigurations = 139 new ConcurrentHashMap<>(); 140 141 private final Context mContext; 142 private final INetd mNetd; 143 private final Handler mHandler; 144 private final EthernetNetworkFactory mFactory; 145 private final EthernetConfigStore mConfigStore; 146 private final NetlinkMonitor mNetlinkMonitor; 147 private final Dependencies mDeps; 148 149 private final RemoteCallbackList<IEthernetServiceListener> mListeners = 150 new RemoteCallbackList<>(); 151 private final TetheredInterfaceRequestList mTetheredInterfaceRequests = 152 new TetheredInterfaceRequestList(); 153 154 // The first interface discovered is set as the mTetheringInterface. It is the interface that is 155 // returned when a tethered interface is requested; until then, it remains in client mode. Its 156 // current mode is reflected in mTetheringInterfaceMode. 157 private String mTetheringInterface; 158 // If the tethering interface is in server mode, it is not tracked by factory. The HW address 159 // must be maintained by the EthernetTracker. Its current mode is reflected in 160 // mTetheringInterfaceMode. 161 private String mTetheringInterfaceHwAddr; 162 private int mTetheringInterfaceMode = INTERFACE_MODE_CLIENT; 163 // Tracks whether clients were notified that the tethered interface is available 164 private boolean mTetheredInterfaceWasAvailable = false; 165 // Tracks the current state of ethernet as configured by EthernetManager#setEthernetEnabled. 166 private boolean mIsEthernetEnabled = true; 167 168 private class TetheredInterfaceRequestList extends 169 RemoteCallbackList<ITetheredInterfaceCallback> { 170 @Override onCallbackDied(ITetheredInterfaceCallback cb, Object cookie)171 public void onCallbackDied(ITetheredInterfaceCallback cb, Object cookie) { 172 mHandler.post(EthernetTracker.this::maybeUntetherInterface); 173 } 174 } 175 176 public static class Dependencies { getInterfaceRegexFromResource(Context context)177 public String getInterfaceRegexFromResource(Context context) { 178 final ConnectivityResources resources = new ConnectivityResources(context); 179 return resources.get().getString( 180 com.android.connectivity.resources.R.string.config_ethernet_iface_regex); 181 } 182 getInterfaceConfigFromResource(Context context)183 public String[] getInterfaceConfigFromResource(Context context) { 184 final ConnectivityResources resources = new ConnectivityResources(context); 185 return resources.get().getStringArray( 186 com.android.connectivity.resources.R.array.config_ethernet_interfaces); 187 } 188 isAtLeastB()189 public boolean isAtLeastB() { 190 return SdkLevel.isAtLeastB(); 191 } 192 } 193 194 private class EthernetNetlinkMonitor extends NetlinkMonitor { EthernetNetlinkMonitor(Handler handler)195 EthernetNetlinkMonitor(Handler handler) { 196 super(handler, sLog, EthernetNetlinkMonitor.class.getSimpleName(), 197 OsConstants.NETLINK_ROUTE, NetlinkConstants.RTMGRP_LINK); 198 } 199 onNewLink(String ifname, boolean linkUp)200 private void onNewLink(String ifname, boolean linkUp) { 201 if (!mFactory.hasInterface(ifname) && !ifname.equals(mTetheringInterface)) { 202 Log.i(TAG, "onInterfaceAdded, iface: " + ifname); 203 maybeTrackInterface(ifname); 204 } 205 Log.i(TAG, "interfaceLinkStateChanged, iface: " + ifname + ", up: " + linkUp); 206 updateInterfaceState(ifname, linkUp); 207 } 208 onDelLink(String ifname)209 private void onDelLink(String ifname) { 210 Log.i(TAG, "onInterfaceRemoved, iface: " + ifname); 211 stopTrackingInterface(ifname); 212 } 213 processRtNetlinkLinkMessage(RtNetlinkLinkMessage msg)214 private void processRtNetlinkLinkMessage(RtNetlinkLinkMessage msg) { 215 final StructIfinfoMsg ifinfomsg = msg.getIfinfoHeader(); 216 // check if the message is valid 217 if (ifinfomsg.family != OsConstants.AF_UNSPEC) return; 218 219 // ignore messages for the loopback interface 220 if ((ifinfomsg.flags & OsConstants.IFF_LOOPBACK) != 0) return; 221 222 // check if the received message applies to an ethernet interface. 223 final String ifname = msg.getInterfaceName(); 224 if (!isValidEthernetInterface(ifname)) return; 225 226 switch (msg.getHeader().nlmsg_type) { 227 case NetlinkConstants.RTM_NEWLINK: 228 final boolean linkUp = (ifinfomsg.flags & NetlinkConstants.IFF_LOWER_UP) != 0; 229 onNewLink(ifname, linkUp); 230 break; 231 232 case NetlinkConstants.RTM_DELLINK: 233 onDelLink(ifname); 234 break; 235 236 default: 237 Log.e(TAG, "Unknown rtnetlink link msg type: " + msg); 238 break; 239 } 240 } 241 242 // Note: processNetlinkMessage is called on the handler thread. 243 @Override processNetlinkMessage(NetlinkMessage nlMsg, long whenMs)244 protected void processNetlinkMessage(NetlinkMessage nlMsg, long whenMs) { 245 if (nlMsg instanceof RtNetlinkLinkMessage) { 246 processRtNetlinkLinkMessage((RtNetlinkLinkMessage) nlMsg); 247 } else { 248 Log.e(TAG, "Unknown netlink message: " + nlMsg); 249 } 250 } 251 } 252 253 EthernetTracker(@onNull final Context context, @NonNull final Handler handler, @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd)254 EthernetTracker(@NonNull final Context context, @NonNull final Handler handler, 255 @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd) { 256 this(context, handler, factory, netd, new Dependencies()); 257 } 258 259 @VisibleForTesting EthernetTracker(@onNull final Context context, @NonNull final Handler handler, @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd, @NonNull final Dependencies deps)260 EthernetTracker(@NonNull final Context context, @NonNull final Handler handler, 261 @NonNull final EthernetNetworkFactory factory, @NonNull final INetd netd, 262 @NonNull final Dependencies deps) { 263 mContext = context; 264 mHandler = handler; 265 mFactory = factory; 266 mNetd = netd; 267 mDeps = deps; 268 269 // Interface match regex. 270 String ifaceMatchRegex = mDeps.getInterfaceRegexFromResource(mContext); 271 // "*" is a magic string to indicate "pick the default". 272 if (ifaceMatchRegex.equals("*")) { 273 if (SdkLevel.isAtLeastV()) { 274 // On V+, include both usb%d and eth%d interfaces. 275 ifaceMatchRegex = "(usb|eth)\\d+"; 276 } else { 277 // On T and U, include only eth%d interfaces. 278 ifaceMatchRegex = "eth\\d+"; 279 } 280 } 281 mIfaceMatch = ifaceMatchRegex; 282 283 // Read default Ethernet interface configuration from resources 284 final String[] interfaceConfigs = mDeps.getInterfaceConfigFromResource(context); 285 for (String strConfig : interfaceConfigs) { 286 parseEthernetConfig(strConfig); 287 } 288 289 mConfigStore = new EthernetConfigStore(); 290 mNetlinkMonitor = new EthernetNetlinkMonitor(mHandler); 291 } 292 start()293 void start() { 294 mFactory.register(); 295 mConfigStore.read(); 296 297 final ArrayMap<String, IpConfiguration> configs = mConfigStore.getIpConfigurations(); 298 for (int i = 0; i < configs.size(); i++) { 299 mIpConfigurations.put(configs.keyAt(i), configs.valueAt(i)); 300 } 301 302 mHandler.post(() -> { 303 mNetlinkMonitor.start(); 304 trackAvailableInterfaces(); 305 }); 306 } 307 updateIpConfiguration(String iface, IpConfiguration ipConfiguration)308 void updateIpConfiguration(String iface, IpConfiguration ipConfiguration) { 309 if (DBG) { 310 Log.i(TAG, "updateIpConfiguration, iface: " + iface + ", cfg: " + ipConfiguration); 311 } 312 writeIpConfiguration(iface, ipConfiguration); 313 mHandler.post(() -> { 314 mFactory.updateInterface(iface, ipConfiguration, null); 315 broadcastInterfaceStateChange(iface); 316 }); 317 } 318 writeIpConfiguration(@onNull final String iface, @NonNull final IpConfiguration ipConfig)319 private void writeIpConfiguration(@NonNull final String iface, 320 @NonNull final IpConfiguration ipConfig) { 321 mConfigStore.write(iface, ipConfig); 322 mIpConfigurations.put(iface, ipConfig); 323 } 324 getIpConfigurationForCallback(String iface, int state)325 private IpConfiguration getIpConfigurationForCallback(String iface, int state) { 326 return (state == EthernetManager.STATE_ABSENT) ? null : getOrCreateIpConfiguration(iface); 327 } 328 ensureRunningOnEthernetServiceThread()329 private void ensureRunningOnEthernetServiceThread() { 330 HandlerUtils.ensureRunningOnHandlerThread(mHandler); 331 } 332 333 /** 334 * Broadcast the link state or IpConfiguration change of existing Ethernet interfaces to all 335 * listeners. 336 */ broadcastInterfaceStateChange(@onNull String iface)337 protected void broadcastInterfaceStateChange(@NonNull String iface) { 338 ensureRunningOnEthernetServiceThread(); 339 final int state = getInterfaceState(iface); 340 final int role = getInterfaceRole(iface); 341 final IpConfiguration config = getIpConfigurationForCallback(iface, state); 342 final boolean isRestricted = isRestrictedInterface(iface); 343 final int n = mListeners.beginBroadcast(); 344 for (int i = 0; i < n; i++) { 345 try { 346 if (isRestricted) { 347 final ListenerInfo info = (ListenerInfo) mListeners.getBroadcastCookie(i); 348 if (!info.canUseRestrictedNetworks) continue; 349 } 350 mListeners.getBroadcastItem(i).onInterfaceStateChanged(iface, state, role, config); 351 } catch (RemoteException e) { 352 // Do nothing here. 353 } 354 } 355 mListeners.finishBroadcast(); 356 } 357 358 /** 359 * Unicast the interface state or IpConfiguration change of existing Ethernet interfaces to a 360 * specific listener. 361 */ unicastInterfaceStateChange(@onNull IEthernetServiceListener listener, @NonNull String iface)362 protected void unicastInterfaceStateChange(@NonNull IEthernetServiceListener listener, 363 @NonNull String iface) { 364 ensureRunningOnEthernetServiceThread(); 365 final int state = getInterfaceState(iface); 366 final int role = getInterfaceRole(iface); 367 final IpConfiguration config = getIpConfigurationForCallback(iface, state); 368 try { 369 listener.onInterfaceStateChanged(iface, state, role, config); 370 } catch (RemoteException e) { 371 // Do nothing here. 372 } 373 } 374 375 @VisibleForTesting(visibility = PACKAGE) updateConfiguration(@onNull final String iface, @Nullable final IpConfiguration ipConfig, @Nullable final NetworkCapabilities capabilities, @Nullable final EthernetCallback cb)376 protected void updateConfiguration(@NonNull final String iface, 377 @Nullable final IpConfiguration ipConfig, 378 @Nullable final NetworkCapabilities capabilities, 379 @Nullable final EthernetCallback cb) { 380 if (DBG) { 381 Log.i(TAG, "updateConfiguration, iface: " + iface + ", capabilities: " + capabilities 382 + ", ipConfig: " + ipConfig); 383 } 384 385 // TODO: do the right thing if the interface was in server mode: either fail this operation, 386 // or take the interface out of server mode. 387 final IpConfiguration localIpConfig = ipConfig == null 388 ? null : new IpConfiguration(ipConfig); 389 if (ipConfig != null) { 390 writeIpConfiguration(iface, localIpConfig); 391 } 392 393 if (null != capabilities) { 394 mNetworkCapabilities.put(iface, capabilities); 395 } 396 mHandler.post(() -> { 397 mFactory.updateInterface(iface, localIpConfig, capabilities); 398 399 // only broadcast state change when the ip configuration is updated. 400 if (ipConfig != null) { 401 broadcastInterfaceStateChange(iface); 402 } 403 // Always return success. Even if the interface does not currently exist, the 404 // IpConfiguration and NetworkCapabilities were saved and will be applied if an 405 // interface with the given name is ever added. 406 cb.onResult(iface); 407 }); 408 } 409 410 /** Configure the administrative state of ethernet interface by toggling IFF_UP. */ setInterfaceEnabled(String iface, boolean enabled, EthernetCallback cb)411 public void setInterfaceEnabled(String iface, boolean enabled, EthernetCallback cb) { 412 mHandler.post(() -> setInterfaceAdministrativeState(iface, enabled, cb)); 413 } 414 getIpConfiguration(String iface)415 IpConfiguration getIpConfiguration(String iface) { 416 return mIpConfigurations.get(iface); 417 } 418 419 @VisibleForTesting(visibility = PACKAGE) isTrackingInterface(String iface)420 protected boolean isTrackingInterface(String iface) { 421 return mFactory.hasInterface(iface); 422 } 423 getAllInterfaces()424 private List<String> getAllInterfaces() { 425 final ArrayList<String> interfaces = new ArrayList<>( 426 List.of(mFactory.getAvailableInterfaces(/* includeRestricted */ true))); 427 428 if (mTetheringInterfaceMode == INTERFACE_MODE_SERVER && mTetheringInterface != null) { 429 interfaces.add(mTetheringInterface); 430 } 431 return interfaces; 432 } 433 getClientModeInterfaces(boolean includeRestricted)434 String[] getClientModeInterfaces(boolean includeRestricted) { 435 return mFactory.getAvailableInterfaces(includeRestricted); 436 } 437 getEthernetInterfaceList()438 List<String> getEthernetInterfaceList() { 439 final List<String> interfaceList = new ArrayList<String>(); 440 final Enumeration<NetworkInterface> ifaces; 441 try { 442 ifaces = NetworkInterface.getNetworkInterfaces(); 443 } catch (SocketException e) { 444 Log.e(TAG, "Failed to get ethernet interfaces: ", e); 445 return interfaceList; 446 } 447 448 // There is a possible race with setIncludeTestInterfaces() which can affect 449 // isValidEthernetInterface (it returns true for test interfaces if setIncludeTestInterfaces 450 // is set to true). 451 // setIncludeTestInterfaces() is only used in tests, and since getEthernetInterfaceList() 452 // does not run on the handler thread, the behavior around setIncludeTestInterfaces() is 453 // indeterminate either way. This can easily be circumvented by waiting on a callback from 454 // a test interface after calling setIncludeTestInterfaces() before calling this function. 455 // In production code, this has no effect. 456 while (ifaces.hasMoreElements()) { 457 NetworkInterface iface = ifaces.nextElement(); 458 if (isValidEthernetInterface(iface.getName())) interfaceList.add(iface.getName()); 459 } 460 return interfaceList; 461 } 462 463 /** 464 * Returns true if given interface was configured as restricted (doesn't have 465 * NET_CAPABILITY_NOT_RESTRICTED) capability. Otherwise, returns false. 466 */ isRestrictedInterface(String iface)467 boolean isRestrictedInterface(String iface) { 468 final NetworkCapabilities nc = mNetworkCapabilities.get(iface); 469 return nc != null && !nc.hasCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED); 470 } 471 addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks)472 void addListener(IEthernetServiceListener listener, boolean canUseRestrictedNetworks) { 473 mHandler.post(() -> { 474 if (!mListeners.register(listener, new ListenerInfo(canUseRestrictedNetworks))) { 475 // Remote process has already died 476 return; 477 } 478 for (String iface : getClientModeInterfaces(canUseRestrictedNetworks)) { 479 unicastInterfaceStateChange(listener, iface); 480 } 481 if (mTetheringInterface != null && mTetheringInterfaceMode == INTERFACE_MODE_SERVER) { 482 unicastInterfaceStateChange(listener, mTetheringInterface); 483 } 484 485 unicastEthernetStateChange(listener, mIsEthernetEnabled); 486 }); 487 } 488 removeListener(IEthernetServiceListener listener)489 void removeListener(IEthernetServiceListener listener) { 490 mHandler.post(() -> mListeners.unregister(listener)); 491 } 492 setIncludeTestInterfaces(boolean include)493 public void setIncludeTestInterfaces(boolean include) { 494 mHandler.post(() -> { 495 mIncludeTestInterfaces = include; 496 if (include) { 497 trackAvailableInterfaces(); 498 } else { 499 removeTestData(); 500 // remove all test interfaces 501 for (String iface : getAllInterfaces()) { 502 if (isValidEthernetInterface(iface)) continue; 503 stopTrackingInterface(iface); 504 } 505 } 506 }); 507 } 508 removeTestData()509 private void removeTestData() { 510 removeTestIpData(); 511 removeTestCapabilityData(); 512 } 513 removeTestIpData()514 private void removeTestIpData() { 515 final Iterator<String> iterator = mIpConfigurations.keySet().iterator(); 516 while (iterator.hasNext()) { 517 final String iface = iterator.next(); 518 if (iface.matches(TEST_IFACE_REGEXP)) { 519 mConfigStore.write(iface, null); 520 iterator.remove(); 521 } 522 } 523 } 524 removeTestCapabilityData()525 private void removeTestCapabilityData() { 526 mNetworkCapabilities.keySet().removeIf(iface -> iface.matches(TEST_IFACE_REGEXP)); 527 } 528 requestTetheredInterface(ITetheredInterfaceCallback callback)529 public void requestTetheredInterface(ITetheredInterfaceCallback callback) { 530 mHandler.post(() -> { 531 if (!mTetheredInterfaceRequests.register(callback)) { 532 // Remote process has already died 533 return; 534 } 535 if (mTetheringInterfaceMode == INTERFACE_MODE_SERVER) { 536 if (mTetheredInterfaceWasAvailable) { 537 notifyTetheredInterfaceAvailable(callback, mTetheringInterface); 538 } 539 return; 540 } 541 542 setTetheringInterfaceMode(INTERFACE_MODE_SERVER); 543 }); 544 } 545 releaseTetheredInterface(ITetheredInterfaceCallback callback)546 public void releaseTetheredInterface(ITetheredInterfaceCallback callback) { 547 mHandler.post(() -> { 548 mTetheredInterfaceRequests.unregister(callback); 549 maybeUntetherInterface(); 550 }); 551 } 552 notifyTetheredInterfaceAvailable(ITetheredInterfaceCallback cb, String iface)553 private void notifyTetheredInterfaceAvailable(ITetheredInterfaceCallback cb, String iface) { 554 try { 555 cb.onAvailable(iface); 556 } catch (RemoteException e) { 557 Log.e(TAG, "Error sending tethered interface available callback", e); 558 } 559 } 560 notifyTetheredInterfaceUnavailable(ITetheredInterfaceCallback cb)561 private void notifyTetheredInterfaceUnavailable(ITetheredInterfaceCallback cb) { 562 try { 563 cb.onUnavailable(); 564 } catch (RemoteException e) { 565 Log.e(TAG, "Error sending tethered interface available callback", e); 566 } 567 } 568 maybeUntetherInterface()569 private void maybeUntetherInterface() { 570 if (mTetheredInterfaceRequests.getRegisteredCallbackCount() > 0) return; 571 if (mTetheringInterfaceMode == INTERFACE_MODE_CLIENT) return; 572 setTetheringInterfaceMode(INTERFACE_MODE_CLIENT); 573 } 574 setTetheringInterfaceMode(int mode)575 private void setTetheringInterfaceMode(int mode) { 576 Log.d(TAG, "Setting tethering interface mode to " + mode); 577 mTetheringInterfaceMode = mode; 578 if (mTetheringInterface != null) { 579 removeInterface(mTetheringInterface); 580 addInterface(mTetheringInterface); 581 // when this broadcast is sent, any calls to notifyTetheredInterfaceAvailable or 582 // notifyTetheredInterfaceUnavailable have already happened 583 broadcastInterfaceStateChange(mTetheringInterface); 584 } 585 } 586 getInterfaceState(final String iface)587 private int getInterfaceState(final String iface) { 588 if (mFactory.hasInterface(iface)) { 589 return mFactory.getInterfaceState(iface); 590 } 591 if (getInterfaceMode(iface) == INTERFACE_MODE_SERVER) { 592 // server mode interfaces are not tracked by the factory. 593 // TODO(b/234743836): interface state for server mode interfaces is not tracked 594 // properly; just return link up. 595 return EthernetManager.STATE_LINK_UP; 596 } 597 return EthernetManager.STATE_ABSENT; 598 } 599 getInterfaceRole(final String iface)600 private int getInterfaceRole(final String iface) { 601 if (mFactory.hasInterface(iface)) { 602 // only client mode interfaces are tracked by the factory. 603 return EthernetManager.ROLE_CLIENT; 604 } 605 if (getInterfaceMode(iface) == INTERFACE_MODE_SERVER) { 606 return EthernetManager.ROLE_SERVER; 607 } 608 return EthernetManager.ROLE_NONE; 609 } 610 getInterfaceMode(final String iface)611 private int getInterfaceMode(final String iface) { 612 if (iface.equals(mTetheringInterface)) { 613 return mTetheringInterfaceMode; 614 } 615 return INTERFACE_MODE_CLIENT; 616 } 617 removeInterface(String iface)618 private void removeInterface(String iface) { 619 mFactory.removeInterface(iface); 620 maybeUpdateServerModeInterfaceState(iface, false); 621 } 622 stopTrackingInterface(String iface)623 private void stopTrackingInterface(String iface) { 624 removeInterface(iface); 625 if (iface.equals(mTetheringInterface)) { 626 mTetheringInterface = null; 627 mTetheringInterfaceHwAddr = null; 628 } 629 broadcastInterfaceStateChange(iface); 630 } 631 addInterface(String iface)632 private void addInterface(String iface) { 633 InterfaceConfigurationParcel config = null; 634 // Bring up the interface so we get link status indications. 635 try { 636 // Read the flags before attempting to bring up the interface. If the interface is 637 // already running an UP event is created after adding the interface. 638 config = NetdUtils.getInterfaceConfigParcel(mNetd, iface); 639 // Only bring the interface up when ethernet is enabled, otherwise set interface down. 640 setInterfaceUpState(iface, mIsEthernetEnabled); 641 } catch (IllegalStateException e) { 642 // Either the system is crashing or the interface has disappeared. Just ignore the 643 // error; we haven't modified any state because we only do that if our calls succeed. 644 Log.e(TAG, "Error upping interface " + iface, e); 645 } 646 647 if (config == null) { 648 Log.e(TAG, "Null interface config parcelable for " + iface + ". Bailing out."); 649 return; 650 } 651 652 final String hwAddress = config.hwAddr; 653 654 if (getInterfaceMode(iface) == INTERFACE_MODE_SERVER) { 655 maybeUpdateServerModeInterfaceState(iface, true); 656 mTetheringInterfaceHwAddr = hwAddress; 657 return; 658 } 659 660 NetworkCapabilities nc = mNetworkCapabilities.get(iface); 661 if (nc == null) { 662 // Try to resolve using mac address 663 nc = mNetworkCapabilities.get(hwAddress); 664 if (nc == null) { 665 final boolean isTestIface = iface.matches(TEST_IFACE_REGEXP); 666 nc = createDefaultNetworkCapabilities(isTestIface); 667 } 668 } 669 670 IpConfiguration ipConfiguration = getOrCreateIpConfiguration(iface); 671 Log.d(TAG, "Tracking interface in client mode: " + iface); 672 mFactory.addInterface(iface, hwAddress, ipConfiguration, nc); 673 674 // Note: if the interface already has link (e.g., if we crashed and got 675 // restarted while it was running), we need to fake a link up notification so we 676 // start configuring it. 677 if (NetdUtils.hasFlag(config, INetd.IF_FLAG_RUNNING)) { 678 // no need to send an interface state change as this is not a true "state change". The 679 // callers (maybeTrackInterface() and setTetheringInterfaceMode()) already broadcast the 680 // state change. 681 mFactory.updateInterfaceLinkState(iface, true); 682 } 683 } 684 setInterfaceAdministrativeState(String iface, boolean up, EthernetCallback cb)685 private void setInterfaceAdministrativeState(String iface, boolean up, EthernetCallback cb) { 686 if (!mIsEthernetEnabled) { 687 cb.onError("Cannot enable/disable interface when ethernet is disabled"); 688 return; 689 } 690 if (getInterfaceState(iface) == EthernetManager.STATE_ABSENT) { 691 cb.onError("Failed to enable/disable absent interface: " + iface); 692 return; 693 } 694 if (getInterfaceRole(iface) == EthernetManager.ROLE_SERVER) { 695 // TODO: support setEthernetState for server mode interfaces. 696 cb.onError("Failed to enable/disable interface in server mode: " + iface); 697 return; 698 } 699 700 setInterfaceUpState(iface, up); 701 cb.onResult(iface); 702 } 703 updateInterfaceState(String iface, boolean up)704 private void updateInterfaceState(String iface, boolean up) { 705 final int mode = getInterfaceMode(iface); 706 if (mode == INTERFACE_MODE_SERVER) { 707 // TODO: support tracking link state for interfaces in server mode. 708 return; 709 } 710 711 // If updateInterfaceLinkState returns false, the interface is already in the correct state. 712 if (mFactory.updateInterfaceLinkState(iface, up)) { 713 broadcastInterfaceStateChange(iface); 714 } 715 } 716 maybeUpdateServerModeInterfaceState(String iface, boolean available)717 private void maybeUpdateServerModeInterfaceState(String iface, boolean available) { 718 if (available == mTetheredInterfaceWasAvailable || !iface.equals(mTetheringInterface)) { 719 return; 720 } 721 722 Log.d(TAG, (available ? "Tracking" : "No longer tracking") 723 + " interface in server mode: " + iface); 724 725 final int pendingCbs = mTetheredInterfaceRequests.beginBroadcast(); 726 for (int i = 0; i < pendingCbs; i++) { 727 ITetheredInterfaceCallback item = mTetheredInterfaceRequests.getBroadcastItem(i); 728 if (available) { 729 notifyTetheredInterfaceAvailable(item, iface); 730 } else { 731 notifyTetheredInterfaceUnavailable(item); 732 } 733 } 734 mTetheredInterfaceRequests.finishBroadcast(); 735 mTetheredInterfaceWasAvailable = available; 736 } 737 maybeTrackInterface(String iface)738 private void maybeTrackInterface(String iface) { 739 // If we don't already track this interface, and if this interface matches 740 // our regex, start tracking it. 741 if (mFactory.hasInterface(iface) || iface.equals(mTetheringInterface)) { 742 if (DBG) Log.w(TAG, "Ignoring already-tracked interface " + iface); 743 return; 744 } 745 if (DBG) Log.i(TAG, "maybeTrackInterface: " + iface); 746 747 // Do not use an interface for tethering if it has configured NetworkCapabilities. 748 if (mTetheringInterface == null && !mNetworkCapabilities.containsKey(iface)) { 749 mTetheringInterface = iface; 750 } 751 752 addInterface(iface); 753 754 broadcastInterfaceStateChange(iface); 755 } 756 trackAvailableInterfaces()757 private void trackAvailableInterfaces() { 758 final List<String> ifaces = getEthernetInterfaceList(); 759 for (String iface : ifaces) { 760 maybeTrackInterface(iface); 761 } 762 } 763 764 private static class ListenerInfo { 765 766 boolean canUseRestrictedNetworks = false; 767 ListenerInfo(boolean canUseRestrictedNetworks)768 ListenerInfo(boolean canUseRestrictedNetworks) { 769 this.canUseRestrictedNetworks = canUseRestrictedNetworks; 770 } 771 } 772 773 /** 774 * Parses an Ethernet interface configuration 775 * 776 * @param configString represents an Ethernet configuration in the following format: {@code 777 * <interface name|mac address>;[Network Capabilities];[IP config];[Override Transport]} 778 */ parseEthernetConfig(String configString)779 private void parseEthernetConfig(String configString) { 780 final EthernetConfigParser config = 781 new EthernetConfigParser(configString, mDeps.isAtLeastB()); 782 mNetworkCapabilities.put(config.mIface, config.mCaps); 783 784 if (null != config.mIpConfig) { 785 IpConfiguration ipConfig = parseStaticIpConfiguration(config.mIpConfig); 786 mIpConfigurations.put(config.mIface, ipConfig); 787 } 788 } 789 createDefaultNetworkCapabilities(boolean isTestIface)790 private static NetworkCapabilities createDefaultNetworkCapabilities(boolean isTestIface) { 791 final NetworkCapabilities.Builder builder = 792 new NetworkCapabilities.Builder(DEFAULT_CAPABILITIES); 793 if (isTestIface) { 794 builder.addTransportType(NetworkCapabilities.TRANSPORT_TEST); 795 // TODO: do not remove INTERNET capability for test networks. 796 builder.removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET); 797 } 798 799 return builder.build(); 800 } 801 802 /** 803 * Parses static IP configuration. 804 * 805 * @param staticIpConfig represents static IP configuration in the following format: {@code 806 * ip=<ip-address/mask> gateway=<ip-address> dns=<comma-sep-ip-addresses> 807 * domains=<comma-sep-domains>} 808 */ 809 @VisibleForTesting parseStaticIpConfiguration(String staticIpConfig)810 static IpConfiguration parseStaticIpConfiguration(String staticIpConfig) { 811 final StaticIpConfiguration.Builder staticIpConfigBuilder = 812 new StaticIpConfiguration.Builder(); 813 814 for (String keyValueAsString : staticIpConfig.trim().split(" ")) { 815 if (TextUtils.isEmpty(keyValueAsString)) continue; 816 817 String[] pair = keyValueAsString.split("="); 818 if (pair.length != 2) { 819 throw new IllegalArgumentException("Unexpected token: " + keyValueAsString 820 + " in " + staticIpConfig); 821 } 822 823 String key = pair[0]; 824 String value = pair[1]; 825 826 switch (key) { 827 case "ip": 828 staticIpConfigBuilder.setIpAddress(new LinkAddress(value)); 829 break; 830 case "domains": 831 staticIpConfigBuilder.setDomains(value); 832 break; 833 case "gateway": 834 staticIpConfigBuilder.setGateway(InetAddress.parseNumericAddress(value)); 835 break; 836 case "dns": { 837 ArrayList<InetAddress> dnsAddresses = new ArrayList<>(); 838 for (String address: value.split(",")) { 839 dnsAddresses.add(InetAddress.parseNumericAddress(address)); 840 } 841 staticIpConfigBuilder.setDnsServers(dnsAddresses); 842 break; 843 } 844 default : { 845 throw new IllegalArgumentException("Unexpected key: " + key 846 + " in " + staticIpConfig); 847 } 848 } 849 } 850 return createIpConfiguration(staticIpConfigBuilder.build()); 851 } 852 createIpConfiguration( @onNull final StaticIpConfiguration staticIpConfig)853 private static IpConfiguration createIpConfiguration( 854 @NonNull final StaticIpConfiguration staticIpConfig) { 855 return new IpConfiguration.Builder().setStaticIpConfiguration(staticIpConfig).build(); 856 } 857 getOrCreateIpConfiguration(String iface)858 private IpConfiguration getOrCreateIpConfiguration(String iface) { 859 IpConfiguration ret = mIpConfigurations.get(iface); 860 if (ret != null) return ret; 861 ret = new IpConfiguration(); 862 ret.setIpAssignment(IpAssignment.DHCP); 863 ret.setProxySettings(ProxySettings.NONE); 864 return ret; 865 } 866 isValidEthernetInterface(String iface)867 private boolean isValidEthernetInterface(String iface) { 868 return iface.matches(mIfaceMatch) || isValidTestInterface(iface); 869 } 870 871 /** 872 * Validate if a given interface is valid for testing. 873 * 874 * @param iface the name of the interface to validate. 875 * @return {@code true} if test interfaces are enabled and the given {@code iface} has a test 876 * interface prefix, {@code false} otherwise. 877 */ isValidTestInterface(@onNull final String iface)878 public boolean isValidTestInterface(@NonNull final String iface) { 879 return mIncludeTestInterfaces && iface.matches(TEST_IFACE_REGEXP); 880 } 881 postAndWaitForRunnable(Runnable r)882 private void postAndWaitForRunnable(Runnable r) { 883 final ConditionVariable cv = new ConditionVariable(); 884 if (mHandler.post(() -> { 885 r.run(); 886 cv.open(); 887 })) { 888 cv.block(2000L); 889 } 890 } 891 892 @VisibleForTesting(visibility = PACKAGE) setEthernetEnabled(boolean enabled)893 protected void setEthernetEnabled(boolean enabled) { 894 mHandler.post(() -> { 895 if (mIsEthernetEnabled == enabled) return; 896 897 mIsEthernetEnabled = enabled; 898 for (String iface : getAllInterfaces()) { 899 setInterfaceUpState(iface, enabled); 900 } 901 broadcastEthernetStateChange(mIsEthernetEnabled); 902 }); 903 } 904 isEthernetEnabledAsInt(boolean state)905 private int isEthernetEnabledAsInt(boolean state) { 906 return state ? ETHERNET_STATE_ENABLED : ETHERNET_STATE_DISABLED; 907 } 908 unicastEthernetStateChange(@onNull IEthernetServiceListener listener, boolean enabled)909 private void unicastEthernetStateChange(@NonNull IEthernetServiceListener listener, 910 boolean enabled) { 911 ensureRunningOnEthernetServiceThread(); 912 try { 913 listener.onEthernetStateChanged(isEthernetEnabledAsInt(enabled)); 914 } catch (RemoteException e) { 915 // Do nothing here. 916 } 917 } 918 broadcastEthernetStateChange(boolean enabled)919 private void broadcastEthernetStateChange(boolean enabled) { 920 ensureRunningOnEthernetServiceThread(); 921 final int n = mListeners.beginBroadcast(); 922 for (int i = 0; i < n; i++) { 923 try { 924 mListeners.getBroadcastItem(i) 925 .onEthernetStateChanged(isEthernetEnabledAsInt(enabled)); 926 } catch (RemoteException e) { 927 // Do nothing here. 928 } 929 } 930 mListeners.finishBroadcast(); 931 } 932 setInterfaceUpState(@onNull String interfaceName, boolean up)933 private void setInterfaceUpState(@NonNull String interfaceName, boolean up) { 934 if (!NetlinkUtils.setInterfaceFlags(interfaceName, up ? IFF_UP : ~IFF_UP)) { 935 Log.e(TAG, "Failed to set interface " + interfaceName + (up ? " up" : " down")); 936 } 937 } 938 dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args)939 void dump(FileDescriptor fd, IndentingPrintWriter pw, String[] args) { 940 postAndWaitForRunnable(() -> { 941 pw.println(getClass().getSimpleName()); 942 pw.println("Ethernet State: " 943 + (mIsEthernetEnabled ? "enabled" : "disabled")); 944 pw.println("Ethernet interface name filter: " + mIfaceMatch); 945 pw.println("Interface used for tethering: " + mTetheringInterface); 946 pw.println("Tethering interface mode: " + mTetheringInterfaceMode); 947 pw.println("Tethered interface requests: " 948 + mTetheredInterfaceRequests.getRegisteredCallbackCount()); 949 pw.println("Listeners: " + mListeners.getRegisteredCallbackCount()); 950 pw.println("IP Configurations:"); 951 pw.increaseIndent(); 952 for (String iface : mIpConfigurations.keySet()) { 953 pw.println(iface + ": " + mIpConfigurations.get(iface)); 954 } 955 pw.decreaseIndent(); 956 pw.println(); 957 958 pw.println("Network Capabilities:"); 959 pw.increaseIndent(); 960 for (String iface : mNetworkCapabilities.keySet()) { 961 pw.println(iface + ": " + mNetworkCapabilities.get(iface)); 962 } 963 pw.decreaseIndent(); 964 pw.println(); 965 966 mFactory.dump(fd, pw, args); 967 }); 968 } 969 970 @VisibleForTesting 971 static class EthernetConfigParser { 972 final String mIface; 973 final NetworkCapabilities mCaps; 974 final String mIpConfig; 975 parseCapabilities(@ullable String capabilitiesString, boolean isAtLeastB)976 private static NetworkCapabilities parseCapabilities(@Nullable String capabilitiesString, 977 boolean isAtLeastB) { 978 final NetworkCapabilities.Builder builder = 979 NetworkCapabilities.Builder.withoutDefaultCapabilities(); 980 builder.setLinkUpstreamBandwidthKbps(100 * 1000 /* 100 Mbps */); 981 builder.setLinkDownstreamBandwidthKbps(100 * 1000 /* 100 Mbps */); 982 // Ethernet networks have no way to update the following capabilities, so they always 983 // have them. 984 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING); 985 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED); 986 builder.addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED); 987 988 if (capabilitiesString == null) { 989 return builder.build(); 990 } 991 992 if (isAtLeastB && capabilitiesString.equals("*")) { 993 // On Android B+, a "*" string defaults to the same set of default 994 // capabilities assigned to unconfigured interfaces. 995 // Note that the transport type is populated later with the result of 996 // parseTransportType(). 997 return new NetworkCapabilities.Builder(DEFAULT_CAPABILITIES) 998 .removeTransportType(NetworkCapabilities.TRANSPORT_ETHERNET) 999 .build(); 1000 } 1001 1002 for (String strNetworkCapability : capabilitiesString.split(",")) { 1003 if (TextUtils.isEmpty(strNetworkCapability)) { 1004 continue; 1005 } 1006 final Integer capability; 1007 try { 1008 builder.addCapability(Integer.valueOf(strNetworkCapability)); 1009 } catch (NumberFormatException e) { 1010 Log.e(TAG, "Failed to parse capability: " + strNetworkCapability, e); 1011 continue; 1012 } 1013 } 1014 return builder.build(); 1015 } 1016 parseTransportType(@ullable String transportString)1017 private static int parseTransportType(@Nullable String transportString) { 1018 if (TextUtils.isEmpty(transportString)) { 1019 return TRANSPORT_ETHERNET; 1020 } 1021 1022 final int parsedTransport; 1023 try { 1024 parsedTransport = Integer.valueOf(transportString); 1025 } catch (NumberFormatException e) { 1026 Log.e(TAG, "Failed to parse transport type", e); 1027 return TRANSPORT_ETHERNET; 1028 } 1029 1030 if (!NetworkCapabilities.isValidTransport(parsedTransport)) { 1031 return TRANSPORT_ETHERNET; 1032 } 1033 1034 switch (parsedTransport) { 1035 case TRANSPORT_VPN: 1036 case TRANSPORT_WIFI_AWARE: 1037 case TRANSPORT_LOWPAN: 1038 Log.e(TAG, "Unsupported transport type '" + parsedTransport + "'"); 1039 return TRANSPORT_ETHERNET; 1040 default: 1041 return parsedTransport; 1042 } 1043 } 1044 EthernetConfigParser(String configString, boolean isAtLeastB)1045 EthernetConfigParser(String configString, boolean isAtLeastB) { 1046 Objects.requireNonNull(configString, "EthernetConfigParser requires non-null config"); 1047 final String[] tokens = configString.split(";", /* limit of tokens */ 4); 1048 mIface = tokens[0]; 1049 1050 final NetworkCapabilities nc = 1051 parseCapabilities(tokens.length > 1 ? tokens[1] : null, isAtLeastB); 1052 final int transportType = parseTransportType(tokens.length > 3 ? tokens[3] : null); 1053 nc.addTransportType(transportType); 1054 mCaps = nc; 1055 1056 mIpConfig = tokens.length > 2 && !TextUtils.isEmpty(tokens[2]) ? tokens[2] : null; 1057 } 1058 } 1059 } 1060