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