blob: edfe3cad9039525af3fa6421b66277574133e09d [file] [log] [blame]
Erik Kline1eb8c692016-07-08 17:21:26 +09001/*
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 com.android.server.connectivity.tethering;
18
Erik Kline1eb8c692016-07-08 17:21:26 +090019import android.net.IpPrefix;
20import android.net.LinkAddress;
21import android.net.LinkProperties;
22import android.net.Network;
23import android.net.NetworkCapabilities;
24import android.net.NetworkState;
25import android.net.RouteInfo;
paulhud9736de2019-03-08 16:35:20 +080026import android.net.ip.IpServer;
Erik Klineea9cc482017-03-10 19:35:34 +090027import android.net.util.NetworkConstants;
Erik Kline7747fd42017-05-12 16:52:48 +090028import android.net.util.SharedLog;
Erik Kline1eb8c692016-07-08 17:21:26 +090029import android.util.Log;
30
31import java.net.Inet6Address;
32import java.net.InetAddress;
33import java.util.ArrayList;
Erik Klineea9cc482017-03-10 19:35:34 +090034import java.util.Arrays;
Erik Kline6e29bf02016-08-15 16:16:18 +090035import java.util.LinkedList;
Erik Klineea9cc482017-03-10 19:35:34 +090036import java.util.Random;
Erik Kline1eb8c692016-07-08 17:21:26 +090037
38
39/**
40 * IPv6 tethering is rather different from IPv4 owing to the absence of NAT.
41 * This coordinator is responsible for evaluating the dedicated prefixes
42 * assigned to the device and deciding how to divvy them up among downstream
43 * interfaces.
44 *
45 * @hide
46 */
47public class IPv6TetheringCoordinator {
48 private static final String TAG = IPv6TetheringCoordinator.class.getSimpleName();
49 private static final boolean DBG = false;
50 private static final boolean VDBG = false;
51
Erik Klineea9cc482017-03-10 19:35:34 +090052 private static class Downstream {
Erik Kline7a4ccc62018-08-27 17:26:47 +090053 public final IpServer ipServer;
54 public final int mode; // IpServer.STATE_*
Erik Klineea9cc482017-03-10 19:35:34 +090055 // Used to append to a ULA /48, constructing a ULA /64 for local use.
56 public final short subnetId;
57
Erik Kline7a4ccc62018-08-27 17:26:47 +090058 Downstream(IpServer ipServer, int mode, short subnetId) {
59 this.ipServer = ipServer;
Erik Klineea9cc482017-03-10 19:35:34 +090060 this.mode = mode;
61 this.subnetId = subnetId;
62 }
63 }
64
Erik Kline7a4ccc62018-08-27 17:26:47 +090065 private final ArrayList<IpServer> mNotifyList;
Erik Kline7747fd42017-05-12 16:52:48 +090066 private final SharedLog mLog;
Erik Klineea9cc482017-03-10 19:35:34 +090067 // NOTE: mActiveDownstreams is a list and not a hash data structure because
68 // we keep active downstreams in arrival order. This is done so /64s can
69 // be parceled out on a "first come, first served" basis and a /64 used by
70 // a downstream that is no longer active can be redistributed to any next
71 // waiting active downstream (again, in arrival order).
72 private final LinkedList<Downstream> mActiveDownstreams;
73 private final byte[] mUniqueLocalPrefix;
74 private short mNextSubnetId;
Erik Kline1eb8c692016-07-08 17:21:26 +090075 private NetworkState mUpstreamNetworkState;
76
Erik Kline7a4ccc62018-08-27 17:26:47 +090077 public IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log) {
Erik Kline1eb8c692016-07-08 17:21:26 +090078 mNotifyList = notifyList;
Erik Kline7747fd42017-05-12 16:52:48 +090079 mLog = log.forSubComponent(TAG);
Erik Kline6e29bf02016-08-15 16:16:18 +090080 mActiveDownstreams = new LinkedList<>();
Erik Klineea9cc482017-03-10 19:35:34 +090081 mUniqueLocalPrefix = generateUniqueLocalPrefix();
82 mNextSubnetId = 0;
Erik Kline6e29bf02016-08-15 16:16:18 +090083 }
84
markchien0df2ebc42019-09-30 14:40:57 +080085 /** Add active downstream to ipv6 tethering candidate list. */
Erik Kline7a4ccc62018-08-27 17:26:47 +090086 public void addActiveDownstream(IpServer downstream, int mode) {
Erik Klineea9cc482017-03-10 19:35:34 +090087 if (findDownstream(downstream) == null) {
Erik Kline6e29bf02016-08-15 16:16:18 +090088 // Adding a new downstream appends it to the list. Adding a
89 // downstream a second time without first removing it has no effect.
Erik Klineea9cc482017-03-10 19:35:34 +090090 // We never change the mode of a downstream except by first removing
91 // it and then re-adding it (with its new mode specified);
92 if (mActiveDownstreams.offer(new Downstream(downstream, mode, mNextSubnetId))) {
93 // Make sure subnet IDs are always positive. They are appended
94 // to a ULA /48 to make a ULA /64 for local use.
95 mNextSubnetId = (short) Math.max(0, mNextSubnetId + 1);
96 }
Erik Kline6e29bf02016-08-15 16:16:18 +090097 updateIPv6TetheringInterfaces();
98 }
99 }
100
markchien0df2ebc42019-09-30 14:40:57 +0800101 /** Remove downstream from ipv6 tethering candidate list. */
Erik Kline7a4ccc62018-08-27 17:26:47 +0900102 public void removeActiveDownstream(IpServer downstream) {
Erik Kline6e29bf02016-08-15 16:16:18 +0900103 stopIPv6TetheringOn(downstream);
Erik Klineea9cc482017-03-10 19:35:34 +0900104 if (mActiveDownstreams.remove(findDownstream(downstream))) {
Erik Kline6e29bf02016-08-15 16:16:18 +0900105 updateIPv6TetheringInterfaces();
106 }
Erik Klineea9cc482017-03-10 19:35:34 +0900107
108 // When tethering is stopping we can reset the subnet counter.
109 if (mNotifyList.isEmpty()) {
110 if (!mActiveDownstreams.isEmpty()) {
111 Log.wtf(TAG, "Tethering notify list empty, IPv6 downstreams non-empty.");
112 }
113 mNextSubnetId = 0;
114 }
Erik Kline1eb8c692016-07-08 17:21:26 +0900115 }
116
markchien0df2ebc42019-09-30 14:40:57 +0800117 /**
118 * Call when upstream NetworkState may be changed.
119 * If upstream has ipv6 for tethering, update this new NetworkState
120 * to IpServer. Otherwise stop ipv6 tethering on downstream interfaces.
121 */
Erik Kline1eb8c692016-07-08 17:21:26 +0900122 public void updateUpstreamNetworkState(NetworkState ns) {
123 if (VDBG) {
124 Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns));
125 }
Remi NGUYEN VAN25a7e4f2018-03-09 14:07:18 +0900126 if (TetheringInterfaceUtils.getIPv6Interface(ns) == null) {
Erik Kline1eb8c692016-07-08 17:21:26 +0900127 stopIPv6TetheringOnAllInterfaces();
128 setUpstreamNetworkState(null);
129 return;
130 }
131
markchien0df2ebc42019-09-30 14:40:57 +0800132 if (mUpstreamNetworkState != null
133 && !ns.network.equals(mUpstreamNetworkState.network)) {
Erik Kline1eb8c692016-07-08 17:21:26 +0900134 stopIPv6TetheringOnAllInterfaces();
135 }
Erik Klinefa37b2f2016-08-02 18:27:03 +0900136
Erik Kline1eb8c692016-07-08 17:21:26 +0900137 setUpstreamNetworkState(ns);
Erik Klinefa37b2f2016-08-02 18:27:03 +0900138 updateIPv6TetheringInterfaces();
Erik Kline1eb8c692016-07-08 17:21:26 +0900139 }
140
141 private void stopIPv6TetheringOnAllInterfaces() {
Erik Kline7a4ccc62018-08-27 17:26:47 +0900142 for (IpServer ipServer : mNotifyList) {
143 stopIPv6TetheringOn(ipServer);
Erik Kline1eb8c692016-07-08 17:21:26 +0900144 }
145 }
146
147 private void setUpstreamNetworkState(NetworkState ns) {
Erik Klinefa37b2f2016-08-02 18:27:03 +0900148 if (ns == null) {
Erik Kline1eb8c692016-07-08 17:21:26 +0900149 mUpstreamNetworkState = null;
150 } else {
Erik Klinefa37b2f2016-08-02 18:27:03 +0900151 // Make a deep copy of the parts we need.
Erik Kline1eb8c692016-07-08 17:21:26 +0900152 mUpstreamNetworkState = new NetworkState(
153 null,
154 new LinkProperties(ns.linkProperties),
155 new NetworkCapabilities(ns.networkCapabilities),
156 new Network(ns.network),
157 null,
158 null);
159 }
160
Erik Kline7747fd42017-05-12 16:52:48 +0900161 mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState));
Erik Kline1eb8c692016-07-08 17:21:26 +0900162 }
163
Erik Klinefa37b2f2016-08-02 18:27:03 +0900164 private void updateIPv6TetheringInterfaces() {
Erik Kline7a4ccc62018-08-27 17:26:47 +0900165 for (IpServer ipServer : mNotifyList) {
166 final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer);
167 ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, lp);
Erik Kline1eb8c692016-07-08 17:21:26 +0900168 break;
169 }
170 }
171
Erik Kline7a4ccc62018-08-27 17:26:47 +0900172 private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) {
Erik Kline7a4ccc62018-08-27 17:26:47 +0900173 final Downstream ds = findDownstream(ipServer);
Erik Klineea9cc482017-03-10 19:35:34 +0900174 if (ds == null) return null;
175
Erik Kline7a4ccc62018-08-27 17:26:47 +0900176 if (ds.mode == IpServer.STATE_LOCAL_ONLY) {
Erik Klineea9cc482017-03-10 19:35:34 +0900177 // Build a Unique Locally-assigned Prefix configuration.
178 return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId);
179 }
180
Erik Kline7a4ccc62018-08-27 17:26:47 +0900181 // This downstream is in IpServer.STATE_TETHERED mode.
Erik Klineea9cc482017-03-10 19:35:34 +0900182 if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) {
183 return null;
184 }
185
Erik Kline1eb8c692016-07-08 17:21:26 +0900186 // NOTE: Here, in future, we would have policies to decide how to divvy
187 // up the available dedicated prefixes among downstream interfaces.
188 // At this time we have no such mechanism--we only support tethering
Erik Kline6e29bf02016-08-15 16:16:18 +0900189 // IPv6 toward the oldest (first requested) active downstream.
Erik Kline1eb8c692016-07-08 17:21:26 +0900190
Erik Klineea9cc482017-03-10 19:35:34 +0900191 final Downstream currentActive = mActiveDownstreams.peek();
Erik Kline7a4ccc62018-08-27 17:26:47 +0900192 if (currentActive != null && currentActive.ipServer == ipServer) {
Erik Kline6e29bf02016-08-15 16:16:18 +0900193 final LinkProperties lp = getIPv6OnlyLinkProperties(
194 mUpstreamNetworkState.linkProperties);
paulhud9736de2019-03-08 16:35:20 +0800195 if (lp.hasIpv6DefaultRoute() && lp.hasGlobalIpv6Address()) {
Erik Kline6e29bf02016-08-15 16:16:18 +0900196 return lp;
197 }
Erik Kline1eb8c692016-07-08 17:21:26 +0900198 }
199
200 return null;
201 }
202
Erik Kline7a4ccc62018-08-27 17:26:47 +0900203 Downstream findDownstream(IpServer ipServer) {
Erik Klineea9cc482017-03-10 19:35:34 +0900204 for (Downstream ds : mActiveDownstreams) {
Erik Kline7a4ccc62018-08-27 17:26:47 +0900205 if (ds.ipServer == ipServer) return ds;
Erik Klineea9cc482017-03-10 19:35:34 +0900206 }
207 return null;
208 }
209
Erik Kline1eb8c692016-07-08 17:21:26 +0900210 private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) {
211 final LinkProperties v6only = new LinkProperties();
212 if (lp == null) {
213 return v6only;
214 }
215
216 // NOTE: At this time we don't copy over any information about any
217 // stacked links. No current stacked link configuration has IPv6.
218
219 v6only.setInterfaceName(lp.getInterfaceName());
220
221 v6only.setMtu(lp.getMtu());
222
223 for (LinkAddress linkAddr : lp.getLinkAddresses()) {
224 if (linkAddr.isGlobalPreferred() && linkAddr.getPrefixLength() == 64) {
225 v6only.addLinkAddress(linkAddr);
226 }
227 }
228
229 for (RouteInfo routeInfo : lp.getRoutes()) {
230 final IpPrefix destination = routeInfo.getDestination();
markchien0df2ebc42019-09-30 14:40:57 +0800231 if ((destination.getAddress() instanceof Inet6Address)
232 && (destination.getPrefixLength() <= 64)) {
Erik Kline1eb8c692016-07-08 17:21:26 +0900233 v6only.addRoute(routeInfo);
234 }
235 }
236
237 for (InetAddress dnsServer : lp.getDnsServers()) {
238 if (isIPv6GlobalAddress(dnsServer)) {
239 // For now we include ULAs.
240 v6only.addDnsServer(dnsServer);
241 }
242 }
243
244 v6only.setDomains(lp.getDomains());
245
246 return v6only;
247 }
248
249 // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we
250 // announce our own IPv6 address as DNS server.
251 private static boolean isIPv6GlobalAddress(InetAddress ip) {
markchien0df2ebc42019-09-30 14:40:57 +0800252 return (ip instanceof Inet6Address)
253 && !ip.isAnyLocalAddress()
254 && !ip.isLoopbackAddress()
255 && !ip.isLinkLocalAddress()
256 && !ip.isSiteLocalAddress()
257 && !ip.isMulticastAddress();
Erik Kline1eb8c692016-07-08 17:21:26 +0900258 }
259
Erik Klineea9cc482017-03-10 19:35:34 +0900260 private static LinkProperties getUniqueLocalConfig(byte[] ulp, short subnetId) {
261 final LinkProperties lp = new LinkProperties();
262
263 final IpPrefix local48 = makeUniqueLocalPrefix(ulp, (short) 0, 48);
264 lp.addRoute(new RouteInfo(local48, null, null));
265
266 final IpPrefix local64 = makeUniqueLocalPrefix(ulp, subnetId, 64);
267 // Because this is a locally-generated ULA, we don't have an upstream
268 // address. But because the downstream IP address management code gets
269 // its prefix from the upstream's IP address, we create a fake one here.
270 lp.addLinkAddress(new LinkAddress(local64.getAddress(), 64));
271
272 lp.setMtu(NetworkConstants.ETHER_MTU);
273 return lp;
274 }
275
276 private static IpPrefix makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen) {
277 final byte[] bytes = Arrays.copyOf(in6addr, in6addr.length);
278 bytes[7] = (byte) (subnetId >> 8);
279 bytes[8] = (byte) subnetId;
280 return new IpPrefix(bytes, prefixlen);
281 }
282
283 // Generates a Unique Locally-assigned Prefix:
284 //
285 // https://tools.ietf.org/html/rfc4193#section-3.1
286 //
287 // The result is a /48 that can be used for local-only communications.
288 private static byte[] generateUniqueLocalPrefix() {
289 final byte[] ulp = new byte[6]; // 6 = 48bits / 8bits/byte
290 (new Random()).nextBytes(ulp);
291
292 final byte[] in6addr = Arrays.copyOf(ulp, NetworkConstants.IPV6_ADDR_LEN);
293 in6addr[0] = (byte) 0xfd; // fc00::/7 and L=1
294
295 return in6addr;
296 }
297
Erik Kline1eb8c692016-07-08 17:21:26 +0900298 private static String toDebugString(NetworkState ns) {
299 if (ns == null) {
300 return "NetworkState{null}";
301 }
302 return String.format("NetworkState{%s, %s, %s}",
303 ns.network,
304 ns.networkCapabilities,
305 ns.linkProperties);
306 }
Erik Kline6e29bf02016-08-15 16:16:18 +0900307
Erik Kline7a4ccc62018-08-27 17:26:47 +0900308 private static void stopIPv6TetheringOn(IpServer ipServer) {
309 ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null);
Erik Kline6e29bf02016-08-15 16:16:18 +0900310 }
Erik Kline1eb8c692016-07-08 17:21:26 +0900311}