1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.server.connectivity.tethering; 18 19 import android.net.ConnectivityManager; 20 import android.net.IpPrefix; 21 import android.net.LinkAddress; 22 import android.net.LinkProperties; 23 import android.net.Network; 24 import android.net.NetworkCapabilities; 25 import android.net.NetworkState; 26 import android.net.RouteInfo; 27 import android.net.ip.IpServer; 28 import android.net.util.NetworkConstants; 29 import android.net.util.SharedLog; 30 import android.util.Log; 31 32 import java.net.Inet6Address; 33 import java.net.InetAddress; 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.LinkedList; 37 import java.util.Random; 38 39 40 /** 41 * IPv6 tethering is rather different from IPv4 owing to the absence of NAT. 42 * This coordinator is responsible for evaluating the dedicated prefixes 43 * assigned to the device and deciding how to divvy them up among downstream 44 * interfaces. 45 * 46 * @hide 47 */ 48 public class IPv6TetheringCoordinator { 49 private static final String TAG = IPv6TetheringCoordinator.class.getSimpleName(); 50 private static final boolean DBG = false; 51 private static final boolean VDBG = false; 52 53 private static class Downstream { 54 public final IpServer ipServer; 55 public final int mode; // IpServer.STATE_* 56 // Used to append to a ULA /48, constructing a ULA /64 for local use. 57 public final short subnetId; 58 Downstream(IpServer ipServer, int mode, short subnetId)59 Downstream(IpServer ipServer, int mode, short subnetId) { 60 this.ipServer = ipServer; 61 this.mode = mode; 62 this.subnetId = subnetId; 63 } 64 } 65 66 private final ArrayList<IpServer> mNotifyList; 67 private final SharedLog mLog; 68 // NOTE: mActiveDownstreams is a list and not a hash data structure because 69 // we keep active downstreams in arrival order. This is done so /64s can 70 // be parceled out on a "first come, first served" basis and a /64 used by 71 // a downstream that is no longer active can be redistributed to any next 72 // waiting active downstream (again, in arrival order). 73 private final LinkedList<Downstream> mActiveDownstreams; 74 private final byte[] mUniqueLocalPrefix; 75 private short mNextSubnetId; 76 private NetworkState mUpstreamNetworkState; 77 IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log)78 public IPv6TetheringCoordinator(ArrayList<IpServer> notifyList, SharedLog log) { 79 mNotifyList = notifyList; 80 mLog = log.forSubComponent(TAG); 81 mActiveDownstreams = new LinkedList<>(); 82 mUniqueLocalPrefix = generateUniqueLocalPrefix(); 83 mNextSubnetId = 0; 84 } 85 addActiveDownstream(IpServer downstream, int mode)86 public void addActiveDownstream(IpServer downstream, int mode) { 87 if (findDownstream(downstream) == null) { 88 // Adding a new downstream appends it to the list. Adding a 89 // downstream a second time without first removing it has no effect. 90 // 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 } 97 updateIPv6TetheringInterfaces(); 98 } 99 } 100 removeActiveDownstream(IpServer downstream)101 public void removeActiveDownstream(IpServer downstream) { 102 stopIPv6TetheringOn(downstream); 103 if (mActiveDownstreams.remove(findDownstream(downstream))) { 104 updateIPv6TetheringInterfaces(); 105 } 106 107 // When tethering is stopping we can reset the subnet counter. 108 if (mNotifyList.isEmpty()) { 109 if (!mActiveDownstreams.isEmpty()) { 110 Log.wtf(TAG, "Tethering notify list empty, IPv6 downstreams non-empty."); 111 } 112 mNextSubnetId = 0; 113 } 114 } 115 updateUpstreamNetworkState(NetworkState ns)116 public void updateUpstreamNetworkState(NetworkState ns) { 117 if (VDBG) { 118 Log.d(TAG, "updateUpstreamNetworkState: " + toDebugString(ns)); 119 } 120 if (TetheringInterfaceUtils.getIPv6Interface(ns) == null) { 121 stopIPv6TetheringOnAllInterfaces(); 122 setUpstreamNetworkState(null); 123 return; 124 } 125 126 if (mUpstreamNetworkState != null && 127 !ns.network.equals(mUpstreamNetworkState.network)) { 128 stopIPv6TetheringOnAllInterfaces(); 129 } 130 131 setUpstreamNetworkState(ns); 132 updateIPv6TetheringInterfaces(); 133 } 134 stopIPv6TetheringOnAllInterfaces()135 private void stopIPv6TetheringOnAllInterfaces() { 136 for (IpServer ipServer : mNotifyList) { 137 stopIPv6TetheringOn(ipServer); 138 } 139 } 140 setUpstreamNetworkState(NetworkState ns)141 private void setUpstreamNetworkState(NetworkState ns) { 142 if (ns == null) { 143 mUpstreamNetworkState = null; 144 } else { 145 // Make a deep copy of the parts we need. 146 mUpstreamNetworkState = new NetworkState( 147 null, 148 new LinkProperties(ns.linkProperties), 149 new NetworkCapabilities(ns.networkCapabilities), 150 new Network(ns.network), 151 null, 152 null); 153 } 154 155 mLog.log("setUpstreamNetworkState: " + toDebugString(mUpstreamNetworkState)); 156 } 157 updateIPv6TetheringInterfaces()158 private void updateIPv6TetheringInterfaces() { 159 for (IpServer ipServer : mNotifyList) { 160 final LinkProperties lp = getInterfaceIPv6LinkProperties(ipServer); 161 ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, lp); 162 break; 163 } 164 } 165 getInterfaceIPv6LinkProperties(IpServer ipServer)166 private LinkProperties getInterfaceIPv6LinkProperties(IpServer ipServer) { 167 if (ipServer.interfaceType() == ConnectivityManager.TETHERING_BLUETOOTH) { 168 // TODO: Figure out IPv6 support on PAN interfaces. 169 return null; 170 } 171 172 final Downstream ds = findDownstream(ipServer); 173 if (ds == null) return null; 174 175 if (ds.mode == IpServer.STATE_LOCAL_ONLY) { 176 // Build a Unique Locally-assigned Prefix configuration. 177 return getUniqueLocalConfig(mUniqueLocalPrefix, ds.subnetId); 178 } 179 180 // This downstream is in IpServer.STATE_TETHERED mode. 181 if (mUpstreamNetworkState == null || mUpstreamNetworkState.linkProperties == null) { 182 return null; 183 } 184 185 // NOTE: Here, in future, we would have policies to decide how to divvy 186 // up the available dedicated prefixes among downstream interfaces. 187 // At this time we have no such mechanism--we only support tethering 188 // IPv6 toward the oldest (first requested) active downstream. 189 190 final Downstream currentActive = mActiveDownstreams.peek(); 191 if (currentActive != null && currentActive.ipServer == ipServer) { 192 final LinkProperties lp = getIPv6OnlyLinkProperties( 193 mUpstreamNetworkState.linkProperties); 194 if (lp.hasIpv6DefaultRoute() && lp.hasGlobalIpv6Address()) { 195 return lp; 196 } 197 } 198 199 return null; 200 } 201 findDownstream(IpServer ipServer)202 Downstream findDownstream(IpServer ipServer) { 203 for (Downstream ds : mActiveDownstreams) { 204 if (ds.ipServer == ipServer) return ds; 205 } 206 return null; 207 } 208 getIPv6OnlyLinkProperties(LinkProperties lp)209 private static LinkProperties getIPv6OnlyLinkProperties(LinkProperties lp) { 210 final LinkProperties v6only = new LinkProperties(); 211 if (lp == null) { 212 return v6only; 213 } 214 215 // NOTE: At this time we don't copy over any information about any 216 // stacked links. No current stacked link configuration has IPv6. 217 218 v6only.setInterfaceName(lp.getInterfaceName()); 219 220 v6only.setMtu(lp.getMtu()); 221 222 for (LinkAddress linkAddr : lp.getLinkAddresses()) { 223 if (linkAddr.isGlobalPreferred() && linkAddr.getPrefixLength() == 64) { 224 v6only.addLinkAddress(linkAddr); 225 } 226 } 227 228 for (RouteInfo routeInfo : lp.getRoutes()) { 229 final IpPrefix destination = routeInfo.getDestination(); 230 if ((destination.getAddress() instanceof Inet6Address) && 231 (destination.getPrefixLength() <= 64)) { 232 v6only.addRoute(routeInfo); 233 } 234 } 235 236 for (InetAddress dnsServer : lp.getDnsServers()) { 237 if (isIPv6GlobalAddress(dnsServer)) { 238 // For now we include ULAs. 239 v6only.addDnsServer(dnsServer); 240 } 241 } 242 243 v6only.setDomains(lp.getDomains()); 244 245 return v6only; 246 } 247 248 // TODO: Delete this and switch to LinkAddress#isGlobalPreferred once we 249 // announce our own IPv6 address as DNS server. isIPv6GlobalAddress(InetAddress ip)250 private static boolean isIPv6GlobalAddress(InetAddress ip) { 251 return (ip instanceof Inet6Address) && 252 !ip.isAnyLocalAddress() && 253 !ip.isLoopbackAddress() && 254 !ip.isLinkLocalAddress() && 255 !ip.isSiteLocalAddress() && 256 !ip.isMulticastAddress(); 257 } 258 getUniqueLocalConfig(byte[] ulp, short subnetId)259 private static LinkProperties getUniqueLocalConfig(byte[] ulp, short subnetId) { 260 final LinkProperties lp = new LinkProperties(); 261 262 final IpPrefix local48 = makeUniqueLocalPrefix(ulp, (short) 0, 48); 263 lp.addRoute(new RouteInfo(local48, null, null)); 264 265 final IpPrefix local64 = makeUniqueLocalPrefix(ulp, subnetId, 64); 266 // Because this is a locally-generated ULA, we don't have an upstream 267 // address. But because the downstream IP address management code gets 268 // its prefix from the upstream's IP address, we create a fake one here. 269 lp.addLinkAddress(new LinkAddress(local64.getAddress(), 64)); 270 271 lp.setMtu(NetworkConstants.ETHER_MTU); 272 return lp; 273 } 274 makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen)275 private static IpPrefix makeUniqueLocalPrefix(byte[] in6addr, short subnetId, int prefixlen) { 276 final byte[] bytes = Arrays.copyOf(in6addr, in6addr.length); 277 bytes[7] = (byte) (subnetId >> 8); 278 bytes[8] = (byte) subnetId; 279 return new IpPrefix(bytes, prefixlen); 280 } 281 282 // Generates a Unique Locally-assigned Prefix: 283 // 284 // https://tools.ietf.org/html/rfc4193#section-3.1 285 // 286 // The result is a /48 that can be used for local-only communications. generateUniqueLocalPrefix()287 private static byte[] generateUniqueLocalPrefix() { 288 final byte[] ulp = new byte[6]; // 6 = 48bits / 8bits/byte 289 (new Random()).nextBytes(ulp); 290 291 final byte[] in6addr = Arrays.copyOf(ulp, NetworkConstants.IPV6_ADDR_LEN); 292 in6addr[0] = (byte) 0xfd; // fc00::/7 and L=1 293 294 return in6addr; 295 } 296 toDebugString(NetworkState ns)297 private static String toDebugString(NetworkState ns) { 298 if (ns == null) { 299 return "NetworkState{null}"; 300 } 301 return String.format("NetworkState{%s, %s, %s}", 302 ns.network, 303 ns.networkCapabilities, 304 ns.linkProperties); 305 } 306 stopIPv6TetheringOn(IpServer ipServer)307 private static void stopIPv6TetheringOn(IpServer ipServer) { 308 ipServer.sendMessage(IpServer.CMD_IPV6_TETHER_UPDATE, 0, 0, null); 309 } 310 } 311