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