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