diff options
Diffstat (limited to 'packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java')
-rw-r--r-- | packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java | 744 |
1 files changed, 0 insertions, 744 deletions
diff --git a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java b/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java deleted file mode 100644 index 7c0b7cc7515c..000000000000 --- a/packages/Tethering/src/android/net/ip/RouterAdvertisementDaemon.java +++ /dev/null @@ -1,744 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.net.ip; - -import static android.net.util.NetworkConstants.IPV6_MIN_MTU; -import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; -import static android.net.util.TetheringUtils.getAllNodesForScopeId; -import static android.system.OsConstants.AF_INET6; -import static android.system.OsConstants.IPPROTO_ICMPV6; -import static android.system.OsConstants.SOCK_RAW; -import static android.system.OsConstants.SOL_SOCKET; -import static android.system.OsConstants.SO_SNDTIMEO; - -import android.net.IpPrefix; -import android.net.LinkAddress; -import android.net.TrafficStats; -import android.net.util.InterfaceParams; -import android.net.util.SocketUtils; -import android.net.util.TetheringUtils; -import android.system.ErrnoException; -import android.system.Os; -import android.system.StructTimeval; -import android.util.Log; - -import com.android.internal.annotations.GuardedBy; -import com.android.internal.util.TrafficStatsConstants; - -import java.io.FileDescriptor; -import java.io.IOException; -import java.net.Inet6Address; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.SocketException; -import java.nio.BufferOverflowException; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.atomic.AtomicInteger; - - -/** - * Basic IPv6 Router Advertisement Daemon. - * - * TODO: - * - * - Rewrite using Handler (and friends) so that AlarmManager can deliver - * "kick" messages when it's time to send a multicast RA. - * - * @hide - */ -public class RouterAdvertisementDaemon { - private static final String TAG = RouterAdvertisementDaemon.class.getSimpleName(); - private static final byte ICMPV6_ND_ROUTER_SOLICIT = asByte(133); - private static final byte ICMPV6_ND_ROUTER_ADVERT = asByte(134); - private static final int MIN_RA_HEADER_SIZE = 16; - - // Summary of various timers and lifetimes. - private static final int MIN_RTR_ADV_INTERVAL_SEC = 300; - private static final int MAX_RTR_ADV_INTERVAL_SEC = 600; - // In general, router, prefix, and DNS lifetimes are all advised to be - // greater than or equal to 3 * MAX_RTR_ADV_INTERVAL. Here, we double - // that to allow for multicast packet loss. - // - // This MAX_RTR_ADV_INTERVAL_SEC and DEFAULT_LIFETIME are also consistent - // with the https://tools.ietf.org/html/rfc7772#section-4 discussion of - // "approximately 7 RAs per hour". - private static final int DEFAULT_LIFETIME = 6 * MAX_RTR_ADV_INTERVAL_SEC; - // From https://tools.ietf.org/html/rfc4861#section-10 . - private static final int MIN_DELAY_BETWEEN_RAS_SEC = 3; - // Both initial and final RAs, but also for changes in RA contents. - // From https://tools.ietf.org/html/rfc4861#section-10 . - private static final int MAX_URGENT_RTR_ADVERTISEMENTS = 5; - - private static final int DAY_IN_SECONDS = 86_400; - - private final InterfaceParams mInterface; - private final InetSocketAddress mAllNodes; - - // This lock is to protect the RA from being updated while being - // transmitted on another thread (multicast or unicast). - // - // TODO: This should be handled with a more RCU-like approach. - private final Object mLock = new Object(); - @GuardedBy("mLock") - private final byte[] mRA = new byte[IPV6_MIN_MTU]; - @GuardedBy("mLock") - private int mRaLength; - @GuardedBy("mLock") - private final DeprecatedInfoTracker mDeprecatedInfoTracker; - @GuardedBy("mLock") - private RaParams mRaParams; - - private volatile FileDescriptor mSocket; - private volatile MulticastTransmitter mMulticastTransmitter; - private volatile UnicastResponder mUnicastResponder; - - /** Encapsulate the RA parameters for RouterAdvertisementDaemon.*/ - public static class RaParams { - // Tethered traffic will have the hop limit properly decremented. - // Consequently, set the hoplimit greater by one than the upstream - // unicast hop limit. - // - // TODO: Dynamically pass down the IPV6_UNICAST_HOPS value from the - // upstream interface for more correct behaviour. - static final byte DEFAULT_HOPLIMIT = 65; - - public boolean hasDefaultRoute; - public byte hopLimit; - public int mtu; - public HashSet<IpPrefix> prefixes; - public HashSet<Inet6Address> dnses; - - public RaParams() { - hasDefaultRoute = false; - hopLimit = DEFAULT_HOPLIMIT; - mtu = IPV6_MIN_MTU; - prefixes = new HashSet<IpPrefix>(); - dnses = new HashSet<Inet6Address>(); - } - - public RaParams(RaParams other) { - hasDefaultRoute = other.hasDefaultRoute; - hopLimit = other.hopLimit; - mtu = other.mtu; - prefixes = (HashSet) other.prefixes.clone(); - dnses = (HashSet) other.dnses.clone(); - } - - /** - * Returns the subset of RA parameters that become deprecated when - * moving from announcing oldRa to announcing newRa. - * - * Currently only tracks differences in |prefixes| and |dnses|. - */ - public static RaParams getDeprecatedRaParams(RaParams oldRa, RaParams newRa) { - RaParams newlyDeprecated = new RaParams(); - - if (oldRa != null) { - for (IpPrefix ipp : oldRa.prefixes) { - if (newRa == null || !newRa.prefixes.contains(ipp)) { - newlyDeprecated.prefixes.add(ipp); - } - } - - for (Inet6Address dns : oldRa.dnses) { - if (newRa == null || !newRa.dnses.contains(dns)) { - newlyDeprecated.dnses.add(dns); - } - } - } - - return newlyDeprecated; - } - } - - private static class DeprecatedInfoTracker { - private final HashMap<IpPrefix, Integer> mPrefixes = new HashMap<>(); - private final HashMap<Inet6Address, Integer> mDnses = new HashMap<>(); - - Set<IpPrefix> getPrefixes() { - return mPrefixes.keySet(); - } - - void putPrefixes(Set<IpPrefix> prefixes) { - for (IpPrefix ipp : prefixes) { - mPrefixes.put(ipp, MAX_URGENT_RTR_ADVERTISEMENTS); - } - } - - void removePrefixes(Set<IpPrefix> prefixes) { - for (IpPrefix ipp : prefixes) { - mPrefixes.remove(ipp); - } - } - - Set<Inet6Address> getDnses() { - return mDnses.keySet(); - } - - void putDnses(Set<Inet6Address> dnses) { - for (Inet6Address dns : dnses) { - mDnses.put(dns, MAX_URGENT_RTR_ADVERTISEMENTS); - } - } - - void removeDnses(Set<Inet6Address> dnses) { - for (Inet6Address dns : dnses) { - mDnses.remove(dns); - } - } - - boolean isEmpty() { - return mPrefixes.isEmpty() && mDnses.isEmpty(); - } - - private boolean decrementCounters() { - boolean removed = decrementCounter(mPrefixes); - removed |= decrementCounter(mDnses); - return removed; - } - - private <T> boolean decrementCounter(HashMap<T, Integer> map) { - boolean removed = false; - - for (Iterator<Map.Entry<T, Integer>> it = map.entrySet().iterator(); - it.hasNext();) { - Map.Entry<T, Integer> kv = it.next(); - if (kv.getValue() == 0) { - it.remove(); - removed = true; - } else { - kv.setValue(kv.getValue() - 1); - } - } - - return removed; - } - } - - public RouterAdvertisementDaemon(InterfaceParams ifParams) { - mInterface = ifParams; - mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0); - mDeprecatedInfoTracker = new DeprecatedInfoTracker(); - } - - /** Build new RA.*/ - public void buildNewRa(RaParams deprecatedParams, RaParams newParams) { - synchronized (mLock) { - if (deprecatedParams != null) { - mDeprecatedInfoTracker.putPrefixes(deprecatedParams.prefixes); - mDeprecatedInfoTracker.putDnses(deprecatedParams.dnses); - } - - if (newParams != null) { - // Process information that is no longer deprecated. - mDeprecatedInfoTracker.removePrefixes(newParams.prefixes); - mDeprecatedInfoTracker.removeDnses(newParams.dnses); - } - - mRaParams = newParams; - assembleRaLocked(); - } - - maybeNotifyMulticastTransmitter(); - } - - /** Start router advertisement daemon. */ - public boolean start() { - if (!createSocket()) { - return false; - } - - mMulticastTransmitter = new MulticastTransmitter(); - mMulticastTransmitter.start(); - - mUnicastResponder = new UnicastResponder(); - mUnicastResponder.start(); - - return true; - } - - /** Stop router advertisement daemon. */ - public void stop() { - closeSocket(); - // Wake up mMulticastTransmitter thread to interrupt a potential 1 day sleep before - // the thread's termination. - maybeNotifyMulticastTransmitter(); - mMulticastTransmitter = null; - mUnicastResponder = null; - } - - @GuardedBy("mLock") - private void assembleRaLocked() { - final ByteBuffer ra = ByteBuffer.wrap(mRA); - ra.order(ByteOrder.BIG_ENDIAN); - - final boolean haveRaParams = (mRaParams != null); - boolean shouldSendRA = false; - - try { - putHeader(ra, haveRaParams && mRaParams.hasDefaultRoute, - haveRaParams ? mRaParams.hopLimit : RaParams.DEFAULT_HOPLIMIT); - putSlla(ra, mInterface.macAddr.toByteArray()); - mRaLength = ra.position(); - - // https://tools.ietf.org/html/rfc5175#section-4 says: - // - // "MUST NOT be added to a Router Advertisement message - // if no flags in the option are set." - // - // putExpandedFlagsOption(ra); - - if (haveRaParams) { - putMtu(ra, mRaParams.mtu); - mRaLength = ra.position(); - - for (IpPrefix ipp : mRaParams.prefixes) { - putPio(ra, ipp, DEFAULT_LIFETIME, DEFAULT_LIFETIME); - mRaLength = ra.position(); - shouldSendRA = true; - } - - if (mRaParams.dnses.size() > 0) { - putRdnss(ra, mRaParams.dnses, DEFAULT_LIFETIME); - mRaLength = ra.position(); - shouldSendRA = true; - } - } - - for (IpPrefix ipp : mDeprecatedInfoTracker.getPrefixes()) { - putPio(ra, ipp, 0, 0); - mRaLength = ra.position(); - shouldSendRA = true; - } - - final Set<Inet6Address> deprecatedDnses = mDeprecatedInfoTracker.getDnses(); - if (!deprecatedDnses.isEmpty()) { - putRdnss(ra, deprecatedDnses, 0); - mRaLength = ra.position(); - shouldSendRA = true; - } - } catch (BufferOverflowException e) { - // The packet up to mRaLength is valid, since it has been updated - // progressively as the RA was built. Log an error, and continue - // on as best as possible. - Log.e(TAG, "Could not construct new RA: " + e); - } - - // We have nothing worth announcing; indicate as much to maybeSendRA(). - if (!shouldSendRA) { - mRaLength = 0; - } - } - - private void maybeNotifyMulticastTransmitter() { - final MulticastTransmitter m = mMulticastTransmitter; - if (m != null) { - m.hup(); - } - } - - private static byte asByte(int value) { - return (byte) value; - } - private static short asShort(int value) { - return (short) value; - } - - private static void putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit) { - /** - Router Advertisement Message Format - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Code | Checksum | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Cur Hop Limit |M|O|H|Prf|P|R|R| Router Lifetime | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Reachable Time | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Retrans Timer | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Options ... - +-+-+-+-+-+-+-+-+-+-+-+- - */ - ra.put(ICMPV6_ND_ROUTER_ADVERT) - .put(asByte(0)) - .putShort(asShort(0)) - .put(hopLimit) - // RFC 4191 "high" preference, iff. advertising a default route. - .put(hasDefaultRoute ? asByte(0x08) : asByte(0)) - .putShort(hasDefaultRoute ? asShort(DEFAULT_LIFETIME) : asShort(0)) - .putInt(0) - .putInt(0); - } - - private static void putSlla(ByteBuffer ra, byte[] slla) { - /** - Source/Target Link-layer Address - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Link-Layer Address ... - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - if (slla == null || slla.length != 6) { - // Only IEEE 802.3 6-byte addresses are supported. - return; - } - - final byte nd_option_slla = 1; - final byte slla_num_8octets = 1; - ra.put(nd_option_slla) - .put(slla_num_8octets) - .put(slla); - } - - private static void putExpandedFlagsOption(ByteBuffer ra) { - /** - Router Advertisement Expanded Flags Option - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Bit fields available .. - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - ... for assignment | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - - final byte nd_option__efo = 26; - final byte efo_num_8octets = 1; - - ra.put(nd_option__efo) - .put(efo_num_8octets) - .putShort(asShort(0)) - .putInt(0); - } - - private static void putMtu(ByteBuffer ra, int mtu) { - /** - MTU - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Reserved | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | MTU | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - final byte nd_option_mtu = 5; - final byte mtu_num_8octs = 1; - ra.put(nd_option_mtu) - .put(mtu_num_8octs) - .putShort(asShort(0)) - .putInt((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu); - } - - private static void putPio(ByteBuffer ra, IpPrefix ipp, - int validTime, int preferredTime) { - /** - Prefix Information - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Prefix Length |L|A| Reserved1 | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Valid Lifetime | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Preferred Lifetime | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Reserved2 | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | | - + + - | | - + Prefix + - | | - + + - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - final int prefixLength = ipp.getPrefixLength(); - if (prefixLength != 64) { - return; - } - final byte nd_option_pio = 3; - final byte pio_num_8octets = 4; - - if (validTime < 0) validTime = 0; - if (preferredTime < 0) preferredTime = 0; - if (preferredTime > validTime) preferredTime = validTime; - - final byte[] addr = ipp.getAddress().getAddress(); - ra.put(nd_option_pio) - .put(pio_num_8octets) - .put(asByte(prefixLength)) - .put(asByte(0xc0)) /* L & A set */ - .putInt(validTime) - .putInt(preferredTime) - .putInt(0) - .put(addr); - } - - private static void putRio(ByteBuffer ra, IpPrefix ipp) { - /** - Route Information Option - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Prefix Length |Resvd|Prf|Resvd| - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Route Lifetime | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Prefix (Variable Length) | - . . - . . - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - final int prefixLength = ipp.getPrefixLength(); - if (prefixLength > 64) { - return; - } - final byte nd_option_rio = 24; - final byte rio_num_8octets = asByte( - (prefixLength == 0) ? 1 : (prefixLength <= 8) ? 2 : 3); - - final byte[] addr = ipp.getAddress().getAddress(); - ra.put(nd_option_rio) - .put(rio_num_8octets) - .put(asByte(prefixLength)) - .put(asByte(0x18)) - .putInt(DEFAULT_LIFETIME); - - // Rely upon an IpPrefix's address being properly zeroed. - if (prefixLength > 0) { - ra.put(addr, 0, (prefixLength <= 64) ? 8 : 16); - } - } - - private static void putRdnss(ByteBuffer ra, Set<Inet6Address> dnses, int lifetime) { - /** - Recursive DNS Server (RDNSS) Option - - 0 1 2 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Type | Length | Reserved | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | Lifetime | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | | - : Addresses of IPv6 Recursive DNS Servers : - | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - */ - - final HashSet<Inet6Address> filteredDnses = new HashSet<>(); - for (Inet6Address dns : dnses) { - if ((new LinkAddress(dns, RFC7421_PREFIX_LENGTH)).isGlobalPreferred()) { - filteredDnses.add(dns); - } - } - if (filteredDnses.isEmpty()) return; - - final byte nd_option_rdnss = 25; - final byte rdnss_num_8octets = asByte(dnses.size() * 2 + 1); - ra.put(nd_option_rdnss) - .put(rdnss_num_8octets) - .putShort(asShort(0)) - .putInt(lifetime); - - for (Inet6Address dns : filteredDnses) { - // NOTE: If the full of list DNS servers doesn't fit in the packet, - // this code will cause a buffer overflow and the RA won't include - // this instance of the option at all. - // - // TODO: Consider looking at ra.remaining() to determine how many - // DNS servers will fit, and adding only those. - ra.put(dns.getAddress()); - } - } - - private boolean createSocket() { - final int send_timout_ms = 300; - - final int oldTag = TrafficStats.getAndSetThreadStatsTag( - TrafficStatsConstants.TAG_SYSTEM_NEIGHBOR); - try { - mSocket = Os.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); - // Setting SNDTIMEO is purely for defensive purposes. - Os.setsockoptTimeval( - mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(send_timout_ms)); - SocketUtils.bindSocketToInterface(mSocket, mInterface.name); - TetheringUtils.setupRaSocket(mSocket, mInterface.index); - } catch (ErrnoException | IOException e) { - Log.e(TAG, "Failed to create RA daemon socket: " + e); - return false; - } finally { - TrafficStats.setThreadStatsTag(oldTag); - } - - return true; - } - - private void closeSocket() { - if (mSocket != null) { - try { - SocketUtils.closeSocket(mSocket); - } catch (IOException ignored) { } - } - mSocket = null; - } - - private boolean isSocketValid() { - final FileDescriptor s = mSocket; - return (s != null) && s.valid(); - } - - private boolean isSuitableDestination(InetSocketAddress dest) { - if (mAllNodes.equals(dest)) { - return true; - } - - final InetAddress destip = dest.getAddress(); - return (destip instanceof Inet6Address) - && destip.isLinkLocalAddress() - && (((Inet6Address) destip).getScopeId() == mInterface.index); - } - - private void maybeSendRA(InetSocketAddress dest) { - if (dest == null || !isSuitableDestination(dest)) { - dest = mAllNodes; - } - - try { - synchronized (mLock) { - if (mRaLength < MIN_RA_HEADER_SIZE) { - // No actual RA to send. - return; - } - Os.sendto(mSocket, mRA, 0, mRaLength, 0, dest); - } - Log.d(TAG, "RA sendto " + dest.getAddress().getHostAddress()); - } catch (ErrnoException | SocketException e) { - if (isSocketValid()) { - Log.e(TAG, "sendto error: " + e); - } - } - } - - private final class UnicastResponder extends Thread { - private final InetSocketAddress mSolicitor = new InetSocketAddress(0); - // The recycled buffer for receiving Router Solicitations from clients. - // If the RS is larger than IPV6_MIN_MTU the packets are truncated. - // This is fine since currently only byte 0 is examined anyway. - private final byte[] mSolicitation = new byte[IPV6_MIN_MTU]; - - @Override - public void run() { - while (isSocketValid()) { - try { - // Blocking receive. - final int rval = Os.recvfrom( - mSocket, mSolicitation, 0, mSolicitation.length, 0, mSolicitor); - // Do the least possible amount of validation. - if (rval < 1 || mSolicitation[0] != ICMPV6_ND_ROUTER_SOLICIT) { - continue; - } - } catch (ErrnoException | SocketException e) { - if (isSocketValid()) { - Log.e(TAG, "recvfrom error: " + e); - } - continue; - } - - maybeSendRA(mSolicitor); - } - } - } - - // TODO: Consider moving this to run on a provided Looper as a Handler, - // with WakeupMessage-style messages providing the timer driven input. - private final class MulticastTransmitter extends Thread { - private final Random mRandom = new Random(); - private final AtomicInteger mUrgentAnnouncements = new AtomicInteger(0); - - @Override - public void run() { - while (isSocketValid()) { - try { - Thread.sleep(getNextMulticastTransmitDelayMs()); - } catch (InterruptedException ignored) { - // Stop sleeping, immediately send an RA, and continue. - } - - maybeSendRA(mAllNodes); - synchronized (mLock) { - if (mDeprecatedInfoTracker.decrementCounters()) { - // At least one deprecated PIO has been removed; - // reassemble the RA. - assembleRaLocked(); - } - } - } - } - - public void hup() { - // Set to one fewer that the desired number, because as soon as - // the thread interrupt is processed we immediately send an RA - // and mUrgentAnnouncements is not examined until the subsequent - // sleep interval computation (i.e. this way we send 3 and not 4). - mUrgentAnnouncements.set(MAX_URGENT_RTR_ADVERTISEMENTS - 1); - interrupt(); - } - - private int getNextMulticastTransmitDelaySec() { - boolean deprecationInProgress = false; - synchronized (mLock) { - if (mRaLength < MIN_RA_HEADER_SIZE) { - // No actual RA to send; just sleep for 1 day. - return DAY_IN_SECONDS; - } - deprecationInProgress = !mDeprecatedInfoTracker.isEmpty(); - } - - final int urgentPending = mUrgentAnnouncements.getAndDecrement(); - if ((urgentPending > 0) || deprecationInProgress) { - return MIN_DELAY_BETWEEN_RAS_SEC; - } - - return MIN_RTR_ADV_INTERVAL_SEC + mRandom.nextInt( - MAX_RTR_ADV_INTERVAL_SEC - MIN_RTR_ADV_INTERVAL_SEC); - } - - private long getNextMulticastTransmitDelayMs() { - return 1000 * (long) getNextMulticastTransmitDelaySec(); - } - } -} |