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