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