blob: d8779b83c0befb83843efe65844217f393703177 [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;
KH Shibdcd7db2023-03-16 15:23:13 +080021import static android.system.OsConstants.SOCK_NONBLOCK;
markchien74a4fa92019-09-09 20:50:49 +080022import static android.system.OsConstants.SOCK_RAW;
23import static android.system.OsConstants.SOL_SOCKET;
markchien74a4fa92019-09-09 20:50:49 +080024import static android.system.OsConstants.SO_SNDTIMEO;
25
Xiao Ma3e557d72021-03-04 06:04:28 +000026import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA;
27import static com.android.net.module.util.NetworkStackConstants.ICMPV6_RA_HEADER_LEN;
28import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT;
29import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION;
30import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU;
31import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS;
32import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK;
Xiao Ma1f993302023-08-09 18:55:49 +090033import static com.android.net.module.util.NetworkStackConstants.RFC7421_PREFIX_LENGTH;
Xiao Ma3e557d72021-03-04 06:04:28 +000034import static com.android.net.module.util.NetworkStackConstants.TAG_SYSTEM_NEIGHBOR;
markchiend02f9af2021-11-04 11:26:03 +080035import static com.android.networkstack.tethering.util.TetheringUtils.getAllNodesForScopeId;
Xiao Ma3e557d72021-03-04 06:04:28 +000036
markchien74a4fa92019-09-09 20:50:49 +080037import android.net.IpPrefix;
38import android.net.LinkAddress;
Xiao Ma3e557d72021-03-04 06:04:28 +000039import android.net.MacAddress;
markchien74a4fa92019-09-09 20:50:49 +080040import android.net.TrafficStats;
markchien6cf0e552019-12-06 15:24:53 +080041import android.net.util.SocketUtils;
KH Shibdcd7db2023-03-16 15:23:13 +080042import android.os.Handler;
43import android.os.HandlerThread;
44import android.os.Looper;
45import android.os.Message;
markchien74a4fa92019-09-09 20:50:49 +080046import android.system.ErrnoException;
47import android.system.Os;
48import android.system.StructTimeval;
49import android.util.Log;
50
KH Shibdcd7db2023-03-16 15:23:13 +080051import androidx.annotation.NonNull;
52
markchien74a4fa92019-09-09 20:50:49 +080053import com.android.internal.annotations.GuardedBy;
KH Shibdcd7db2023-03-16 15:23:13 +080054import com.android.net.module.util.FdEventsReader;
Patrick Rohr9f371f02022-03-04 15:14:27 +010055import com.android.net.module.util.InterfaceParams;
Xiao Ma3e557d72021-03-04 06:04:28 +000056import com.android.net.module.util.structs.Icmpv6Header;
57import com.android.net.module.util.structs.LlaOption;
58import com.android.net.module.util.structs.MtuOption;
59import com.android.net.module.util.structs.PrefixInformationOption;
60import com.android.net.module.util.structs.RaHeader;
61import com.android.net.module.util.structs.RdnssOption;
markchiend02f9af2021-11-04 11:26:03 +080062import com.android.networkstack.tethering.util.TetheringUtils;
markchien74a4fa92019-09-09 20:50:49 +080063
markchien74a4fa92019-09-09 20:50:49 +080064import java.io.FileDescriptor;
65import java.io.IOException;
66import java.net.Inet6Address;
67import java.net.InetAddress;
68import java.net.InetSocketAddress;
69import java.net.SocketException;
markchien74a4fa92019-09-09 20:50:49 +080070import java.nio.BufferOverflowException;
71import java.nio.ByteBuffer;
72import java.nio.ByteOrder;
73import java.util.HashMap;
74import java.util.HashSet;
75import java.util.Iterator;
76import java.util.Map;
77import java.util.Random;
78import java.util.Set;
79import java.util.concurrent.atomic.AtomicInteger;
80
81
82/**
83 * Basic IPv6 Router Advertisement Daemon.
84 *
85 * TODO:
86 *
87 * - Rewrite using Handler (and friends) so that AlarmManager can deliver
88 * "kick" messages when it's time to send a multicast RA.
89 *
90 * @hide
91 */
92public class RouterAdvertisementDaemon {
93 private static final String TAG = RouterAdvertisementDaemon.class.getSimpleName();
markchien74a4fa92019-09-09 20:50:49 +080094
95 // Summary of various timers and lifetimes.
96 private static final int MIN_RTR_ADV_INTERVAL_SEC = 300;
97 private static final int MAX_RTR_ADV_INTERVAL_SEC = 600;
98 // In general, router, prefix, and DNS lifetimes are all advised to be
Maciej Żenczykowskif95fd402023-02-16 22:37:22 +000099 // greater than or equal to 3 * MAX_RTR_ADV_INTERVAL. Here, we quadruple
markchien74a4fa92019-09-09 20:50:49 +0800100 // that to allow for multicast packet loss.
101 //
102 // This MAX_RTR_ADV_INTERVAL_SEC and DEFAULT_LIFETIME are also consistent
103 // with the https://tools.ietf.org/html/rfc7772#section-4 discussion of
104 // "approximately 7 RAs per hour".
Maciej Żenczykowskif95fd402023-02-16 22:37:22 +0000105 private static final int DEFAULT_LIFETIME = 12 * MAX_RTR_ADV_INTERVAL_SEC;
markchien74a4fa92019-09-09 20:50:49 +0800106 // From https://tools.ietf.org/html/rfc4861#section-10 .
107 private static final int MIN_DELAY_BETWEEN_RAS_SEC = 3;
108 // Both initial and final RAs, but also for changes in RA contents.
109 // From https://tools.ietf.org/html/rfc4861#section-10 .
110 private static final int MAX_URGENT_RTR_ADVERTISEMENTS = 5;
111
112 private static final int DAY_IN_SECONDS = 86_400;
113
KH Shibdcd7db2023-03-16 15:23:13 +0800114 // Commands for IpServer to control RouterAdvertisementDaemon
115 private static final int CMD_START = 1;
116 private static final int CMD_STOP = 2;
117
markchien74a4fa92019-09-09 20:50:49 +0800118 private final InterfaceParams mInterface;
119 private final InetSocketAddress mAllNodes;
120
121 // This lock is to protect the RA from being updated while being
122 // transmitted on another thread (multicast or unicast).
123 //
124 // TODO: This should be handled with a more RCU-like approach.
125 private final Object mLock = new Object();
126 @GuardedBy("mLock")
127 private final byte[] mRA = new byte[IPV6_MIN_MTU];
128 @GuardedBy("mLock")
129 private int mRaLength;
130 @GuardedBy("mLock")
131 private final DeprecatedInfoTracker mDeprecatedInfoTracker;
132 @GuardedBy("mLock")
133 private RaParams mRaParams;
134
KH Shibdcd7db2023-03-16 15:23:13 +0800135 // To be accessed only from RaMessageHandler
136 private RsPacketListener mRsPacketListener;
137
markchien74a4fa92019-09-09 20:50:49 +0800138 private volatile FileDescriptor mSocket;
139 private volatile MulticastTransmitter mMulticastTransmitter;
KH Shibdcd7db2023-03-16 15:23:13 +0800140 private volatile RaMessageHandler mRaMessageHandler;
141 private volatile HandlerThread mRaHandlerThread;
markchien74a4fa92019-09-09 20:50:49 +0800142
143 /** Encapsulate the RA parameters for RouterAdvertisementDaemon.*/
144 public static class RaParams {
145 // Tethered traffic will have the hop limit properly decremented.
146 // Consequently, set the hoplimit greater by one than the upstream
147 // unicast hop limit.
markchien74a4fa92019-09-09 20:50:49 +0800148 static final byte DEFAULT_HOPLIMIT = 65;
149
150 public boolean hasDefaultRoute;
151 public byte hopLimit;
152 public int mtu;
153 public HashSet<IpPrefix> prefixes;
154 public HashSet<Inet6Address> dnses;
155
156 public RaParams() {
157 hasDefaultRoute = false;
158 hopLimit = DEFAULT_HOPLIMIT;
159 mtu = IPV6_MIN_MTU;
160 prefixes = new HashSet<IpPrefix>();
161 dnses = new HashSet<Inet6Address>();
162 }
163
164 public RaParams(RaParams other) {
165 hasDefaultRoute = other.hasDefaultRoute;
166 hopLimit = other.hopLimit;
167 mtu = other.mtu;
168 prefixes = (HashSet) other.prefixes.clone();
169 dnses = (HashSet) other.dnses.clone();
170 }
171
172 /**
173 * Returns the subset of RA parameters that become deprecated when
174 * moving from announcing oldRa to announcing newRa.
175 *
176 * Currently only tracks differences in |prefixes| and |dnses|.
177 */
178 public static RaParams getDeprecatedRaParams(RaParams oldRa, RaParams newRa) {
179 RaParams newlyDeprecated = new RaParams();
180
181 if (oldRa != null) {
182 for (IpPrefix ipp : oldRa.prefixes) {
183 if (newRa == null || !newRa.prefixes.contains(ipp)) {
184 newlyDeprecated.prefixes.add(ipp);
185 }
186 }
187
188 for (Inet6Address dns : oldRa.dnses) {
189 if (newRa == null || !newRa.dnses.contains(dns)) {
190 newlyDeprecated.dnses.add(dns);
191 }
192 }
193 }
194
195 return newlyDeprecated;
196 }
197 }
198
199 private static class DeprecatedInfoTracker {
200 private final HashMap<IpPrefix, Integer> mPrefixes = new HashMap<>();
201 private final HashMap<Inet6Address, Integer> mDnses = new HashMap<>();
202
203 Set<IpPrefix> getPrefixes() {
204 return mPrefixes.keySet();
205 }
206
207 void putPrefixes(Set<IpPrefix> prefixes) {
208 for (IpPrefix ipp : prefixes) {
209 mPrefixes.put(ipp, MAX_URGENT_RTR_ADVERTISEMENTS);
210 }
211 }
212
213 void removePrefixes(Set<IpPrefix> prefixes) {
214 for (IpPrefix ipp : prefixes) {
215 mPrefixes.remove(ipp);
216 }
217 }
218
219 Set<Inet6Address> getDnses() {
220 return mDnses.keySet();
221 }
222
223 void putDnses(Set<Inet6Address> dnses) {
224 for (Inet6Address dns : dnses) {
225 mDnses.put(dns, MAX_URGENT_RTR_ADVERTISEMENTS);
226 }
227 }
228
229 void removeDnses(Set<Inet6Address> dnses) {
230 for (Inet6Address dns : dnses) {
231 mDnses.remove(dns);
232 }
233 }
234
235 boolean isEmpty() {
236 return mPrefixes.isEmpty() && mDnses.isEmpty();
237 }
238
239 private boolean decrementCounters() {
240 boolean removed = decrementCounter(mPrefixes);
241 removed |= decrementCounter(mDnses);
242 return removed;
243 }
244
245 private <T> boolean decrementCounter(HashMap<T, Integer> map) {
246 boolean removed = false;
247
248 for (Iterator<Map.Entry<T, Integer>> it = map.entrySet().iterator();
249 it.hasNext();) {
250 Map.Entry<T, Integer> kv = it.next();
251 if (kv.getValue() == 0) {
252 it.remove();
253 removed = true;
254 } else {
255 kv.setValue(kv.getValue() - 1);
256 }
257 }
258
259 return removed;
260 }
261 }
262
KH Shibdcd7db2023-03-16 15:23:13 +0800263 private class RaMessageHandler extends Handler {
264 RaMessageHandler(Looper looper) {
265 super(looper);
266 }
267
268 @Override
269 public void handleMessage(Message msg) {
270 switch (msg.what) {
271 case CMD_START:
272 mRsPacketListener = new RsPacketListener(this);
273 mRsPacketListener.start();
274 break;
275 case CMD_STOP:
276 if (mRsPacketListener != null) {
277 mRsPacketListener.stop();
278 mRsPacketListener = null;
279 }
280 break;
281 default:
282 Log.e(TAG, "Unknown message, cmd = " + String.valueOf(msg.what));
283 break;
284 }
285 }
286 }
287
288 private class RsPacketListener extends FdEventsReader<RsPacketListener.RecvBuffer> {
289 private static final class RecvBuffer {
290 // The recycled buffer for receiving Router Solicitations from clients.
291 // If the RS is larger than IPV6_MIN_MTU the packets are truncated.
292 // This is fine since currently only byte 0 is examined anyway.
293 final byte[] mBytes = new byte[IPV6_MIN_MTU];
294 final InetSocketAddress mSrcAddr = new InetSocketAddress(0);
295 }
296
297 RsPacketListener(@NonNull Handler handler) {
298 super(handler, new RecvBuffer());
299 }
300
301 @Override
302 protected int recvBufSize(@NonNull RecvBuffer buffer) {
303 return buffer.mBytes.length;
304 }
305
306 @Override
307 protected FileDescriptor createFd() {
308 return mSocket;
309 }
310
311 @Override
312 protected int readPacket(@NonNull FileDescriptor fd, @NonNull RecvBuffer buffer)
313 throws Exception {
314 return Os.recvfrom(
315 fd, buffer.mBytes, 0, buffer.mBytes.length, 0 /* flags */, buffer.mSrcAddr);
316 }
317
318 @Override
319 protected final void handlePacket(@NonNull RecvBuffer buffer, int length) {
320 // Do the least possible amount of validations.
321 if (buffer.mSrcAddr == null
322 || length <= 0
323 || buffer.mBytes[0] != asByte(ICMPV6_ROUTER_SOLICITATION)) {
324 return;
325 }
326
327 maybeSendRA(buffer.mSrcAddr);
328 }
329 }
330
markchien74a4fa92019-09-09 20:50:49 +0800331 public RouterAdvertisementDaemon(InterfaceParams ifParams) {
332 mInterface = ifParams;
333 mAllNodes = new InetSocketAddress(getAllNodesForScopeId(mInterface.index), 0);
334 mDeprecatedInfoTracker = new DeprecatedInfoTracker();
335 }
336
337 /** Build new RA.*/
338 public void buildNewRa(RaParams deprecatedParams, RaParams newParams) {
339 synchronized (mLock) {
340 if (deprecatedParams != null) {
341 mDeprecatedInfoTracker.putPrefixes(deprecatedParams.prefixes);
342 mDeprecatedInfoTracker.putDnses(deprecatedParams.dnses);
343 }
344
345 if (newParams != null) {
346 // Process information that is no longer deprecated.
347 mDeprecatedInfoTracker.removePrefixes(newParams.prefixes);
348 mDeprecatedInfoTracker.removeDnses(newParams.dnses);
349 }
350
351 mRaParams = newParams;
352 assembleRaLocked();
353 }
354
355 maybeNotifyMulticastTransmitter();
356 }
357
358 /** Start router advertisement daemon. */
359 public boolean start() {
360 if (!createSocket()) {
KH Shibdcd7db2023-03-16 15:23:13 +0800361 Log.e(TAG, "Failed to start RouterAdvertisementDaemon.");
markchien74a4fa92019-09-09 20:50:49 +0800362 return false;
363 }
364
365 mMulticastTransmitter = new MulticastTransmitter();
366 mMulticastTransmitter.start();
367
KH Shibdcd7db2023-03-16 15:23:13 +0800368 mRaHandlerThread = new HandlerThread(TAG);
369 mRaHandlerThread.start();
370 mRaMessageHandler = new RaMessageHandler(mRaHandlerThread.getLooper());
markchien74a4fa92019-09-09 20:50:49 +0800371
KH Shibdcd7db2023-03-16 15:23:13 +0800372 return sendMessage(CMD_START);
markchien74a4fa92019-09-09 20:50:49 +0800373 }
374
375 /** Stop router advertisement daemon. */
376 public void stop() {
KH Shibdcd7db2023-03-16 15:23:13 +0800377 if (!sendMessage(CMD_STOP)) {
378 Log.e(TAG, "RouterAdvertisementDaemon has been stopped or was never started.");
379 return;
380 }
381
382 mRaHandlerThread.quitSafely();
383 mRaHandlerThread = null;
384 mRaMessageHandler = null;
385
markchien74a4fa92019-09-09 20:50:49 +0800386 closeSocket();
387 // Wake up mMulticastTransmitter thread to interrupt a potential 1 day sleep before
388 // the thread's termination.
389 maybeNotifyMulticastTransmitter();
390 mMulticastTransmitter = null;
markchien74a4fa92019-09-09 20:50:49 +0800391 }
392
393 @GuardedBy("mLock")
394 private void assembleRaLocked() {
395 final ByteBuffer ra = ByteBuffer.wrap(mRA);
396 ra.order(ByteOrder.BIG_ENDIAN);
397
398 final boolean haveRaParams = (mRaParams != null);
399 boolean shouldSendRA = false;
400
401 try {
402 putHeader(ra, haveRaParams && mRaParams.hasDefaultRoute,
403 haveRaParams ? mRaParams.hopLimit : RaParams.DEFAULT_HOPLIMIT);
404 putSlla(ra, mInterface.macAddr.toByteArray());
405 mRaLength = ra.position();
406
407 // https://tools.ietf.org/html/rfc5175#section-4 says:
408 //
409 // "MUST NOT be added to a Router Advertisement message
410 // if no flags in the option are set."
411 //
412 // putExpandedFlagsOption(ra);
413
414 if (haveRaParams) {
415 putMtu(ra, mRaParams.mtu);
416 mRaLength = ra.position();
417
418 for (IpPrefix ipp : mRaParams.prefixes) {
419 putPio(ra, ipp, DEFAULT_LIFETIME, DEFAULT_LIFETIME);
420 mRaLength = ra.position();
421 shouldSendRA = true;
422 }
423
424 if (mRaParams.dnses.size() > 0) {
425 putRdnss(ra, mRaParams.dnses, DEFAULT_LIFETIME);
426 mRaLength = ra.position();
427 shouldSendRA = true;
428 }
429 }
430
431 for (IpPrefix ipp : mDeprecatedInfoTracker.getPrefixes()) {
432 putPio(ra, ipp, 0, 0);
433 mRaLength = ra.position();
434 shouldSendRA = true;
435 }
436
437 final Set<Inet6Address> deprecatedDnses = mDeprecatedInfoTracker.getDnses();
438 if (!deprecatedDnses.isEmpty()) {
439 putRdnss(ra, deprecatedDnses, 0);
440 mRaLength = ra.position();
441 shouldSendRA = true;
442 }
443 } catch (BufferOverflowException e) {
444 // The packet up to mRaLength is valid, since it has been updated
445 // progressively as the RA was built. Log an error, and continue
446 // on as best as possible.
447 Log.e(TAG, "Could not construct new RA: " + e);
448 }
449
450 // We have nothing worth announcing; indicate as much to maybeSendRA().
451 if (!shouldSendRA) {
452 mRaLength = 0;
453 }
454 }
455
456 private void maybeNotifyMulticastTransmitter() {
457 final MulticastTransmitter m = mMulticastTransmitter;
458 if (m != null) {
459 m.hup();
460 }
461 }
462
markchien74a4fa92019-09-09 20:50:49 +0800463 private static byte asByte(int value) {
464 return (byte) value;
465 }
466 private static short asShort(int value) {
467 return (short) value;
468 }
469
470 private static void putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit) {
Xiao Ma3e557d72021-03-04 06:04:28 +0000471 // RFC 4191 "high" preference, iff. advertising a default route.
472 final byte flags = hasDefaultRoute ? asByte(0x08) : asByte(0);
473 final short lifetime = hasDefaultRoute ? asShort(DEFAULT_LIFETIME) : asShort(0);
474 final Icmpv6Header icmpv6Header =
475 new Icmpv6Header(asByte(ICMPV6_ROUTER_ADVERTISEMENT) /* type */,
476 asByte(0) /* code */, asShort(0) /* checksum */);
477 final RaHeader raHeader = new RaHeader(hopLimit, flags, lifetime, 0 /* reachableTime */,
478 0 /* retransTimer */);
479 icmpv6Header.writeToByteBuffer(ra);
480 raHeader.writeToByteBuffer(ra);
markchien74a4fa92019-09-09 20:50:49 +0800481 }
482
483 private static void putSlla(ByteBuffer ra, byte[] slla) {
markchien74a4fa92019-09-09 20:50:49 +0800484 if (slla == null || slla.length != 6) {
485 // Only IEEE 802.3 6-byte addresses are supported.
486 return;
487 }
488
Xiao Ma3e557d72021-03-04 06:04:28 +0000489 final ByteBuffer sllaOption = LlaOption.build(asByte(ICMPV6_ND_OPTION_SLLA),
490 MacAddress.fromBytes(slla));
491 ra.put(sllaOption);
markchien74a4fa92019-09-09 20:50:49 +0800492 }
493
494 private static void putExpandedFlagsOption(ByteBuffer ra) {
495 /**
496 Router Advertisement Expanded Flags Option
497
498 0 1 2 3
499 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
500 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
501 | Type | Length | Bit fields available ..
502 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
503 ... for assignment |
504 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
505 */
506
507 final byte nd_option__efo = 26;
508 final byte efo_num_8octets = 1;
509
510 ra.put(nd_option__efo)
511 .put(efo_num_8octets)
512 .putShort(asShort(0))
513 .putInt(0);
514 }
515
516 private static void putMtu(ByteBuffer ra, int mtu) {
Xiao Ma3e557d72021-03-04 06:04:28 +0000517 final ByteBuffer mtuOption = MtuOption.build((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu);
518 ra.put(mtuOption);
markchien74a4fa92019-09-09 20:50:49 +0800519 }
520
521 private static void putPio(ByteBuffer ra, IpPrefix ipp,
522 int validTime, int preferredTime) {
markchien74a4fa92019-09-09 20:50:49 +0800523 final int prefixLength = ipp.getPrefixLength();
524 if (prefixLength != 64) {
525 return;
526 }
markchien74a4fa92019-09-09 20:50:49 +0800527
528 if (validTime < 0) validTime = 0;
529 if (preferredTime < 0) preferredTime = 0;
530 if (preferredTime > validTime) preferredTime = validTime;
531
Xiao Ma3e557d72021-03-04 06:04:28 +0000532 final ByteBuffer pioOption = PrefixInformationOption.build(ipp,
533 asByte(PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), validTime, preferredTime);
534 ra.put(pioOption);
markchien74a4fa92019-09-09 20:50:49 +0800535 }
536
537 private static void putRio(ByteBuffer ra, IpPrefix ipp) {
538 /**
539 Route Information Option
540
541 0 1 2 3
542 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
543 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
544 | Type | Length | Prefix Length |Resvd|Prf|Resvd|
545 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
546 | Route Lifetime |
547 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
548 | Prefix (Variable Length) |
549 . .
550 . .
551 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
552 */
553 final int prefixLength = ipp.getPrefixLength();
554 if (prefixLength > 64) {
555 return;
556 }
557 final byte nd_option_rio = 24;
558 final byte rio_num_8octets = asByte(
559 (prefixLength == 0) ? 1 : (prefixLength <= 8) ? 2 : 3);
560
561 final byte[] addr = ipp.getAddress().getAddress();
562 ra.put(nd_option_rio)
563 .put(rio_num_8octets)
564 .put(asByte(prefixLength))
565 .put(asByte(0x18))
566 .putInt(DEFAULT_LIFETIME);
567
568 // Rely upon an IpPrefix's address being properly zeroed.
569 if (prefixLength > 0) {
570 ra.put(addr, 0, (prefixLength <= 64) ? 8 : 16);
571 }
572 }
573
574 private static void putRdnss(ByteBuffer ra, Set<Inet6Address> dnses, int lifetime) {
markchien74a4fa92019-09-09 20:50:49 +0800575 final HashSet<Inet6Address> filteredDnses = new HashSet<>();
576 for (Inet6Address dns : dnses) {
577 if ((new LinkAddress(dns, RFC7421_PREFIX_LENGTH)).isGlobalPreferred()) {
578 filteredDnses.add(dns);
579 }
580 }
581 if (filteredDnses.isEmpty()) return;
582
Xiao Ma3e557d72021-03-04 06:04:28 +0000583 final Inet6Address[] dnsesArray =
584 filteredDnses.toArray(new Inet6Address[filteredDnses.size()]);
585 final ByteBuffer rdnssOption = RdnssOption.build(lifetime, dnsesArray);
586 // NOTE: If the full of list DNS servers doesn't fit in the packet,
587 // this code will cause a buffer overflow and the RA won't include
588 // this instance of the option at all.
589 //
590 // TODO: Consider looking at ra.remaining() to determine how many
591 // DNS servers will fit, and adding only those.
592 ra.put(rdnssOption);
markchien74a4fa92019-09-09 20:50:49 +0800593 }
594
595 private boolean createSocket() {
596 final int send_timout_ms = 300;
597
Xiao Ma3e557d72021-03-04 06:04:28 +0000598 final int oldTag = TrafficStats.getAndSetThreadStatsTag(TAG_SYSTEM_NEIGHBOR);
markchien74a4fa92019-09-09 20:50:49 +0800599 try {
KH Shibdcd7db2023-03-16 15:23:13 +0800600 mSocket = Os.socket(AF_INET6, SOCK_RAW | SOCK_NONBLOCK, IPPROTO_ICMPV6);
markchien74a4fa92019-09-09 20:50:49 +0800601 // Setting SNDTIMEO is purely for defensive purposes.
602 Os.setsockoptTimeval(
603 mSocket, SOL_SOCKET, SO_SNDTIMEO, StructTimeval.fromMillis(send_timout_ms));
markchien6cf0e552019-12-06 15:24:53 +0800604 SocketUtils.bindSocketToInterface(mSocket, mInterface.name);
markchienf87ebdc2019-12-07 22:02:28 +0800605 TetheringUtils.setupRaSocket(mSocket, mInterface.index);
markchien74a4fa92019-09-09 20:50:49 +0800606 } catch (ErrnoException | IOException e) {
607 Log.e(TAG, "Failed to create RA daemon socket: " + e);
608 return false;
609 } finally {
610 TrafficStats.setThreadStatsTag(oldTag);
611 }
612
613 return true;
614 }
615
616 private void closeSocket() {
617 if (mSocket != null) {
618 try {
markchien6cf0e552019-12-06 15:24:53 +0800619 SocketUtils.closeSocket(mSocket);
markchien74a4fa92019-09-09 20:50:49 +0800620 } catch (IOException ignored) { }
621 }
622 mSocket = null;
623 }
624
625 private boolean isSocketValid() {
626 final FileDescriptor s = mSocket;
627 return (s != null) && s.valid();
628 }
629
630 private boolean isSuitableDestination(InetSocketAddress dest) {
631 if (mAllNodes.equals(dest)) {
632 return true;
633 }
634
635 final InetAddress destip = dest.getAddress();
636 return (destip instanceof Inet6Address)
637 && destip.isLinkLocalAddress()
638 && (((Inet6Address) destip).getScopeId() == mInterface.index);
639 }
640
641 private void maybeSendRA(InetSocketAddress dest) {
642 if (dest == null || !isSuitableDestination(dest)) {
643 dest = mAllNodes;
644 }
645
646 try {
647 synchronized (mLock) {
Xiao Ma3e557d72021-03-04 06:04:28 +0000648 if (mRaLength < ICMPV6_RA_HEADER_LEN) {
markchien74a4fa92019-09-09 20:50:49 +0800649 // No actual RA to send.
650 return;
651 }
652 Os.sendto(mSocket, mRA, 0, mRaLength, 0, dest);
653 }
654 Log.d(TAG, "RA sendto " + dest.getAddress().getHostAddress());
655 } catch (ErrnoException | SocketException e) {
656 if (isSocketValid()) {
657 Log.e(TAG, "sendto error: " + e);
658 }
659 }
660 }
661
KH Shibdcd7db2023-03-16 15:23:13 +0800662 private boolean sendMessage(int cmd) {
663 if (mRaMessageHandler == null) {
664 return false;
markchien74a4fa92019-09-09 20:50:49 +0800665 }
KH Shibdcd7db2023-03-16 15:23:13 +0800666
667 return mRaMessageHandler.sendMessage(Message.obtain(mRaMessageHandler, cmd));
markchien74a4fa92019-09-09 20:50:49 +0800668 }
669
670 // TODO: Consider moving this to run on a provided Looper as a Handler,
671 // with WakeupMessage-style messages providing the timer driven input.
672 private final class MulticastTransmitter extends Thread {
673 private final Random mRandom = new Random();
674 private final AtomicInteger mUrgentAnnouncements = new AtomicInteger(0);
675
676 @Override
677 public void run() {
678 while (isSocketValid()) {
679 try {
680 Thread.sleep(getNextMulticastTransmitDelayMs());
681 } catch (InterruptedException ignored) {
682 // Stop sleeping, immediately send an RA, and continue.
683 }
684
685 maybeSendRA(mAllNodes);
686 synchronized (mLock) {
687 if (mDeprecatedInfoTracker.decrementCounters()) {
688 // At least one deprecated PIO has been removed;
689 // reassemble the RA.
690 assembleRaLocked();
691 }
692 }
693 }
694 }
695
696 public void hup() {
697 // Set to one fewer that the desired number, because as soon as
698 // the thread interrupt is processed we immediately send an RA
699 // and mUrgentAnnouncements is not examined until the subsequent
700 // sleep interval computation (i.e. this way we send 3 and not 4).
701 mUrgentAnnouncements.set(MAX_URGENT_RTR_ADVERTISEMENTS - 1);
702 interrupt();
703 }
704
705 private int getNextMulticastTransmitDelaySec() {
706 boolean deprecationInProgress = false;
707 synchronized (mLock) {
Xiao Ma3e557d72021-03-04 06:04:28 +0000708 if (mRaLength < ICMPV6_RA_HEADER_LEN) {
markchien74a4fa92019-09-09 20:50:49 +0800709 // No actual RA to send; just sleep for 1 day.
710 return DAY_IN_SECONDS;
711 }
712 deprecationInProgress = !mDeprecatedInfoTracker.isEmpty();
713 }
714
715 final int urgentPending = mUrgentAnnouncements.getAndDecrement();
716 if ((urgentPending > 0) || deprecationInProgress) {
717 return MIN_DELAY_BETWEEN_RAS_SEC;
718 }
719
720 return MIN_RTR_ADV_INTERVAL_SEC + mRandom.nextInt(
721 MAX_RTR_ADV_INTERVAL_SEC - MIN_RTR_ADV_INTERVAL_SEC);
722 }
723
724 private long getNextMulticastTransmitDelayMs() {
725 return 1000 * (long) getNextMulticastTransmitDelaySec();
726 }
727 }
728}