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