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