1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.net.ip; 18 19 import static android.net.util.NetworkConstants.RFC7421_PREFIX_LENGTH; 20 import static android.system.OsConstants.AF_INET6; 21 import static android.system.OsConstants.IPPROTO_ICMPV6; 22 import static android.system.OsConstants.SOCK_RAW; 23 import static android.system.OsConstants.SOL_SOCKET; 24 import static android.system.OsConstants.SO_SNDTIMEO; 25 26 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ND_OPTION_SLLA; 27 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_RA_HEADER_LEN; 28 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_ADVERTISEMENT; 29 import static com.android.net.module.util.NetworkStackConstants.ICMPV6_ROUTER_SOLICITATION; 30 import static com.android.net.module.util.NetworkStackConstants.IPV6_MIN_MTU; 31 import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_AUTONOMOUS; 32 import static com.android.net.module.util.NetworkStackConstants.PIO_FLAG_ON_LINK; 33 import static com.android.net.module.util.NetworkStackConstants.TAG_SYSTEM_NEIGHBOR; 34 import static com.android.networkstack.tethering.util.TetheringUtils.getAllNodesForScopeId; 35 36 import android.net.IpPrefix; 37 import android.net.LinkAddress; 38 import android.net.MacAddress; 39 import android.net.TrafficStats; 40 import android.net.util.SocketUtils; 41 import android.system.ErrnoException; 42 import android.system.Os; 43 import android.system.StructTimeval; 44 import android.util.Log; 45 46 import com.android.internal.annotations.GuardedBy; 47 import com.android.net.module.util.InterfaceParams; 48 import com.android.net.module.util.structs.Icmpv6Header; 49 import com.android.net.module.util.structs.LlaOption; 50 import com.android.net.module.util.structs.MtuOption; 51 import com.android.net.module.util.structs.PrefixInformationOption; 52 import com.android.net.module.util.structs.RaHeader; 53 import com.android.net.module.util.structs.RdnssOption; 54 import com.android.networkstack.tethering.util.TetheringUtils; 55 56 import java.io.FileDescriptor; 57 import java.io.IOException; 58 import java.net.Inet6Address; 59 import java.net.InetAddress; 60 import java.net.InetSocketAddress; 61 import java.net.SocketException; 62 import java.nio.BufferOverflowException; 63 import java.nio.ByteBuffer; 64 import java.nio.ByteOrder; 65 import java.util.HashMap; 66 import java.util.HashSet; 67 import java.util.Iterator; 68 import java.util.Map; 69 import java.util.Random; 70 import java.util.Set; 71 import 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 */ 84 public class RouterAdvertisementDaemon { 85 private static final String TAG = RouterAdvertisementDaemon.class.getSimpleName(); 86 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 91 // greater than or equal to 3 * MAX_RTR_ADV_INTERVAL. Here, we quadruple 92 // 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". 97 private static final int DEFAULT_LIFETIME = 12 * MAX_RTR_ADV_INTERVAL_SEC; 98 // 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 106 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. 132 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 RaParams()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 RaParams(RaParams other)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 */ getDeprecatedRaParams(RaParams oldRa, RaParams newRa)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 getPrefixes()187 Set<IpPrefix> getPrefixes() { 188 return mPrefixes.keySet(); 189 } 190 putPrefixes(Set<IpPrefix> prefixes)191 void putPrefixes(Set<IpPrefix> prefixes) { 192 for (IpPrefix ipp : prefixes) { 193 mPrefixes.put(ipp, MAX_URGENT_RTR_ADVERTISEMENTS); 194 } 195 } 196 removePrefixes(Set<IpPrefix> prefixes)197 void removePrefixes(Set<IpPrefix> prefixes) { 198 for (IpPrefix ipp : prefixes) { 199 mPrefixes.remove(ipp); 200 } 201 } 202 getDnses()203 Set<Inet6Address> getDnses() { 204 return mDnses.keySet(); 205 } 206 putDnses(Set<Inet6Address> dnses)207 void putDnses(Set<Inet6Address> dnses) { 208 for (Inet6Address dns : dnses) { 209 mDnses.put(dns, MAX_URGENT_RTR_ADVERTISEMENTS); 210 } 211 } 212 removeDnses(Set<Inet6Address> dnses)213 void removeDnses(Set<Inet6Address> dnses) { 214 for (Inet6Address dns : dnses) { 215 mDnses.remove(dns); 216 } 217 } 218 isEmpty()219 boolean isEmpty() { 220 return mPrefixes.isEmpty() && mDnses.isEmpty(); 221 } 222 decrementCounters()223 private boolean decrementCounters() { 224 boolean removed = decrementCounter(mPrefixes); 225 removed |= decrementCounter(mDnses); 226 return removed; 227 } 228 decrementCounter(HashMap<T, Integer> map)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 RouterAdvertisementDaemon(InterfaceParams ifParams)247 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.*/ buildNewRa(RaParams deprecatedParams, RaParams newParams)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. */ start()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. */ stop()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") assembleRaLocked()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 maybeNotifyMulticastTransmitter()362 private void maybeNotifyMulticastTransmitter() { 363 final MulticastTransmitter m = mMulticastTransmitter; 364 if (m != null) { 365 m.hup(); 366 } 367 } 368 asByte(int value)369 private static byte asByte(int value) { 370 return (byte) value; 371 } asShort(int value)372 private static short asShort(int value) { 373 return (short) value; 374 } 375 putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit)376 private static void putHeader(ByteBuffer ra, boolean hasDefaultRoute, byte hopLimit) { 377 // 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); 387 } 388 putSlla(ByteBuffer ra, byte[] slla)389 private static void putSlla(ByteBuffer ra, byte[] slla) { 390 if (slla == null || slla.length != 6) { 391 // Only IEEE 802.3 6-byte addresses are supported. 392 return; 393 } 394 395 final ByteBuffer sllaOption = LlaOption.build(asByte(ICMPV6_ND_OPTION_SLLA), 396 MacAddress.fromBytes(slla)); 397 ra.put(sllaOption); 398 } 399 putExpandedFlagsOption(ByteBuffer ra)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 putMtu(ByteBuffer ra, int mtu)422 private static void putMtu(ByteBuffer ra, int mtu) { 423 final ByteBuffer mtuOption = MtuOption.build((mtu < IPV6_MIN_MTU) ? IPV6_MIN_MTU : mtu); 424 ra.put(mtuOption); 425 } 426 putPio(ByteBuffer ra, IpPrefix ipp, int validTime, int preferredTime)427 private static void putPio(ByteBuffer ra, IpPrefix ipp, 428 int validTime, int preferredTime) { 429 final int prefixLength = ipp.getPrefixLength(); 430 if (prefixLength != 64) { 431 return; 432 } 433 434 if (validTime < 0) validTime = 0; 435 if (preferredTime < 0) preferredTime = 0; 436 if (preferredTime > validTime) preferredTime = validTime; 437 438 final ByteBuffer pioOption = PrefixInformationOption.build(ipp, 439 asByte(PIO_FLAG_ON_LINK | PIO_FLAG_AUTONOMOUS), validTime, preferredTime); 440 ra.put(pioOption); 441 } 442 putRio(ByteBuffer ra, IpPrefix ipp)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 putRdnss(ByteBuffer ra, Set<Inet6Address> dnses, int lifetime)480 private static void putRdnss(ByteBuffer ra, Set<Inet6Address> dnses, int lifetime) { 481 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 489 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); 499 } 500 createSocket()501 private boolean createSocket() { 502 final int send_timout_ms = 300; 503 504 final int oldTag = TrafficStats.getAndSetThreadStatsTag(TAG_SYSTEM_NEIGHBOR); 505 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)); 510 SocketUtils.bindSocketToInterface(mSocket, mInterface.name); 511 TetheringUtils.setupRaSocket(mSocket, mInterface.index); 512 } 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 closeSocket()522 private void closeSocket() { 523 if (mSocket != null) { 524 try { 525 SocketUtils.closeSocket(mSocket); 526 } catch (IOException ignored) { } 527 } 528 mSocket = null; 529 } 530 isSocketValid()531 private boolean isSocketValid() { 532 final FileDescriptor s = mSocket; 533 return (s != null) && s.valid(); 534 } 535 isSuitableDestination(InetSocketAddress dest)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 maybeSendRA(InetSocketAddress dest)547 private void maybeSendRA(InetSocketAddress dest) { 548 if (dest == null || !isSuitableDestination(dest)) { 549 dest = mAllNodes; 550 } 551 552 try { 553 synchronized (mLock) { 554 if (mRaLength < ICMPV6_RA_HEADER_LEN) { 555 // 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 { 569 private final InetSocketAddress mSolicitor = new InetSocketAddress(0); 570 // 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 run()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. 583 if (rval < 1 || mSolicitation[0] != asByte(ICMPV6_ROUTER_SOLICITATION)) { 584 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 run()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 hup()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 getNextMulticastTransmitDelaySec()633 private int getNextMulticastTransmitDelaySec() { 634 boolean deprecationInProgress = false; 635 synchronized (mLock) { 636 if (mRaLength < ICMPV6_RA_HEADER_LEN) { 637 // 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 getNextMulticastTransmitDelayMs()652 private long getNextMulticastTransmitDelayMs() { 653 return 1000 * (long) getNextMulticastTransmitDelaySec(); 654 } 655 } 656 } 657