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