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