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