• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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