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