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