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