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 android.net.ip;
18 
19 import static android.system.OsConstants.AF_INET6;
20 import static android.system.OsConstants.IPPROTO_ICMPV6;
21 import static android.system.OsConstants.SOCK_RAW;
22 import static android.system.OsConstants.SOL_SOCKET;
23 import static android.system.OsConstants.SO_SNDTIMEO;
24 
25 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
26 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_RA_HEADER_LEN;
27 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
28 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
29 import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
30 import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS;
31 import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK;
32 import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
33 import static com.android.net.module.util.NetworkStackConstants.TAG_SYSTEM_NEIGHBOR;
34 import static com.android.networkstack.tethering.util.TetheringUtils.getAllNodesForScopeId;
35 
36 import android.net.IpPrefix;
37 import android.net.LinkAddress;
38 import android.net.MacAddress;
39 import android.net.TrafficStats;
40 import android.net.util.SocketUtils;
41 import android.system.ErrnoException;
42 import android.system.Os;
43 import android.system.StructTimeval;
44 import android.util.ArraySet;
45 import android.util.Log;
46 
47 import com.android.internal.annotations.GuardedBy;
48 import com.android.net.module.util.InterfaceParams;
49 import com.android.net.module.util.structs.Icmpv6Header;
50 import com.android.net.module.util.structs.LlaOption;
51 import com.android.net.module.util.structs.MtuOption;
52 import com.android.net.module.util.structs.PrefixInformationOption;
53 import com.android.net.module.util.structs.RaHeader;
54 import com.android.net.module.util.structs.RdnssOption;
55 import com.android.networkstack.tethering.util.TetheringUtils;
56 
57 import java.io.FileDescriptor;
58 import java.io.IOException;
59 import java.net.Inet6Address;
60 import java.net.InetAddress;
61 import java.net.InetSocketAddress;
62 import java.net.SocketException;
63 import java.nio.BufferOverflowException;
64 import java.nio.ByteBuffer;
65 import java.nio.ByteOrder;
66 import java.util.HashMap;
67 import java.util.HashSet;
68 import java.util.Iterator;
69 import java.util.Map;
70 import java.util.Random;
71 import java.util.Set;
72 import java.util.concurrent.atomic.AtomicInteger;
73 
74 
75 /**
76  * Basic IPv6 Router Advertisement Daemon.
77  *
78  * TODO:
79  *
80  *     - Rewrite using Handler (and friends) so that AlarmManager can deliver
81  *       "kick" messages when it's time to send a multicast RA.
82  *
83  * @hide
84  */
85 public class RouterAdvertisementDaemon {
86     private static final String TAG = RouterAdvertisementDaemon.class.getSimpleName();
87 
88     // Summary of various timers and lifetimes.
89     private static final int MIN_RTR_ADV_INTERVAL_SEC = 300;
90     private static final int MAX_RTR_ADV_INTERVAL_SEC = 600;
91     // In general, router, prefix, and DNS lifetimes are all advised to be
92     // greater than or equal to 3 * MAX_RTR_ADV_INTERVAL.  Here, we quadruple
93     // that to allow for multicast packet loss.
94     //
95     // This MAX_RTR_ADV_INTERVAL_SEC and DEFAULT_LIFETIME are also consistent
96     // with the https://tools.ietf.org/html/rfc7772#section-4 discussion of
97     // "approximately 7 RAs per hour".
98     private static final int DEFAULT_LIFETIME = 12 * MAX_RTR_ADV_INTERVAL_SEC;
99     // From https://tools.ietf.org/html/rfc4861#section-10 .
100     private static final int MIN_DELAY_BETWEEN_RAS_SEC = 3;
101     // Both initial and final RAs, but also for changes in RA contents.
102     // From https://tools.ietf.org/html/rfc4861#section-10 .
103     private static final int  MAX_URGENT_RTR_ADVERTISEMENTS = 5;
104 
105     private static final int DAY_IN_SECONDS = 86_400;
106 
107     private final InterfaceParams mInterface;
108     private final InetSocketAddress mAllNodes;
109 
110     // This lock is to protect the RA from being updated while being
111     // transmitted on another thread  (multicast or unicast).
112     //
113     // TODO: This should be handled with a more RCU-like approach.
114     private final Object mLock = new Object();
115     @GuardedBy("mLock")
116     private final byte[] mRA = new byte[IPV6_MIN_MTU];
117     @GuardedBy("mLock")
118     private int mRaLength;
119     @GuardedBy("mLock")
120     private final DeprecatedInfoTracker mDeprecatedInfoTracker;
121     @GuardedBy("mLock")
122     private RaParams mRaParams;
123 
124     private volatile FileDescriptor mSocket;
125     private volatile MulticastTransmitter mMulticastTransmitter;
126     private volatile UnicastResponder mUnicastResponder;
127 
128     /** Encapsulate the RA parameters for RouterAdvertisementDaemon.*/
129     public static class RaParams {
130         // Tethered traffic will have the hop limit properly decremented.
131         // Consequently, set the hoplimit greater by one than the upstream
132         // unicast hop limit.
133         static final byte DEFAULT_HOPLIMIT = 65;
134 
135         public boolean hasDefaultRoute;
136         public byte hopLimit;
137         public int mtu;
138         public ArraySet<IpPrefix> prefixes;
139         public ArraySet<Inet6Address> dnses;
140 
RaParams()141         public RaParams() {
142             hasDefaultRoute = false;
143             hopLimit = DEFAULT_HOPLIMIT;
144             mtu = IPV6_MIN_MTU;
145             prefixes = new ArraySet<IpPrefix>();
146             dnses = new ArraySet<Inet6Address>();
147         }
148 
RaParams(RaParams other)149         public RaParams(RaParams other) {
150             hasDefaultRoute = other.hasDefaultRoute;
151             hopLimit = other.hopLimit;
152             mtu = other.mtu;
153             prefixes = new ArraySet<IpPrefix>(other.prefixes);
154             dnses = new ArraySet<Inet6Address>(other.dnses);
155         }
156 
157         /**
158          * Returns the subset of RA parameters that become deprecated when
159          * moving from announcing oldRa to announcing newRa.
160          *
161          * Currently only tracks differences in |prefixes| and |dnses|.
162          */
getDeprecatedRaParams(RaParams oldRa, RaParams newRa)163         public static RaParams getDeprecatedRaParams(RaParams oldRa, RaParams newRa) {
164             RaParams newlyDeprecated = new RaParams();
165 
166             if (oldRa != null) {
167                 for (IpPrefix ipp : oldRa.prefixes) {
168                     if (newRa == null || !newRa.prefixes.contains(ipp)) {
169                         newlyDeprecated.prefixes.add(ipp);
170                     }
171                 }
172 
173                 for (Inet6Address dns : oldRa.dnses) {
174                     if (newRa == null || !newRa.dnses.contains(dns)) {
175                         newlyDeprecated.dnses.add(dns);
176                     }
177                 }
178             }
179 
180             return newlyDeprecated;
181         }
182     }
183 
184     private static class DeprecatedInfoTracker {
185         private final HashMap<IpPrefix, Integer> mPrefixes = new HashMap<>();
186         private final HashMap<Inet6Address, Integer> mDnses = new HashMap<>();
187 
getPrefixes()188         Set<IpPrefix> getPrefixes() {
189             return mPrefixes.keySet();
190         }
191 
putPrefixes(Set<IpPrefix> prefixes)192         void putPrefixes(Set<IpPrefix> prefixes) {
193             for (IpPrefix ipp : prefixes) {
194                 mPrefixes.put(ipp, MAX_URGENT_RTR_ADVERTISEMENTS);
195             }
196         }
197 
removePrefixes(Set<IpPrefix> prefixes)198         void removePrefixes(Set<IpPrefix> prefixes) {
199             for (IpPrefix ipp : prefixes) {
200                 mPrefixes.remove(ipp);
201             }
202         }
203 
getDnses()204         Set<Inet6Address> getDnses() {
205             return mDnses.keySet();
206         }
207 
putDnses(Set<Inet6Address> dnses)208         void putDnses(Set<Inet6Address> dnses) {
209             for (Inet6Address dns : dnses) {
210                 mDnses.put(dns, MAX_URGENT_RTR_ADVERTISEMENTS);
211             }
212         }
213 
removeDnses(Set<Inet6Address> dnses)214         void removeDnses(Set<Inet6Address> dnses) {
215             for (Inet6Address dns : dnses) {
216                 mDnses.remove(dns);
217             }
218         }
219 
isEmpty()220         boolean isEmpty() {
221             return mPrefixes.isEmpty() && mDnses.isEmpty();
222         }
223 
decrementCounters()224         private boolean decrementCounters() {
225             boolean removed = decrementCounter(mPrefixes);
226             removed |= decrementCounter(mDnses);
227             return removed;
228         }
229 
decrementCounter(HashMap<T, Integer> map)230         private <T> boolean decrementCounter(HashMap<T, Integer> map) {
231             boolean removed = false;
232 
233             for (Iterator<Map.Entry<T, Integer>> it = map.entrySet().iterator();
234                     it.hasNext();) {
235                 Map.Entry<T, Integer> kv = it.next();
236                 if (kv.getValue() == 0) {
237                     it.remove();
238                     removed = true;
239                 } else {
240                     kv.setValue(kv.getValue() - 1);
241                 }
242             }
243 
244             return removed;
245         }
246     }
247 
RouterAdvertisementDaemon(InterfaceParams ifParams)248     public RouterAdvertisementDaemon(InterfaceParams ifParams) {
249         mInterface = ifParams;
250         mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0);
251         mDeprecatedInfoTracker = new DeprecatedInfoTracker();
252     }
253 
254     /** Build new RA.*/
buildNewRa(RaParams deprecatedParams, RaParams newParams)255     public void buildNewRa(RaParams deprecatedParams, RaParams newParams) {
256         synchronized (mLock) {
257             if (deprecatedParams != null) {
258                 mDeprecatedInfoTracker.putPrefixes(deprecatedParams.prefixes);
259                 mDeprecatedInfoTracker.putDnses(deprecatedParams.dnses);
260             }
261 
262             if (newParams != null) {
263                 // Process information that is no longer deprecated.
264                 mDeprecatedInfoTracker.removePrefixes(newParams.prefixes);
265                 mDeprecatedInfoTracker.removeDnses(newParams.dnses);
266             }
267 
268             mRaParams = newParams;
269             assembleRaLocked();
270         }
271 
272         maybeNotifyMulticastTransmitter();
273     }
274 
275     /** Start router advertisement daemon. */
start()276     public boolean start() {
277         if (!createSocket()) {
278             return false;
279         }
280 
281         mMulticastTransmitter = new MulticastTransmitter();
282         mMulticastTransmitter.start();
283 
284         mUnicastResponder = new UnicastResponder();
285         mUnicastResponder.start();
286 
287         return true;
288     }
289 
290     /** Stop router advertisement daemon. */
stop()291     public void stop() {
292         closeSocket();
293         // Wake up mMulticastTransmitter thread to interrupt a potential 1 day sleep before
294         // the thread's termination.
295         maybeNotifyMulticastTransmitter();
296         mMulticastTransmitter = null;
297         mUnicastResponder = null;
298     }
299 
300     @GuardedBy("mLock")
assembleRaLocked()301     private void assembleRaLocked() {
302         final ByteBuffer ra = ByteBuffer.wrap(mRA);
303         ra.order(ByteOrder.BIG_ENDIAN);
304 
305         final boolean haveRaParams = (mRaParams != null);
306         boolean shouldSendRA = false;
307 
308         try {
309             putHeader(ra, haveRaParams && mRaParams.hasDefaultRoute,
310                     haveRaParams ? mRaParams.hopLimit : RaParams.DEFAULT_HOPLIMIT);
311             putSlla(ra, mInterface.macAddr.toByteArray());
312             mRaLength = ra.position();
313 
314             // https://tools.ietf.org/html/rfc5175#section-4 says:
315             //
316             //     "MUST NOT be added to a Router Advertisement message
317             //      if no flags in the option are set."
318             //
319             // putExpandedFlagsOption(ra);
320 
321             if (haveRaParams) {
322                 putMtu(ra, mRaParams.mtu);
323                 mRaLength = ra.position();
324 
325                 for (IpPrefix ipp : mRaParams.prefixes) {
326                     putPio(ra, ipp, DEFAULT_LIFETIME, DEFAULT_LIFETIME);
327                     mRaLength = ra.position();
328                     shouldSendRA = true;
329                 }
330 
331                 if (mRaParams.dnses.size() > 0) {
332                     putRdnss(ra, mRaParams.dnses, DEFAULT_LIFETIME);
333                     mRaLength = ra.position();
334                     shouldSendRA = true;
335                 }
336             }
337 
338             for (IpPrefix ipp : mDeprecatedInfoTracker.getPrefixes()) {
339                 putPio(ra, ipp, 0, 0);
340                 mRaLength = ra.position();
341                 shouldSendRA = true;
342             }
343 
344             final Set<Inet6Address> deprecatedDnses = mDeprecatedInfoTracker.getDnses();
345             if (!deprecatedDnses.isEmpty()) {
346                 putRdnss(ra, deprecatedDnses, 0);
347                 mRaLength = ra.position();
348                 shouldSendRA = true;
349             }
350         } catch (BufferOverflowException e) {
351             // The packet up to mRaLength  is valid, since it has been updated
352             // progressively as the RA was built. Log an error, and continue
353             // on as best as possible.
354             Log.e(TAG, "Could not construct new RA: " + e);
355         }
356 
357         // We have nothing worth announcing; indicate as much to maybeSendRA().
358         if (!shouldSendRA) {
359             mRaLength = 0;
360         }
361     }
362 
maybeNotifyMulticastTransmitter()363     private void maybeNotifyMulticastTransmitter() {
364         final MulticastTransmitter m = mMulticastTransmitter;
365         if (m != null) {
366             m.hup();
367         }
368     }
369 
asByte(int value)370     private static byte asByte(int value) {
371         return (byte) value;
372     }
asShort(int value)373     private static short asShort(int value) {
374         return (short) value;
375     }
376 
putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit)377     private static void putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit) {
378         // RFC 4191 "high" preference, iff. advertising a default route.
379         final byte flags = hasDefaultRoute ? asByte(0x08) : asByte(0);
380         final short lifetime = hasDefaultRoute ? asShort(DEFAULT_LIFETIME) : asShort(0);
381         final Icmpv6Header icmpv6Header =
382                 new Icmpv6Header(asByte(ICMPV6_ROUTER_ADVERTISEMENT) /* type */,
383                         asByte(0) /* code */, asShort(0) /* checksum */);
384         final RaHeader raHeader = new RaHeader(hopLimit, flags, lifetime, 0 /* reachableTime */,
385                 0 /* retransTimer */);
386         icmpv6Header.writeToByteBuffer(ra);
387         raHeader.writeToByteBuffer(ra);
388     }
389 
putSlla(ByteBuffer ra, byte[] slla)390     private static void putSlla(ByteBuffer ra, byte[] slla) {
391         if (slla == null || slla.length != 6) {
392             // Only IEEE 802.3 6-byte addresses are supported.
393             return;
394         }
395 
396         final ByteBuffer sllaOption = LlaOption.build(asByte(ICMPV6_ND_OPTION_SLLA),
397                 MacAddress.fromBytes(slla));
398         ra.put(sllaOption);
399     }
400 
putExpandedFlagsOption(ByteBuffer ra)401     private static void putExpandedFlagsOption(ByteBuffer ra) {
402         /**
403             Router Advertisement Expanded Flags Option
404 
405              0                   1                   2                   3
406              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
407             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
408             |     Type      |    Length     |         Bit fields available ..
409             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
410             ... for assignment                                              |
411             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
412          */
413 
414         final byte nd_option__efo = 26;
415         final byte efo_num_8octets = 1;
416 
417         ra.put(nd_option__efo)
418             .put(efo_num_8octets)
419             .putShort(asShort(0))
420             .putInt(0);
421     }
422 
putMtu(ByteBuffer ra, int mtu)423     private static void putMtu(ByteBuffer ra, int mtu) {
424         final ByteBuffer mtuOption = MtuOption.build((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu);
425         ra.put(mtuOption);
426     }
427 
putPio(ByteBuffer ra, IpPrefix ipp, int validTime, int preferredTime)428     private static void putPio(ByteBuffer ra, IpPrefix ipp,
429                                int validTime, int preferredTime) {
430         final int prefixLength = ipp.getPrefixLength();
431         if (prefixLength != 64) {
432             return;
433         }
434 
435         if (validTime < 0) validTime = 0;
436         if (preferredTime < 0) preferredTime = 0;
437         if (preferredTime > validTime) preferredTime = validTime;
438 
439         final ByteBuffer pioOption = PrefixInformationOption.build(ipp,
440                 asByte(PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), validTime, preferredTime);
441         ra.put(pioOption);
442     }
443 
putRio(ByteBuffer ra, IpPrefix ipp)444     private static void putRio(ByteBuffer ra, IpPrefix ipp) {
445         /**
446             Route Information Option
447 
448              0                   1                   2                   3
449              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
450             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
451             |     Type      |    Length     | Prefix Length |Resvd|Prf|Resvd|
452             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
453             |                        Route Lifetime                         |
454             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
455             |                   Prefix (Variable Length)                    |
456             .                                                               .
457             .                                                               .
458             +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
459          */
460         final int prefixLength = ipp.getPrefixLength();
461         if (prefixLength > 64) {
462             return;
463         }
464         final byte nd_option_rio = 24;
465         final byte rio_num_8octets = asByte(
466                 (prefixLength == 0) ? 1 : (prefixLength <= 8) ? 2 : 3);
467 
468         final byte[] addr = ipp.getAddress().getAddress();
469         ra.put(nd_option_rio)
470             .put(rio_num_8octets)
471             .put(asByte(prefixLength))
472             .put(asByte(0x18))
473             .putInt(DEFAULT_LIFETIME);
474 
475         // Rely upon an IpPrefix's address being properly zeroed.
476         if (prefixLength > 0) {
477             ra.put(addr, 0, (prefixLength <= 64) ? 8 : 16);
478         }
479     }
480 
putRdnss(ByteBuffer ra, Set<Inet6Address> dnses, int lifetime)481     private static void putRdnss(ByteBuffer ra, Set<Inet6Address> dnses, int lifetime) {
482         final HashSet<Inet6Address> filteredDnses = new HashSet<>();
483         for (Inet6Address dns : dnses) {
484             if ((new LinkAddress(dns, RFC7421_PREFIX_LENGTH)).isGlobalPreferred()) {
485                 filteredDnses.add(dns);
486             }
487         }
488         if (filteredDnses.isEmpty()) return;
489 
490         final Inet6Address[] dnsesArray =
491                 filteredDnses.toArray(new Inet6Address[filteredDnses.size()]);
492         final ByteBuffer rdnssOption = RdnssOption.build(lifetime, dnsesArray);
493         // NOTE: If the full of list DNS servers doesn't fit in the packet,
494         // this code will cause a buffer overflow and the RA won't include
495         // this instance of the option at all.
496         //
497         // TODO: Consider looking at ra.remaining() to determine how many
498         // DNS servers will fit, and adding only those.
499         ra.put(rdnssOption);
500     }
501 
createSocket()502     private boolean createSocket() {
503         final int send_timout_ms = 300;
504 
505         final int oldTag = TrafficStats.getAndSetThreadStatsTag(TAG_SYSTEM_NEIGHBOR);
506         try {
507             mSocket = Os.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
508             // Setting SNDTIMEO is purely for defensive purposes.
509             Os.setsockoptTimeval(
510                     mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(send_timout_ms));
511             SocketUtils.bindSocketToInterface(mSocket, mInterface.name);
512             TetheringUtils.setupRaSocket(mSocket, mInterface.index);
513         } catch (ErrnoException | IOException e) {
514             Log.e(TAG, "Failed to create RA daemon socket: " + e);
515             return false;
516         } finally {
517             TrafficStats.setThreadStatsTag(oldTag);
518         }
519 
520         return true;
521     }
522 
closeSocket()523     private void closeSocket() {
524         if (mSocket != null) {
525             try {
526                 SocketUtils.closeSocket(mSocket);
527             } catch (IOException ignored) { }
528         }
529         mSocket = null;
530     }
531 
isSocketValid()532     private boolean isSocketValid() {
533         final FileDescriptor s = mSocket;
534         return (s != null) && s.valid();
535     }
536 
isSuitableDestination(InetSocketAddress dest)537     private boolean isSuitableDestination(InetSocketAddress dest) {
538         if (mAllNodes.equals(dest)) {
539             return true;
540         }
541 
542         final InetAddress destip = dest.getAddress();
543         return (destip instanceof Inet6Address)
544                && destip.isLinkLocalAddress()
545                && (((Inet6Address) destip).getScopeId() == mInterface.index);
546     }
547 
maybeSendRA(InetSocketAddress dest)548     private void maybeSendRA(InetSocketAddress dest) {
549         if (dest == null || !isSuitableDestination(dest)) {
550             dest = mAllNodes;
551         }
552 
553         try {
554             synchronized (mLock) {
555                 if (mRaLength < ICMPV6_RA_HEADER_LEN) {
556                     // No actual RA to send.
557                     return;
558                 }
559                 Os.sendto(mSocket, mRA, 0, mRaLength, 0, dest);
560             }
561             Log.d(TAG, "RA sendto " + dest.getAddress().getHostAddress());
562         } catch (ErrnoException | SocketException e) {
563             if (isSocketValid()) {
564                 Log.e(TAG, "sendto error: " + e);
565             }
566         }
567     }
568 
569     private final class UnicastResponder extends Thread {
570         private final InetSocketAddress mSolicitor = new InetSocketAddress(0);
571         // The recycled buffer for receiving Router Solicitations from clients.
572         // If the RS is larger than IPV6_MIN_MTU the packets are truncated.
573         // This is fine since currently only byte 0 is examined anyway.
574         private final byte[] mSolicitation = new byte[IPV6_MIN_MTU];
575 
576         @Override
run()577         public void run() {
578             while (isSocketValid()) {
579                 try {
580                     // Blocking receive.
581                     final int rval = Os.recvfrom(
582                             mSocket, mSolicitation, 0, mSolicitation.length, 0, mSolicitor);
583                     // Do the least possible amount of validation.
584                     if (rval < 1 || mSolicitation[0] != asByte(ICMPV6_ROUTER_SOLICITATION)) {
585                         continue;
586                     }
587                 } catch (ErrnoException | SocketException e) {
588                     if (isSocketValid()) {
589                         Log.e(TAG, "recvfrom error: " + e);
590                     }
591                     continue;
592                 }
593 
594                 maybeSendRA(mSolicitor);
595             }
596         }
597     }
598 
599     // TODO: Consider moving this to run on a provided Looper as a Handler,
600     // with WakeupMessage-style messages providing the timer driven input.
601     private final class MulticastTransmitter extends Thread {
602         private final Random mRandom = new Random();
603         private final AtomicInteger mUrgentAnnouncements = new AtomicInteger(0);
604 
605         @Override
run()606         public void run() {
607             while (isSocketValid()) {
608                 try {
609                     Thread.sleep(getNextMulticastTransmitDelayMs());
610                 } catch (InterruptedException ignored) {
611                     // Stop sleeping, immediately send an RA, and continue.
612                 }
613 
614                 maybeSendRA(mAllNodes);
615                 synchronized (mLock) {
616                     if (mDeprecatedInfoTracker.decrementCounters()) {
617                         // At least one deprecated PIO has been removed;
618                         // reassemble the RA.
619                         assembleRaLocked();
620                     }
621                 }
622             }
623         }
624 
hup()625         public void hup() {
626             // Set to one fewer that the desired number, because as soon as
627             // the thread interrupt is processed we immediately send an RA
628             // and mUrgentAnnouncements is not examined until the subsequent
629             // sleep interval computation (i.e. this way we send 3 and not 4).
630             mUrgentAnnouncements.set(MAX_URGENT_RTR_ADVERTISEMENTS - 1);
631             interrupt();
632         }
633 
getNextMulticastTransmitDelaySec()634         private int getNextMulticastTransmitDelaySec() {
635             boolean deprecationInProgress = false;
636             synchronized (mLock) {
637                 if (mRaLength < ICMPV6_RA_HEADER_LEN) {
638                     // No actual RA to send; just sleep for 1 day.
639                     return DAY_IN_SECONDS;
640                 }
641                 deprecationInProgress = !mDeprecatedInfoTracker.isEmpty();
642             }
643 
644             final int urgentPending = mUrgentAnnouncements.getAndDecrement();
645             if ((urgentPending > 0) || deprecationInProgress) {
646                 return MIN_DELAY_BETWEEN_RAS_SEC;
647             }
648 
649             return MIN_RTR_ADV_INTERVAL_SEC + mRandom.nextInt(
650                     MAX_RTR_ADV_INTERVAL_SEC - MIN_RTR_ADV_INTERVAL_SEC);
651         }
652 
getNextMulticastTransmitDelayMs()653         private long getNextMulticastTransmitDelayMs() {
654             return 1000 * (long) getNextMulticastTransmitDelaySec();
655         }
656     }
657 }
658