1 /*
2  * Copyright (C) 2016 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 android.net.ip;
18 
19 import static android.net.NetworkUtils.numericToInetAddress;
20 import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS;
21 import static android.net.util.NetworkConstants.FF;
22 import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH;
23 import static android.net.util.NetworkConstants.asByte;
24 
25 import android.net.ConnectivityManager;
26 import android.net.INetd;
27 import android.net.INetworkStackStatusCallback;
28 import android.net.INetworkStatsService;
29 import android.net.InterfaceConfiguration;
30 import android.net.IpPrefix;
31 import android.net.LinkAddress;
32 import android.net.LinkProperties;
33 import android.net.NetworkStackClient;
34 import android.net.RouteInfo;
35 import android.net.dhcp.DhcpServerCallbacks;
36 import android.net.dhcp.DhcpServingParamsParcel;
37 import android.net.dhcp.DhcpServingParamsParcelExt;
38 import android.net.dhcp.IDhcpServer;
39 import android.net.ip.RouterAdvertisementDaemon.RaParams;
40 import android.net.util.InterfaceParams;
41 import android.net.util.InterfaceSet;
42 import android.net.util.NetdService;
43 import android.net.util.SharedLog;
44 import android.os.INetworkManagementService;
45 import android.os.Looper;
46 import android.os.Message;
47 import android.os.RemoteException;
48 import android.os.ServiceSpecificException;
49 import android.util.Log;
50 import android.util.Slog;
51 import android.util.SparseArray;
52 
53 import com.android.internal.util.MessageUtils;
54 import com.android.internal.util.Protocol;
55 import com.android.internal.util.State;
56 import com.android.internal.util.StateMachine;
57 
58 import java.net.Inet4Address;
59 import java.net.Inet6Address;
60 import java.net.InetAddress;
61 import java.net.UnknownHostException;
62 import java.util.ArrayList;
63 import java.util.HashSet;
64 import java.util.Objects;
65 import java.util.Random;
66 import java.util.Set;
67 
68 /**
69  * Provides the interface to IP-layer serving functionality for a given network
70  * interface, e.g. for tethering or "local-only hotspot" mode.
71  *
72  * @hide
73  */
74 public class IpServer extends StateMachine {
75     public static final int STATE_UNAVAILABLE = 0;
76     public static final int STATE_AVAILABLE   = 1;
77     public static final int STATE_TETHERED    = 2;
78     public static final int STATE_LOCAL_ONLY  = 3;
79 
getStateString(int state)80     public static String getStateString(int state) {
81         switch (state) {
82             case STATE_UNAVAILABLE: return "UNAVAILABLE";
83             case STATE_AVAILABLE:   return "AVAILABLE";
84             case STATE_TETHERED:    return "TETHERED";
85             case STATE_LOCAL_ONLY:  return "LOCAL_ONLY";
86         }
87         return "UNKNOWN: " + state;
88     }
89 
90     private static final byte DOUG_ADAMS = (byte) 42;
91 
92     private static final String USB_NEAR_IFACE_ADDR = "192.168.42.129";
93     private static final int USB_PREFIX_LENGTH = 24;
94     private static final String WIFI_HOST_IFACE_ADDR = "192.168.43.1";
95     private static final int WIFI_HOST_IFACE_PREFIX_LENGTH = 24;
96 
97     // TODO: have PanService use some visible version of this constant
98     private static final String BLUETOOTH_IFACE_ADDR = "192.168.44.1";
99     private static final int BLUETOOTH_DHCP_PREFIX_LENGTH = 24;
100 
101     // TODO: have this configurable
102     private static final int DHCP_LEASE_TIME_SECS = 3600;
103 
104     private final static String TAG = "IpServer";
105     private final static boolean DBG = false;
106     private final static boolean VDBG = false;
107     private static final Class[] messageClasses = {
108             IpServer.class
109     };
110     private static final SparseArray<String> sMagicDecoderRing =
111             MessageUtils.findMessageNames(messageClasses);
112 
113     public static class Callback {
114         /**
115          * Notify that |who| has changed its tethering state.
116          *
117          * @param who the calling instance of IpServer
118          * @param state one of STATE_*
119          * @param lastError one of ConnectivityManager.TETHER_ERROR_*
120          */
updateInterfaceState(IpServer who, int state, int lastError)121         public void updateInterfaceState(IpServer who, int state, int lastError) {}
122 
123         /**
124          * Notify that |who| has new LinkProperties.
125          *
126          * @param who the calling instance of IpServer
127          * @param newLp the new LinkProperties to report
128          */
updateLinkProperties(IpServer who, LinkProperties newLp)129         public void updateLinkProperties(IpServer who, LinkProperties newLp) {}
130     }
131 
132     public static class Dependencies {
getRouterAdvertisementDaemon(InterfaceParams ifParams)133         public RouterAdvertisementDaemon getRouterAdvertisementDaemon(InterfaceParams ifParams) {
134             return new RouterAdvertisementDaemon(ifParams);
135         }
136 
getInterfaceParams(String ifName)137         public InterfaceParams getInterfaceParams(String ifName) {
138             return InterfaceParams.getByName(ifName);
139         }
140 
getNetdService()141         public INetd getNetdService() {
142             return NetdService.getInstance();
143         }
144 
145         /**
146          * Create a DhcpServer instance to be used by IpServer.
147          */
makeDhcpServer(String ifName, DhcpServingParamsParcel params, DhcpServerCallbacks cb)148         public void makeDhcpServer(String ifName, DhcpServingParamsParcel params,
149                 DhcpServerCallbacks cb) {
150             NetworkStackClient.getInstance().makeDhcpServer(ifName, params, cb);
151         }
152     }
153 
154     private static final int BASE_IFACE              = Protocol.BASE_TETHERING + 100;
155     // request from the user that it wants to tether
156     public static final int CMD_TETHER_REQUESTED            = BASE_IFACE + 2;
157     // request from the user that it wants to untether
158     public static final int CMD_TETHER_UNREQUESTED          = BASE_IFACE + 3;
159     // notification that this interface is down
160     public static final int CMD_INTERFACE_DOWN              = BASE_IFACE + 4;
161     // notification from the master SM that it had trouble enabling IP Forwarding
162     public static final int CMD_IP_FORWARDING_ENABLE_ERROR  = BASE_IFACE + 7;
163     // notification from the master SM that it had trouble disabling IP Forwarding
164     public static final int CMD_IP_FORWARDING_DISABLE_ERROR = BASE_IFACE + 8;
165     // notification from the master SM that it had trouble starting tethering
166     public static final int CMD_START_TETHERING_ERROR       = BASE_IFACE + 9;
167     // notification from the master SM that it had trouble stopping tethering
168     public static final int CMD_STOP_TETHERING_ERROR        = BASE_IFACE + 10;
169     // notification from the master SM that it had trouble setting the DNS forwarders
170     public static final int CMD_SET_DNS_FORWARDERS_ERROR    = BASE_IFACE + 11;
171     // the upstream connection has changed
172     public static final int CMD_TETHER_CONNECTION_CHANGED   = BASE_IFACE + 12;
173     // new IPv6 tethering parameters need to be processed
174     public static final int CMD_IPV6_TETHER_UPDATE          = BASE_IFACE + 13;
175 
176     private final State mInitialState;
177     private final State mLocalHotspotState;
178     private final State mTetheredState;
179     private final State mUnavailableState;
180 
181     private final SharedLog mLog;
182     private final INetworkManagementService mNMService;
183     private final INetd mNetd;
184     private final INetworkStatsService mStatsService;
185     private final Callback mCallback;
186     private final InterfaceController mInterfaceCtrl;
187 
188     private final String mIfaceName;
189     private final int mInterfaceType;
190     private final LinkProperties mLinkProperties;
191     private final boolean mUsingLegacyDhcp;
192 
193     private final Dependencies mDeps;
194 
195     private int mLastError;
196     private int mServingMode;
197     private InterfaceSet mUpstreamIfaceSet;  // may change over time
198     private InterfaceParams mInterfaceParams;
199     // TODO: De-duplicate this with mLinkProperties above. Currently, these link
200     // properties are those selected by the IPv6TetheringCoordinator and relayed
201     // to us. By comparison, mLinkProperties contains the addresses and directly
202     // connected routes that have been formed from these properties iff. we have
203     // succeeded in configuring them and are able to announce them within Router
204     // Advertisements (otherwise, we do not add them to mLinkProperties at all).
205     private LinkProperties mLastIPv6LinkProperties;
206     private RouterAdvertisementDaemon mRaDaemon;
207 
208     // To be accessed only on the handler thread
209     private int mDhcpServerStartIndex = 0;
210     private IDhcpServer mDhcpServer;
211     private RaParams mLastRaParams;
212 
IpServer( String ifaceName, Looper looper, int interfaceType, SharedLog log, INetworkManagementService nMService, INetworkStatsService statsService, Callback callback, boolean usingLegacyDhcp, Dependencies deps)213     public IpServer(
214             String ifaceName, Looper looper, int interfaceType, SharedLog log,
215             INetworkManagementService nMService, INetworkStatsService statsService,
216             Callback callback, boolean usingLegacyDhcp, Dependencies deps) {
217         super(ifaceName, looper);
218         mLog = log.forSubComponent(ifaceName);
219         mNMService = nMService;
220         mNetd = deps.getNetdService();
221         mStatsService = statsService;
222         mCallback = callback;
223         mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog);
224         mIfaceName = ifaceName;
225         mInterfaceType = interfaceType;
226         mLinkProperties = new LinkProperties();
227         mUsingLegacyDhcp = usingLegacyDhcp;
228         mDeps = deps;
229         resetLinkProperties();
230         mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
231         mServingMode = STATE_AVAILABLE;
232 
233         mInitialState = new InitialState();
234         mLocalHotspotState = new LocalHotspotState();
235         mTetheredState = new TetheredState();
236         mUnavailableState = new UnavailableState();
237         addState(mInitialState);
238         addState(mLocalHotspotState);
239         addState(mTetheredState);
240         addState(mUnavailableState);
241 
242         setInitialState(mInitialState);
243     }
244 
interfaceName()245     public String interfaceName() { return mIfaceName; }
246 
interfaceType()247     public int interfaceType() { return mInterfaceType; }
248 
lastError()249     public int lastError() { return mLastError; }
250 
servingMode()251     public int servingMode() { return mServingMode; }
252 
linkProperties()253     public LinkProperties linkProperties() { return new LinkProperties(mLinkProperties); }
254 
stop()255     public void stop() { sendMessage(CMD_INTERFACE_DOWN); }
256 
unwanted()257     public void unwanted() { sendMessage(CMD_TETHER_UNREQUESTED); }
258 
259     /**
260      * Internals.
261      */
262 
startIPv4()263     private boolean startIPv4() { return configureIPv4(true); }
264 
265     /**
266      * Convenience wrapper around INetworkStackStatusCallback to run callbacks on the IpServer
267      * handler.
268      *
269      * <p>Different instances of this class can be created for each call to IDhcpServer methods,
270      * with different implementations of the callback, to differentiate handling of success/error in
271      * each call.
272      */
273     private abstract class OnHandlerStatusCallback extends INetworkStackStatusCallback.Stub {
274         @Override
onStatusAvailable(int statusCode)275         public void onStatusAvailable(int statusCode) {
276             getHandler().post(() -> callback(statusCode));
277         }
278 
callback(int statusCode)279         public abstract void callback(int statusCode);
280 
281         @Override
getInterfaceVersion()282         public int getInterfaceVersion() {
283             return this.VERSION;
284         }
285     }
286 
287     private class DhcpServerCallbacksImpl extends DhcpServerCallbacks {
288         private final int mStartIndex;
289 
DhcpServerCallbacksImpl(int startIndex)290         private DhcpServerCallbacksImpl(int startIndex) {
291             mStartIndex = startIndex;
292         }
293 
294         @Override
onDhcpServerCreated(int statusCode, IDhcpServer server)295         public void onDhcpServerCreated(int statusCode, IDhcpServer server) throws RemoteException {
296             getHandler().post(() -> {
297                 // We are on the handler thread: mDhcpServerStartIndex can be read safely.
298                 if (mStartIndex != mDhcpServerStartIndex) {
299                     // This start request is obsolete. When the |server| binder token goes out of
300                     // scope, the garbage collector will finalize it, which causes the network stack
301                     // process garbage collector to collect the server itself.
302                     return;
303                 }
304 
305                 if (statusCode != STATUS_SUCCESS) {
306                     mLog.e("Error obtaining DHCP server: " + statusCode);
307                     handleError();
308                     return;
309                 }
310 
311                 mDhcpServer = server;
312                 try {
313                     mDhcpServer.start(new OnHandlerStatusCallback() {
314                         @Override
315                         public void callback(int startStatusCode) {
316                             if (startStatusCode != STATUS_SUCCESS) {
317                                 mLog.e("Error starting DHCP server: " + startStatusCode);
318                                 handleError();
319                             }
320                         }
321                     });
322                 } catch (RemoteException e) {
323                     e.rethrowFromSystemServer();
324                 }
325             });
326         }
327 
handleError()328         private void handleError() {
329             mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR;
330             transitionTo(mInitialState);
331         }
332     }
333 
startDhcp(Inet4Address addr, int prefixLen)334     private boolean startDhcp(Inet4Address addr, int prefixLen) {
335         if (mUsingLegacyDhcp) {
336             return true;
337         }
338         final DhcpServingParamsParcel params;
339         params = new DhcpServingParamsParcelExt()
340                 .setDefaultRouters(addr)
341                 .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS)
342                 .setDnsServers(addr)
343                 .setServerAddr(new LinkAddress(addr, prefixLen))
344                 .setMetered(true);
345         // TODO: also advertise link MTU
346 
347         mDhcpServerStartIndex++;
348         mDeps.makeDhcpServer(
349                 mIfaceName, params, new DhcpServerCallbacksImpl(mDhcpServerStartIndex));
350         return true;
351     }
352 
stopDhcp()353     private void stopDhcp() {
354         // Make all previous start requests obsolete so servers are not started later
355         mDhcpServerStartIndex++;
356 
357         if (mDhcpServer != null) {
358             try {
359                 mDhcpServer.stop(new OnHandlerStatusCallback() {
360                     @Override
361                     public void callback(int statusCode) {
362                         if (statusCode != STATUS_SUCCESS) {
363                             mLog.e("Error stopping DHCP server: " + statusCode);
364                             mLastError = ConnectivityManager.TETHER_ERROR_DHCPSERVER_ERROR;
365                             // Not much more we can do here
366                         }
367                     }
368                 });
369                 mDhcpServer = null;
370             } catch (RemoteException e) {
371                 e.rethrowFromSystemServer();
372             }
373         }
374     }
375 
configureDhcp(boolean enable, Inet4Address addr, int prefixLen)376     private boolean configureDhcp(boolean enable, Inet4Address addr, int prefixLen) {
377         if (enable) {
378             return startDhcp(addr, prefixLen);
379         } else {
380             stopDhcp();
381             return true;
382         }
383     }
384 
stopIPv4()385     private void stopIPv4() {
386         configureIPv4(false);
387         // NOTE: All of configureIPv4() will be refactored out of existence
388         // into calls to InterfaceController, shared with startIPv4().
389         mInterfaceCtrl.clearIPv4Address();
390     }
391 
392     // TODO: Refactor this in terms of calls to InterfaceController.
configureIPv4(boolean enabled)393     private boolean configureIPv4(boolean enabled) {
394         if (VDBG) Log.d(TAG, "configureIPv4(" + enabled + ")");
395 
396         // TODO: Replace this hard-coded information with dynamically selected
397         // config passed down to us by a higher layer IP-coordinating element.
398         String ipAsString = null;
399         int prefixLen = 0;
400         if (mInterfaceType == ConnectivityManager.TETHERING_USB) {
401             ipAsString = USB_NEAR_IFACE_ADDR;
402             prefixLen = USB_PREFIX_LENGTH;
403         } else if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
404             ipAsString = getRandomWifiIPv4Address();
405             prefixLen = WIFI_HOST_IFACE_PREFIX_LENGTH;
406         } else {
407             // BT configures the interface elsewhere: only start DHCP.
408             final Inet4Address srvAddr = (Inet4Address) numericToInetAddress(BLUETOOTH_IFACE_ADDR);
409             return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH);
410         }
411 
412         final LinkAddress linkAddr;
413         try {
414             final InterfaceConfiguration ifcg = mNMService.getInterfaceConfig(mIfaceName);
415             if (ifcg == null) {
416                 mLog.e("Received null interface config");
417                 return false;
418             }
419 
420             InetAddress addr = numericToInetAddress(ipAsString);
421             linkAddr = new LinkAddress(addr, prefixLen);
422             ifcg.setLinkAddress(linkAddr);
423             if (mInterfaceType == ConnectivityManager.TETHERING_WIFI) {
424                 // The WiFi stack has ownership of the interface up/down state.
425                 // It is unclear whether the Bluetooth or USB stacks will manage their own
426                 // state.
427                 ifcg.ignoreInterfaceUpDownStatus();
428             } else {
429                 if (enabled) {
430                     ifcg.setInterfaceUp();
431                 } else {
432                     ifcg.setInterfaceDown();
433                 }
434             }
435             ifcg.clearFlag("running");
436 
437             // TODO: this may throw if the interface is already gone. Do proper handling and
438             // simplify the DHCP server start/stop.
439             mNMService.setInterfaceConfig(mIfaceName, ifcg);
440 
441             if (!configureDhcp(enabled, (Inet4Address) addr, prefixLen)) {
442                 return false;
443             }
444         } catch (Exception e) {
445             mLog.e("Error configuring interface " + e);
446             if (!enabled) {
447                 try {
448                     // Calling stopDhcp several times is fine
449                     stopDhcp();
450                 } catch (Exception dhcpError) {
451                     mLog.e("Error stopping DHCP", dhcpError);
452                 }
453             }
454             return false;
455         }
456 
457         // Directly-connected route.
458         final RouteInfo route = new RouteInfo(linkAddr);
459         if (enabled) {
460             mLinkProperties.addLinkAddress(linkAddr);
461             mLinkProperties.addRoute(route);
462         } else {
463             mLinkProperties.removeLinkAddress(linkAddr);
464             mLinkProperties.removeRoute(route);
465         }
466         return true;
467     }
468 
getRandomWifiIPv4Address()469     private String getRandomWifiIPv4Address() {
470         try {
471             byte[] bytes = numericToInetAddress(WIFI_HOST_IFACE_ADDR).getAddress();
472             bytes[3] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1), FF);
473             return InetAddress.getByAddress(bytes).getHostAddress();
474         } catch (Exception e) {
475             return WIFI_HOST_IFACE_ADDR;
476         }
477     }
478 
startIPv6()479     private boolean startIPv6() {
480         mInterfaceParams = mDeps.getInterfaceParams(mIfaceName);
481         if (mInterfaceParams == null) {
482             mLog.e("Failed to find InterfaceParams");
483             stopIPv6();
484             return false;
485         }
486 
487         mRaDaemon = mDeps.getRouterAdvertisementDaemon(mInterfaceParams);
488         if (!mRaDaemon.start()) {
489             stopIPv6();
490             return false;
491         }
492 
493         return true;
494     }
495 
stopIPv6()496     private void stopIPv6() {
497         mInterfaceParams = null;
498         setRaParams(null);
499 
500         if (mRaDaemon != null) {
501             mRaDaemon.stop();
502             mRaDaemon = null;
503         }
504     }
505 
506     // IPv6TetheringCoordinator sends updates with carefully curated IPv6-only
507     // LinkProperties. These have extraneous data filtered out and only the
508     // necessary prefixes included (per its prefix distribution policy).
509     //
510     // TODO: Evaluate using a data structure than is more directly suited to
511     // communicating only the relevant information.
updateUpstreamIPv6LinkProperties(LinkProperties v6only)512     private void updateUpstreamIPv6LinkProperties(LinkProperties v6only) {
513         if (mRaDaemon == null) return;
514 
515         // Avoid unnecessary work on spurious updates.
516         if (Objects.equals(mLastIPv6LinkProperties, v6only)) {
517             return;
518         }
519 
520         RaParams params = null;
521 
522         if (v6only != null) {
523             params = new RaParams();
524             params.mtu = v6only.getMtu();
525             params.hasDefaultRoute = v6only.hasIpv6DefaultRoute();
526 
527             if (params.hasDefaultRoute) params.hopLimit = getHopLimit(v6only.getInterfaceName());
528 
529             for (LinkAddress linkAddr : v6only.getLinkAddresses()) {
530                 if (linkAddr.getPrefixLength() != RFC7421_PREFIX_LENGTH) continue;
531 
532                 final IpPrefix prefix = new IpPrefix(
533                         linkAddr.getAddress(), linkAddr.getPrefixLength());
534                 params.prefixes.add(prefix);
535 
536                 final Inet6Address dnsServer = getLocalDnsIpFor(prefix);
537                 if (dnsServer != null) {
538                     params.dnses.add(dnsServer);
539                 }
540             }
541         }
542         // If v6only is null, we pass in null to setRaParams(), which handles
543         // deprecation of any existing RA data.
544 
545         setRaParams(params);
546         mLastIPv6LinkProperties = v6only;
547     }
548 
configureLocalIPv6Routes( HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes)549     private void configureLocalIPv6Routes(
550             HashSet<IpPrefix> deprecatedPrefixes, HashSet<IpPrefix> newPrefixes) {
551         // [1] Remove the routes that are deprecated.
552         if (!deprecatedPrefixes.isEmpty()) {
553             final ArrayList<RouteInfo> toBeRemoved =
554                     getLocalRoutesFor(mIfaceName, deprecatedPrefixes);
555             try {
556                 final int removalFailures = mNMService.removeRoutesFromLocalNetwork(toBeRemoved);
557                 if (removalFailures > 0) {
558                     mLog.e(String.format("Failed to remove %d IPv6 routes from local table.",
559                             removalFailures));
560                 }
561             } catch (RemoteException e) {
562                 mLog.e("Failed to remove IPv6 routes from local table: " + e);
563             }
564 
565             for (RouteInfo route : toBeRemoved) mLinkProperties.removeRoute(route);
566         }
567 
568         // [2] Add only the routes that have not previously been added.
569         if (newPrefixes != null && !newPrefixes.isEmpty()) {
570             HashSet<IpPrefix> addedPrefixes = (HashSet) newPrefixes.clone();
571             if (mLastRaParams != null) {
572                 addedPrefixes.removeAll(mLastRaParams.prefixes);
573             }
574 
575             if (!addedPrefixes.isEmpty()) {
576                 final ArrayList<RouteInfo> toBeAdded =
577                         getLocalRoutesFor(mIfaceName, addedPrefixes);
578                 try {
579                     // It's safe to call addInterfaceToLocalNetwork() even if
580                     // the interface is already in the local_network. Note also
581                     // that adding routes that already exist does not cause an
582                     // error (EEXIST is silently ignored).
583                     mNMService.addInterfaceToLocalNetwork(mIfaceName, toBeAdded);
584                 } catch (Exception e) {
585                     mLog.e("Failed to add IPv6 routes to local table: " + e);
586                 }
587 
588                 for (RouteInfo route : toBeAdded) mLinkProperties.addRoute(route);
589             }
590         }
591     }
592 
configureLocalIPv6Dns( HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses)593     private void configureLocalIPv6Dns(
594             HashSet<Inet6Address> deprecatedDnses, HashSet<Inet6Address> newDnses) {
595         // TODO: Is this really necessary? Can we not fail earlier if INetd cannot be located?
596         if (mNetd == null) {
597             if (newDnses != null) newDnses.clear();
598             mLog.e("No netd service instance available; not setting local IPv6 addresses");
599             return;
600         }
601 
602         // [1] Remove deprecated local DNS IP addresses.
603         if (!deprecatedDnses.isEmpty()) {
604             for (Inet6Address dns : deprecatedDnses) {
605                 if (!mInterfaceCtrl.removeAddress(dns, RFC7421_PREFIX_LENGTH)) {
606                     mLog.e("Failed to remove local dns IP " + dns);
607                 }
608 
609                 mLinkProperties.removeLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
610             }
611         }
612 
613         // [2] Add only the local DNS IP addresses that have not previously been added.
614         if (newDnses != null && !newDnses.isEmpty()) {
615             final HashSet<Inet6Address> addedDnses = (HashSet) newDnses.clone();
616             if (mLastRaParams != null) {
617                 addedDnses.removeAll(mLastRaParams.dnses);
618             }
619 
620             for (Inet6Address dns : addedDnses) {
621                 if (!mInterfaceCtrl.addAddress(dns, RFC7421_PREFIX_LENGTH)) {
622                     mLog.e("Failed to add local dns IP " + dns);
623                     newDnses.remove(dns);
624                 }
625 
626                 mLinkProperties.addLinkAddress(new LinkAddress(dns, RFC7421_PREFIX_LENGTH));
627             }
628         }
629 
630         try {
631             mNetd.tetherApplyDnsInterfaces();
632         } catch (ServiceSpecificException | RemoteException e) {
633             mLog.e("Failed to update local DNS caching server");
634             if (newDnses != null) newDnses.clear();
635         }
636     }
637 
getHopLimit(String upstreamIface)638     private byte getHopLimit(String upstreamIface) {
639         try {
640             int upstreamHopLimit = Integer.parseUnsignedInt(
641                     mNetd.getProcSysNet(INetd.IPV6, INetd.CONF, upstreamIface, "hop_limit"));
642             // Add one hop to account for this forwarding device
643             upstreamHopLimit++;
644             // Cap the hop limit to 255.
645             return (byte) Integer.min(upstreamHopLimit, 255);
646         } catch (Exception e) {
647             mLog.e("Failed to find upstream interface hop limit", e);
648         }
649         return RaParams.DEFAULT_HOPLIMIT;
650     }
651 
setRaParams(RaParams newParams)652     private void setRaParams(RaParams newParams) {
653         if (mRaDaemon != null) {
654             final RaParams deprecatedParams =
655                     RaParams.getDeprecatedRaParams(mLastRaParams, newParams);
656 
657             configureLocalIPv6Routes(deprecatedParams.prefixes,
658                     (newParams != null) ? newParams.prefixes : null);
659 
660             configureLocalIPv6Dns(deprecatedParams.dnses,
661                     (newParams != null) ? newParams.dnses : null);
662 
663             mRaDaemon.buildNewRa(deprecatedParams, newParams);
664         }
665 
666         mLastRaParams = newParams;
667     }
668 
logMessage(State state, int what)669     private void logMessage(State state, int what) {
670         mLog.log(state.getName() + " got " + sMagicDecoderRing.get(what, Integer.toString(what)));
671     }
672 
sendInterfaceState(int newInterfaceState)673     private void sendInterfaceState(int newInterfaceState) {
674         mServingMode = newInterfaceState;
675         mCallback.updateInterfaceState(this, newInterfaceState, mLastError);
676         sendLinkProperties();
677     }
678 
sendLinkProperties()679     private void sendLinkProperties() {
680         mCallback.updateLinkProperties(this, new LinkProperties(mLinkProperties));
681     }
682 
resetLinkProperties()683     private void resetLinkProperties() {
684         mLinkProperties.clear();
685         mLinkProperties.setInterfaceName(mIfaceName);
686     }
687 
688     class InitialState extends State {
689         @Override
enter()690         public void enter() {
691             sendInterfaceState(STATE_AVAILABLE);
692         }
693 
694         @Override
processMessage(Message message)695         public boolean processMessage(Message message) {
696             logMessage(this, message.what);
697             switch (message.what) {
698                 case CMD_TETHER_REQUESTED:
699                     mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
700                     switch (message.arg1) {
701                         case STATE_LOCAL_ONLY:
702                             transitionTo(mLocalHotspotState);
703                             break;
704                         case STATE_TETHERED:
705                             transitionTo(mTetheredState);
706                             break;
707                         default:
708                             mLog.e("Invalid tethering interface serving state specified.");
709                     }
710                     break;
711                 case CMD_INTERFACE_DOWN:
712                     transitionTo(mUnavailableState);
713                     break;
714                 case CMD_IPV6_TETHER_UPDATE:
715                     updateUpstreamIPv6LinkProperties((LinkProperties) message.obj);
716                     break;
717                 default:
718                     return NOT_HANDLED;
719             }
720             return HANDLED;
721         }
722     }
723 
724     class BaseServingState extends State {
725         @Override
enter()726         public void enter() {
727             if (!startIPv4()) {
728                 mLastError = ConnectivityManager.TETHER_ERROR_IFACE_CFG_ERROR;
729                 return;
730             }
731 
732             try {
733                 mNMService.tetherInterface(mIfaceName);
734             } catch (Exception e) {
735                 mLog.e("Error Tethering: " + e);
736                 mLastError = ConnectivityManager.TETHER_ERROR_TETHER_IFACE_ERROR;
737                 return;
738             }
739 
740             if (!startIPv6()) {
741                 mLog.e("Failed to startIPv6");
742                 // TODO: Make this a fatal error once Bluetooth IPv6 is sorted.
743                 return;
744             }
745         }
746 
747         @Override
exit()748         public void exit() {
749             // Note that at this point, we're leaving the tethered state.  We can fail any
750             // of these operations, but it doesn't really change that we have to try them
751             // all in sequence.
752             stopIPv6();
753 
754             try {
755                 mNMService.untetherInterface(mIfaceName);
756             } catch (Exception e) {
757                 mLastError = ConnectivityManager.TETHER_ERROR_UNTETHER_IFACE_ERROR;
758                 mLog.e("Failed to untether interface: " + e);
759             }
760 
761             stopIPv4();
762 
763             resetLinkProperties();
764         }
765 
766         @Override
processMessage(Message message)767         public boolean processMessage(Message message) {
768             logMessage(this, message.what);
769             switch (message.what) {
770                 case CMD_TETHER_UNREQUESTED:
771                     transitionTo(mInitialState);
772                     if (DBG) Log.d(TAG, "Untethered (unrequested)" + mIfaceName);
773                     break;
774                 case CMD_INTERFACE_DOWN:
775                     transitionTo(mUnavailableState);
776                     if (DBG) Log.d(TAG, "Untethered (ifdown)" + mIfaceName);
777                     break;
778                 case CMD_IPV6_TETHER_UPDATE:
779                     updateUpstreamIPv6LinkProperties((LinkProperties) message.obj);
780                     sendLinkProperties();
781                     break;
782                 case CMD_IP_FORWARDING_ENABLE_ERROR:
783                 case CMD_IP_FORWARDING_DISABLE_ERROR:
784                 case CMD_START_TETHERING_ERROR:
785                 case CMD_STOP_TETHERING_ERROR:
786                 case CMD_SET_DNS_FORWARDERS_ERROR:
787                     mLastError = ConnectivityManager.TETHER_ERROR_MASTER_ERROR;
788                     transitionTo(mInitialState);
789                     break;
790                 default:
791                     return false;
792             }
793             return true;
794         }
795     }
796 
797     // Handling errors in BaseServingState.enter() by transitioning is
798     // problematic because transitioning during a multi-state jump yields
799     // a Log.wtf(). Ultimately, there should be only one ServingState,
800     // and forwarding and NAT rules should be handled by a coordinating
801     // functional element outside of IpServer.
802     class LocalHotspotState extends BaseServingState {
803         @Override
enter()804         public void enter() {
805             super.enter();
806             if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
807                 transitionTo(mInitialState);
808             }
809 
810             if (DBG) Log.d(TAG, "Local hotspot " + mIfaceName);
811             sendInterfaceState(STATE_LOCAL_ONLY);
812         }
813 
814         @Override
processMessage(Message message)815         public boolean processMessage(Message message) {
816             if (super.processMessage(message)) return true;
817 
818             logMessage(this, message.what);
819             switch (message.what) {
820                 case CMD_TETHER_REQUESTED:
821                     mLog.e("CMD_TETHER_REQUESTED while in local-only hotspot mode.");
822                     break;
823                 case CMD_TETHER_CONNECTION_CHANGED:
824                     // Ignored in local hotspot state.
825                     break;
826                 default:
827                     return false;
828             }
829             return true;
830         }
831     }
832 
833     // Handling errors in BaseServingState.enter() by transitioning is
834     // problematic because transitioning during a multi-state jump yields
835     // a Log.wtf(). Ultimately, there should be only one ServingState,
836     // and forwarding and NAT rules should be handled by a coordinating
837     // functional element outside of IpServer.
838     class TetheredState extends BaseServingState {
839         @Override
enter()840         public void enter() {
841             super.enter();
842             if (mLastError != ConnectivityManager.TETHER_ERROR_NO_ERROR) {
843                 transitionTo(mInitialState);
844             }
845 
846             if (DBG) Log.d(TAG, "Tethered " + mIfaceName);
847             sendInterfaceState(STATE_TETHERED);
848         }
849 
850         @Override
exit()851         public void exit() {
852             cleanupUpstream();
853             super.exit();
854         }
855 
cleanupUpstream()856         private void cleanupUpstream() {
857             if (mUpstreamIfaceSet == null) return;
858 
859             for (String ifname : mUpstreamIfaceSet.ifnames) cleanupUpstreamInterface(ifname);
860             mUpstreamIfaceSet = null;
861         }
862 
cleanupUpstreamInterface(String upstreamIface)863         private void cleanupUpstreamInterface(String upstreamIface) {
864             // Note that we don't care about errors here.
865             // Sometimes interfaces are gone before we get
866             // to remove their rules, which generates errors.
867             // Just do the best we can.
868             try {
869                 // About to tear down NAT; gather remaining statistics.
870                 mStatsService.forceUpdate();
871             } catch (Exception e) {
872                 if (VDBG) Log.e(TAG, "Exception in forceUpdate: " + e.toString());
873             }
874             try {
875                 mNMService.stopInterfaceForwarding(mIfaceName, upstreamIface);
876             } catch (Exception e) {
877                 if (VDBG) Log.e(TAG, "Exception in removeInterfaceForward: " + e.toString());
878             }
879             try {
880                 mNMService.disableNat(mIfaceName, upstreamIface);
881             } catch (Exception e) {
882                 if (VDBG) Log.e(TAG, "Exception in disableNat: " + e.toString());
883             }
884         }
885 
886         @Override
processMessage(Message message)887         public boolean processMessage(Message message) {
888             if (super.processMessage(message)) return true;
889 
890             logMessage(this, message.what);
891             switch (message.what) {
892                 case CMD_TETHER_REQUESTED:
893                     mLog.e("CMD_TETHER_REQUESTED while already tethering.");
894                     break;
895                 case CMD_TETHER_CONNECTION_CHANGED:
896                     final InterfaceSet newUpstreamIfaceSet = (InterfaceSet) message.obj;
897                     if (noChangeInUpstreamIfaceSet(newUpstreamIfaceSet)) {
898                         if (VDBG) Log.d(TAG, "Connection changed noop - dropping");
899                         break;
900                     }
901 
902                     if (newUpstreamIfaceSet == null) {
903                         cleanupUpstream();
904                         break;
905                     }
906 
907                     for (String removed : upstreamInterfacesRemoved(newUpstreamIfaceSet)) {
908                         cleanupUpstreamInterface(removed);
909                     }
910 
911                     final Set<String> added = upstreamInterfacesAdd(newUpstreamIfaceSet);
912                     // This makes the call to cleanupUpstream() in the error
913                     // path for any interface neatly cleanup all the interfaces.
914                     mUpstreamIfaceSet = newUpstreamIfaceSet;
915 
916                     for (String ifname : added) {
917                         try {
918                             mNMService.enableNat(mIfaceName, ifname);
919                             mNMService.startInterfaceForwarding(mIfaceName, ifname);
920                         } catch (Exception e) {
921                             mLog.e("Exception enabling NAT: " + e);
922                             cleanupUpstream();
923                             mLastError = ConnectivityManager.TETHER_ERROR_ENABLE_NAT_ERROR;
924                             transitionTo(mInitialState);
925                             return true;
926                         }
927                     }
928                     break;
929                 default:
930                     return false;
931             }
932             return true;
933         }
934 
noChangeInUpstreamIfaceSet(InterfaceSet newIfaces)935         private boolean noChangeInUpstreamIfaceSet(InterfaceSet newIfaces) {
936             if (mUpstreamIfaceSet == null && newIfaces == null) return true;
937             if (mUpstreamIfaceSet != null && newIfaces != null) {
938                 return mUpstreamIfaceSet.equals(newIfaces);
939             }
940             return false;
941         }
942 
upstreamInterfacesRemoved(InterfaceSet newIfaces)943         private Set<String> upstreamInterfacesRemoved(InterfaceSet newIfaces) {
944             if (mUpstreamIfaceSet == null) return new HashSet<>();
945 
946             final HashSet<String> removed = new HashSet<>(mUpstreamIfaceSet.ifnames);
947             removed.removeAll(newIfaces.ifnames);
948             return removed;
949         }
950 
upstreamInterfacesAdd(InterfaceSet newIfaces)951         private Set<String> upstreamInterfacesAdd(InterfaceSet newIfaces) {
952             final HashSet<String> added = new HashSet<>(newIfaces.ifnames);
953             if (mUpstreamIfaceSet != null) added.removeAll(mUpstreamIfaceSet.ifnames);
954             return added;
955         }
956     }
957 
958     /**
959      * This state is terminal for the per interface state machine.  At this
960      * point, the master state machine should have removed this interface
961      * specific state machine from its list of possible recipients of
962      * tethering requests.  The state machine itself will hang around until
963      * the garbage collector finds it.
964      */
965     class UnavailableState extends State {
966         @Override
enter()967         public void enter() {
968             mLastError = ConnectivityManager.TETHER_ERROR_NO_ERROR;
969             sendInterfaceState(STATE_UNAVAILABLE);
970         }
971     }
972 
973     // Accumulate routes representing "prefixes to be assigned to the local
974     // interface", for subsequent modification of local_network routing.
getLocalRoutesFor( String ifname, HashSet<IpPrefix> prefixes)975     private static ArrayList<RouteInfo> getLocalRoutesFor(
976             String ifname, HashSet<IpPrefix> prefixes) {
977         final ArrayList<RouteInfo> localRoutes = new ArrayList<RouteInfo>();
978         for (IpPrefix ipp : prefixes) {
979             localRoutes.add(new RouteInfo(ipp, null, ifname));
980         }
981         return localRoutes;
982     }
983 
984     // Given a prefix like 2001:db8::/64 return an address like 2001:db8::1.
getLocalDnsIpFor(IpPrefix localPrefix)985     private static Inet6Address getLocalDnsIpFor(IpPrefix localPrefix) {
986         final byte[] dnsBytes = localPrefix.getRawAddress();
987         dnsBytes[dnsBytes.length - 1] = getRandomSanitizedByte(DOUG_ADAMS, asByte(0), asByte(1));
988         try {
989             return Inet6Address.getByAddress(null, dnsBytes, 0);
990         } catch (UnknownHostException e) {
991             Slog.wtf(TAG, "Failed to construct Inet6Address from: " + localPrefix);
992             return null;
993         }
994     }
995 
getRandomSanitizedByte(byte dflt, byte... excluded)996     private static byte getRandomSanitizedByte(byte dflt, byte... excluded) {
997         final byte random = (byte) (new Random()).nextInt();
998         for (int value : excluded) {
999             if (random == value) return dflt;
1000         }
1001         return random;
1002     }
1003 }
1004