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