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