1 /* 2 * Copyright (C) 2019 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.dhcp; 18 19 import static com.android.modules.utils.build.SdkLevel.isAtLeastR; 20 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ALL; 21 import static com.android.net.module.util.NetworkStackConstants.IPV4_ADDR_ANY; 22 23 import android.net.DhcpResults; 24 import android.net.LinkAddress; 25 import android.net.metrics.DhcpErrorEvent; 26 import android.net.networkstack.aidl.dhcp.DhcpOption; 27 import android.os.Build; 28 import android.os.SystemProperties; 29 import android.system.OsConstants; 30 import android.text.TextUtils; 31 32 import androidx.annotation.NonNull; 33 import androidx.annotation.Nullable; 34 import androidx.annotation.VisibleForTesting; 35 36 import com.android.net.module.util.DomainUtils; 37 import com.android.net.module.util.Inet4AddressUtils; 38 39 import java.io.UnsupportedEncodingException; 40 import java.net.Inet4Address; 41 import java.net.UnknownHostException; 42 import java.nio.BufferUnderflowException; 43 import java.nio.ByteBuffer; 44 import java.nio.ByteOrder; 45 import java.nio.ShortBuffer; 46 import java.nio.charset.StandardCharsets; 47 import java.util.ArrayList; 48 import java.util.Arrays; 49 import java.util.List; 50 51 /** 52 * Defines basic data and operations needed to build and use packets for the 53 * DHCP protocol. Subclasses create the specific packets used at each 54 * stage of the negotiation. 55 * 56 * @hide 57 */ 58 public abstract class DhcpPacket { 59 protected static final String TAG = "DhcpPacket"; 60 61 // TODO: use NetworkStackConstants.IPV4_MIN_MTU once this class is moved to the network stack. 62 private static final int IPV4_MIN_MTU = 68; 63 64 // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the 65 // CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the 66 // DHCP client timeout. 67 public static final String CONFIG_MINIMUM_LEASE = "dhcp_minimum_lease"; 68 public static final int DEFAULT_MINIMUM_LEASE = 60; 69 public static final int INFINITE_LEASE = (int) 0xffffffff; 70 71 public static final Inet4Address INADDR_ANY = IPV4_ADDR_ANY; 72 public static final Inet4Address INADDR_BROADCAST = IPV4_ADDR_ALL; 73 public static final byte[] ETHER_BROADCAST = new byte[] { 74 (byte) 0xff, (byte) 0xff, (byte) 0xff, 75 (byte) 0xff, (byte) 0xff, (byte) 0xff, 76 }; 77 78 /** 79 * Packet encapsulations. 80 */ 81 public static final int ENCAP_L2 = 0; // EthernetII header included 82 public static final int ENCAP_L3 = 1; // IP/UDP header included 83 public static final int ENCAP_BOOTP = 2; // BOOTP contents only 84 85 /** 86 * Minimum length of a DHCP packet, excluding options, in the above encapsulations. 87 */ 88 public static final int MIN_PACKET_LENGTH_BOOTP = 236; // See diagram in RFC 2131, section 2. 89 public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8; 90 public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14; 91 92 public static final int HWADDR_LEN = 16; 93 public static final int MAX_OPTION_LEN = 255; 94 95 // The lower boundary for V6ONLY_WAIT. 96 public static final long MIN_V6ONLY_WAIT_MS = 300_000; 97 public static final long V6ONLY_PREFERRED_ABSENCE = -1L; 98 99 /** 100 * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum 101 * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280, 102 * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500 103 * because in general it is risky to assume that the hardware is able to send/receive packets 104 * larger than 1500 bytes even if the network supports it. 105 */ 106 private static final int MIN_MTU = 1280; 107 private static final int MAX_MTU = 1500; 108 109 /** 110 * IP layer definitions. 111 */ 112 private static final byte IP_TYPE_UDP = (byte) 0x11; 113 114 /** 115 * IP: Version 4, Header Length 20 bytes 116 */ 117 private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45; 118 119 /** 120 * IP: Flags 0, Fragment Offset 0, Don't Fragment 121 */ 122 private static final short IP_FLAGS_OFFSET = (short) 0x4000; 123 124 /** 125 * IP: TOS 126 */ 127 private static final byte IP_TOS_LOWDELAY = (byte) 0x10; 128 129 /** 130 * IP: TTL -- use default 64 from RFC1340 131 */ 132 private static final byte IP_TTL = (byte) 0x40; 133 134 /** 135 * The client DHCP port. 136 */ 137 public static final short DHCP_CLIENT = (short) 68; 138 139 /** 140 * The server DHCP port. 141 */ 142 public static final short DHCP_SERVER = (short) 67; 143 144 /** 145 * The message op code indicating a request from a client. 146 */ 147 public static final byte DHCP_BOOTREQUEST = (byte) 1; 148 149 /** 150 * The message op code indicating a response from the server. 151 */ 152 public static final byte DHCP_BOOTREPLY = (byte) 2; 153 154 /** 155 * The code type used to identify an Ethernet MAC address in the 156 * Client-ID field. 157 */ 158 protected static final byte CLIENT_ID_ETHER = (byte) 1; 159 160 /** 161 * The maximum length of a packet that can be constructed. 162 */ 163 protected static final int MAX_LENGTH = 1500; 164 165 /** 166 * The magic cookie that identifies this as a DHCP packet instead of BOOTP. 167 */ 168 public static final int DHCP_MAGIC_COOKIE = 0x63825363; 169 170 /** 171 * DHCP Optional Type: DHCP Subnet Mask 172 */ 173 public static final byte DHCP_SUBNET_MASK = 1; 174 protected Inet4Address mSubnetMask; 175 176 /** 177 * DHCP Optional Type: DHCP Router 178 */ 179 public static final byte DHCP_ROUTER = 3; 180 protected List <Inet4Address> mGateways; 181 182 /** 183 * DHCP Optional Type: DHCP DNS Server 184 */ 185 public static final byte DHCP_DNS_SERVER = 6; 186 protected List<Inet4Address> mDnsServers; 187 188 /** 189 * DHCP Optional Type: DHCP Host Name 190 */ 191 public static final byte DHCP_HOST_NAME = 12; 192 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 193 public String mHostName; 194 195 /** 196 * DHCP Optional Type: DHCP DOMAIN NAME 197 */ 198 public static final byte DHCP_DOMAIN_NAME = 15; 199 protected String mDomainName; 200 201 /** 202 * DHCP Optional Type: DHCP Interface MTU 203 */ 204 public static final byte DHCP_MTU = 26; 205 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 206 public Short mMtu; 207 208 /** 209 * DHCP Optional Type: DHCP BROADCAST ADDRESS 210 */ 211 public static final byte DHCP_BROADCAST_ADDRESS = 28; 212 protected Inet4Address mBroadcastAddress; 213 214 /** 215 * DHCP Optional Type: Vendor specific information 216 */ 217 public static final byte DHCP_VENDOR_INFO = 43; 218 protected String mVendorInfo; 219 220 /** 221 * Value of the vendor specific option used to indicate that the network is metered 222 */ 223 public static final String VENDOR_INFO_ANDROID_METERED = "ANDROID_METERED"; 224 225 /** 226 * DHCP Optional Type: Option overload option 227 */ 228 public static final byte DHCP_OPTION_OVERLOAD = 52; 229 230 /** 231 * Possible values of the option overload option. 232 */ 233 private static final byte OPTION_OVERLOAD_FILE = 1; 234 private static final byte OPTION_OVERLOAD_SNAME = 2; 235 private static final byte OPTION_OVERLOAD_BOTH = 3; 236 237 /** 238 * DHCP Optional Type: DHCP Requested IP Address 239 */ 240 public static final byte DHCP_REQUESTED_IP = 50; 241 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 242 public Inet4Address mRequestedIp; 243 244 /** 245 * DHCP Optional Type: DHCP Lease Time 246 */ 247 public static final byte DHCP_LEASE_TIME = 51; 248 protected Integer mLeaseTime; 249 250 /** 251 * DHCP Optional Type: DHCP Message Type 252 */ 253 public static final byte DHCP_MESSAGE_TYPE = 53; 254 // the actual type values 255 public static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1; 256 public static final byte DHCP_MESSAGE_TYPE_OFFER = 2; 257 public static final byte DHCP_MESSAGE_TYPE_REQUEST = 3; 258 public static final byte DHCP_MESSAGE_TYPE_DECLINE = 4; 259 public static final byte DHCP_MESSAGE_TYPE_ACK = 5; 260 public static final byte DHCP_MESSAGE_TYPE_NAK = 6; 261 public static final byte DHCP_MESSAGE_TYPE_RELEASE = 7; 262 public static final byte DHCP_MESSAGE_TYPE_INFORM = 8; 263 264 /** 265 * DHCP Optional Type: DHCP Server Identifier 266 */ 267 public static final byte DHCP_SERVER_IDENTIFIER = 54; 268 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 269 public Inet4Address mServerIdentifier; 270 271 /** 272 * DHCP Optional Type: DHCP Parameter List 273 */ 274 public static final byte DHCP_PARAMETER_LIST = 55; 275 protected byte[] mRequestedParams; 276 277 /** 278 * DHCP Optional Type: DHCP MESSAGE 279 */ 280 public static final byte DHCP_MESSAGE = 56; 281 protected String mMessage; 282 283 /** 284 * DHCP Optional Type: Maximum DHCP Message Size 285 */ 286 public static final byte DHCP_MAX_MESSAGE_SIZE = 57; 287 protected Short mMaxMessageSize; 288 289 /** 290 * DHCP Optional Type: DHCP Renewal Time Value 291 */ 292 public static final byte DHCP_RENEWAL_TIME = 58; 293 protected Integer mT1; 294 295 /** 296 * DHCP Optional Type: Rebinding Time Value 297 */ 298 public static final byte DHCP_REBINDING_TIME = 59; 299 protected Integer mT2; 300 301 /** 302 * DHCP Optional Type: Vendor Class Identifier 303 */ 304 public static final byte DHCP_VENDOR_CLASS_ID = 60; 305 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 306 public String mVendorId; 307 308 /** 309 * DHCP Optional Type: DHCP Client Identifier 310 */ 311 public static final byte DHCP_CLIENT_IDENTIFIER = 61; 312 protected byte[] mClientId; 313 314 /** 315 * DHCP Optional Type: DHCP User Class option 316 */ 317 public static final byte DHCP_USER_CLASS = 77; 318 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 319 public byte[] mUserClass; 320 321 /** 322 * DHCP zero-length Optional Type: Rapid Commit. Per RFC4039, both DHCPDISCOVER and DHCPACK 323 * packet may include this option. 324 */ 325 public static final byte DHCP_RAPID_COMMIT = 80; 326 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 327 public boolean mRapidCommit; 328 329 /** 330 * DHCP IPv6-Only Preferred Option(RFC 8925). 331 * Indicate that a host supports an IPv6-only mode and willing to forgo obtaining an IPv4 332 * address for V6ONLY_WAIT period if the network provides IPv6 connectivity. V6ONLY_WAIT 333 * is 32-bit unsigned integer, so the Integer value cannot be used as-is. 334 */ 335 public static final byte DHCP_IPV6_ONLY_PREFERRED = (byte) 108; 336 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 337 public Integer mIpv6OnlyWaitTime; 338 339 public static final byte DHCP_CAPTIVE_PORTAL = (byte) 114; 340 protected String mCaptivePortalUrl; 341 342 /** 343 * DHCP Optional Type: Domain Search List, domain suffixes are space separated. 344 */ 345 public static final byte DHCP_DOMAIN_SEARCHLIST = (byte) 119; 346 protected List<String> mDmnSrchList; 347 348 /** 349 * DHCP zero-length option code: pad 350 */ 351 public static final byte DHCP_OPTION_PAD = 0x00; 352 353 /** 354 * DHCP zero-length option code: end of options 355 */ 356 public static final byte DHCP_OPTION_END = (byte) 0xff; 357 358 /** 359 * The transaction identifier used in this particular DHCP negotiation 360 */ 361 protected final int mTransId; 362 363 /** 364 * The seconds field in the BOOTP header. Per RFC, should be nonzero in client requests only. 365 */ 366 protected final short mSecs; 367 368 /** 369 * The IP address of the client host. This address is typically 370 * proposed by the client (from an earlier DHCP negotiation) or 371 * supplied by the server. 372 */ 373 @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED) 374 public final Inet4Address mClientIp; 375 protected final Inet4Address mYourIp; 376 private final Inet4Address mNextIp; 377 protected final Inet4Address mRelayIp; 378 379 /** 380 * Does the client request a broadcast response? 381 */ 382 protected boolean mBroadcast; 383 384 /** 385 * The six-octet MAC of the client. 386 */ 387 protected final byte[] mClientMac; 388 389 /** 390 * The server host name from server. 391 */ 392 protected String mServerHostName; 393 394 /** 395 * The customized DHCP client options to be sent. 396 */ 397 @Nullable 398 protected List<DhcpOption> mCustomizedClientOptions; 399 400 /** 401 * Asks the packet object to create a ByteBuffer serialization of 402 * the packet for transmission. 403 */ buildPacket(int encap, short destUdp, short srcUdp)404 public abstract ByteBuffer buildPacket(int encap, short destUdp, 405 short srcUdp); 406 407 /** 408 * Allows the concrete class to fill in packet-type-specific details, 409 * typically optional parameters at the end of the packet. 410 */ finishPacket(ByteBuffer buffer)411 abstract void finishPacket(ByteBuffer buffer); 412 413 // Set in unit tests, to ensure that the test does not break when run on different devices and 414 // on different releases. 415 static String sTestOverrideVendorId = null; 416 DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp, Inet4Address nextIp, Inet4Address relayIp, byte[] clientMac, boolean broadcast)417 protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp, 418 Inet4Address nextIp, Inet4Address relayIp, 419 byte[] clientMac, boolean broadcast) { 420 mTransId = transId; 421 mSecs = secs; 422 mClientIp = clientIp; 423 mYourIp = yourIp; 424 mNextIp = nextIp; 425 mRelayIp = relayIp; 426 mClientMac = clientMac; 427 mBroadcast = broadcast; 428 } 429 430 /** 431 * Returns the transaction ID. 432 */ getTransactionId()433 public int getTransactionId() { 434 return mTransId; 435 } 436 437 /** 438 * Returns the client MAC. 439 */ getClientMac()440 public byte[] getClientMac() { 441 return mClientMac; 442 } 443 444 // TODO: refactor DhcpClient to set clientId when constructing packets and remove 445 // hasExplicitClientId logic 446 /** 447 * Returns whether a client ID was set in the options for this packet. 448 */ hasExplicitClientId()449 public boolean hasExplicitClientId() { 450 return mClientId != null; 451 } 452 453 /** 454 * Convenience method to return the client ID if it was set explicitly, or null otherwise. 455 */ 456 @Nullable getExplicitClientIdOrNull()457 public byte[] getExplicitClientIdOrNull() { 458 return hasExplicitClientId() ? getClientId() : null; 459 } 460 461 /** 462 * Returns the client ID. If not set explicitly, this follows RFC 2132 and creates a client ID 463 * based on the hardware address. 464 */ getClientId()465 public byte[] getClientId() { 466 final byte[] clientId; 467 if (hasExplicitClientId()) { 468 clientId = Arrays.copyOf(mClientId, mClientId.length); 469 } else { 470 clientId = new byte[mClientMac.length + 1]; 471 clientId[0] = CLIENT_ID_ETHER; 472 System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length); 473 } 474 return clientId; 475 } 476 477 /** 478 * Returns whether a parameter is included in the parameter request list option of this packet. 479 * 480 * <p>If there is no parameter request list option in the packet, false is returned. 481 * 482 * @param paramId ID of the parameter, such as {@link #DHCP_MTU} or {@link #DHCP_HOST_NAME}. 483 */ hasRequestedParam(byte paramId)484 public boolean hasRequestedParam(byte paramId) { 485 if (mRequestedParams == null) { 486 return false; 487 } 488 489 for (byte reqParam : mRequestedParams) { 490 if (reqParam == paramId) { 491 return true; 492 } 493 } 494 return false; 495 } 496 497 /** 498 * Creates a new L3 packet (including IP header) containing the 499 * DHCP udp packet. This method relies upon the delegated method 500 * finishPacket() to insert the per-packet contents. 501 */ fillInPacket(int encap, Inet4Address destIp, Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf, byte requestCode, boolean broadcast)502 protected void fillInPacket(int encap, Inet4Address destIp, 503 Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf, 504 byte requestCode, boolean broadcast) { 505 byte[] destIpArray = destIp.getAddress(); 506 byte[] srcIpArray = srcIp.getAddress(); 507 int ipHeaderOffset = 0; 508 int ipLengthOffset = 0; 509 int ipChecksumOffset = 0; 510 int endIpHeader = 0; 511 int udpHeaderOffset = 0; 512 int udpLengthOffset = 0; 513 int udpChecksumOffset = 0; 514 515 buf.clear(); 516 buf.order(ByteOrder.BIG_ENDIAN); 517 518 if (encap == ENCAP_L2) { 519 buf.put(ETHER_BROADCAST); 520 buf.put(mClientMac); 521 buf.putShort((short) OsConstants.ETH_P_IP); 522 } 523 524 // if a full IP packet needs to be generated, put the IP & UDP 525 // headers in place, and pre-populate with artificial values 526 // needed to seed the IP checksum. 527 if (encap <= ENCAP_L3) { 528 ipHeaderOffset = buf.position(); 529 buf.put(IP_VERSION_HEADER_LEN); 530 buf.put(IP_TOS_LOWDELAY); // tos: IPTOS_LOWDELAY 531 ipLengthOffset = buf.position(); 532 buf.putShort((short)0); // length 533 buf.putShort((short)0); // id 534 buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment 535 buf.put(IP_TTL); // TTL: use default 64 from RFC1340 536 buf.put(IP_TYPE_UDP); 537 ipChecksumOffset = buf.position(); 538 buf.putShort((short) 0); // checksum 539 540 buf.put(srcIpArray); 541 buf.put(destIpArray); 542 endIpHeader = buf.position(); 543 544 // UDP header 545 udpHeaderOffset = buf.position(); 546 buf.putShort(srcUdp); 547 buf.putShort(destUdp); 548 udpLengthOffset = buf.position(); 549 buf.putShort((short) 0); // length 550 udpChecksumOffset = buf.position(); 551 buf.putShort((short) 0); // UDP checksum -- initially zero 552 } 553 554 // DHCP payload 555 buf.put(requestCode); 556 buf.put((byte) 1); // Hardware Type: Ethernet 557 buf.put((byte) mClientMac.length); // Hardware Address Length 558 buf.put((byte) 0); // Hop Count 559 buf.putInt(mTransId); // Transaction ID 560 buf.putShort(mSecs); // Elapsed Seconds 561 562 if (broadcast) { 563 buf.putShort((short) 0x8000); // Flags 564 } else { 565 buf.putShort((short) 0x0000); // Flags 566 } 567 568 buf.put(mClientIp.getAddress()); 569 buf.put(mYourIp.getAddress()); 570 buf.put(mNextIp.getAddress()); 571 buf.put(mRelayIp.getAddress()); 572 buf.put(mClientMac); 573 buf.position(buf.position() + 574 (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes 575 + 64 // empty server host name (64 bytes) 576 + 128); // empty boot file name (128 bytes) 577 buf.putInt(DHCP_MAGIC_COOKIE); // magic number 578 finishPacket(buf); 579 580 // round up to an even number of octets 581 if ((buf.position() & 1) == 1) { 582 buf.put((byte) 0); 583 } 584 585 // If an IP packet is being built, the IP & UDP checksums must be 586 // computed. 587 if (encap <= ENCAP_L3) { 588 // fix UDP header: insert length 589 short udpLen = (short)(buf.position() - udpHeaderOffset); 590 buf.putShort(udpLengthOffset, udpLen); 591 // fix UDP header: checksum 592 // checksum for UDP at udpChecksumOffset 593 int udpSeed = 0; 594 595 // apply IPv4 pseudo-header. Read IP address src and destination 596 // values from the IP header and accumulate checksum. 597 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2)); 598 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4)); 599 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6)); 600 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8)); 601 602 // accumulate extra data for the pseudo-header 603 udpSeed += IP_TYPE_UDP; 604 udpSeed += udpLen; 605 // and compute UDP checksum 606 buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed, 607 udpHeaderOffset, 608 buf.position())); 609 // fix IP header: insert length 610 buf.putShort(ipLengthOffset, (short)(buf.position() - ipHeaderOffset)); 611 // fixup IP-header checksum 612 buf.putShort(ipChecksumOffset, 613 (short) checksum(buf, 0, ipHeaderOffset, endIpHeader)); 614 } 615 } 616 617 /** 618 * Converts a signed short value to an unsigned int value. Needed 619 * because Java does not have unsigned types. 620 */ intAbs(short v)621 private static int intAbs(short v) { 622 return v & 0xFFFF; 623 } 624 625 /** 626 * Performs an IP checksum (used in IP header and across UDP 627 * payload) on the specified portion of a ByteBuffer. The seed 628 * allows the checksum to commence with a specified value. 629 */ checksum(ByteBuffer buf, int seed, int start, int end)630 private int checksum(ByteBuffer buf, int seed, int start, int end) { 631 int sum = seed; 632 int bufPosition = buf.position(); 633 634 // set position of original ByteBuffer, so that the ShortBuffer 635 // will be correctly initialized 636 buf.position(start); 637 ShortBuffer shortBuf = buf.asShortBuffer(); 638 639 // re-set ByteBuffer position 640 buf.position(bufPosition); 641 642 short[] shortArray = new short[(end - start) / 2]; 643 shortBuf.get(shortArray); 644 645 for (short s : shortArray) { 646 sum += intAbs(s); 647 } 648 649 start += shortArray.length * 2; 650 651 // see if a singleton byte remains 652 if (end != start) { 653 short b = buf.get(start); 654 655 // make it unsigned 656 if (b < 0) { 657 b += 256; 658 } 659 660 sum += b * 256; 661 } 662 663 sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); 664 sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF); 665 int negated = ~sum; 666 return intAbs((short) negated); 667 } 668 669 /** 670 * Adds an optional parameter containing a single byte value. 671 */ addTlv(ByteBuffer buf, byte type, byte value)672 protected static void addTlv(ByteBuffer buf, byte type, byte value) { 673 buf.put(type); 674 buf.put((byte) 1); 675 buf.put(value); 676 } 677 678 /** 679 * Adds an optional parameter containing zero-length value. 680 */ addTlv(ByteBuffer buf, byte type)681 protected static void addTlv(ByteBuffer buf, byte type) { 682 buf.put(type); 683 buf.put((byte) 0); 684 } 685 686 /** 687 * Adds an optional parameter containing an array of bytes. 688 * 689 * <p>This method is a no-op if the payload argument is null. 690 */ addTlv(ByteBuffer buf, byte type, @Nullable byte[] payload)691 protected static void addTlv(ByteBuffer buf, byte type, @Nullable byte[] payload) { 692 if (payload != null) { 693 if (payload.length > MAX_OPTION_LEN) { 694 throw new IllegalArgumentException("DHCP option too long: " 695 + payload.length + " vs. " + MAX_OPTION_LEN); 696 } 697 buf.put(type); 698 buf.put((byte) payload.length); 699 buf.put(payload); 700 } 701 } 702 703 /** 704 * Adds an optional parameter containing an IP address. 705 * 706 * <p>This method is a no-op if the address argument is null. 707 */ addTlv(ByteBuffer buf, byte type, @Nullable Inet4Address addr)708 protected static void addTlv(ByteBuffer buf, byte type, @Nullable Inet4Address addr) { 709 if (addr != null) { 710 addTlv(buf, type, addr.getAddress()); 711 } 712 } 713 714 /** 715 * Adds an optional parameter containing a list of IP addresses. 716 * 717 * <p>This method is a no-op if the addresses argument is null or empty. 718 */ addTlv(ByteBuffer buf, byte type, @Nullable List<Inet4Address> addrs)719 protected static void addTlv(ByteBuffer buf, byte type, @Nullable List<Inet4Address> addrs) { 720 if (addrs == null || addrs.size() == 0) return; 721 722 int optionLen = 4 * addrs.size(); 723 if (optionLen > MAX_OPTION_LEN) { 724 throw new IllegalArgumentException("DHCP option too long: " 725 + optionLen + " vs. " + MAX_OPTION_LEN); 726 } 727 728 buf.put(type); 729 buf.put((byte)(optionLen)); 730 731 for (Inet4Address addr : addrs) { 732 buf.put(addr.getAddress()); 733 } 734 } 735 736 /** 737 * Adds an optional parameter containing a short integer. 738 * 739 * <p>This method is a no-op if the value argument is null. 740 */ addTlv(ByteBuffer buf, byte type, @Nullable Short value)741 protected static void addTlv(ByteBuffer buf, byte type, @Nullable Short value) { 742 if (value != null) { 743 buf.put(type); 744 buf.put((byte) 2); 745 buf.putShort(value.shortValue()); 746 } 747 } 748 749 /** 750 * Adds an optional parameter containing a simple integer. 751 * 752 * <p>This method is a no-op if the value argument is null. 753 */ addTlv(ByteBuffer buf, byte type, @Nullable Integer value)754 protected static void addTlv(ByteBuffer buf, byte type, @Nullable Integer value) { 755 if (value != null) { 756 buf.put(type); 757 buf.put((byte) 4); 758 buf.putInt(value.intValue()); 759 } 760 } 761 762 /** 763 * Adds an optional parameter containing an ASCII string. 764 * 765 * <p>This method is a no-op if the string argument is null. 766 */ addTlv(ByteBuffer buf, byte type, @Nullable String str)767 protected static void addTlv(ByteBuffer buf, byte type, @Nullable String str) { 768 if (str != null) { 769 try { 770 addTlv(buf, type, str.getBytes("US-ASCII")); 771 } catch (UnsupportedEncodingException e) { 772 throw new IllegalArgumentException("String is not US-ASCII: " + str); 773 } 774 } 775 } 776 777 /** 778 * Adds the special end-of-optional-parameters indicator. 779 */ addTlvEnd(ByteBuffer buf)780 protected static void addTlvEnd(ByteBuffer buf) { 781 buf.put((byte) 0xFF); 782 } 783 784 /** 785 * Get the DHCP Vendor Class Identifier. 786 * 787 * By default the vendor Id is "android-dhcp-<version>". The default value will be overwritten 788 * with the customized option value if any. 789 */ getVendorId(@ullable List<DhcpOption> customizedClientOptions)790 private static String getVendorId(@Nullable List<DhcpOption> customizedClientOptions) { 791 if (sTestOverrideVendorId != null) return sTestOverrideVendorId; 792 793 String vendorId = "android-dhcp-" + Build.VERSION.RELEASE; 794 if (customizedClientOptions != null) { 795 for (DhcpOption option : customizedClientOptions) { 796 if (option.type == DHCP_VENDOR_CLASS_ID) { 797 vendorId = readAsciiString(option.value, false); 798 break; 799 } 800 } 801 } 802 return vendorId; 803 } 804 805 /** 806 * Get the DHCP client hostname after transliteration. 807 */ 808 @VisibleForTesting getHostname()809 public String getHostname() { 810 if (mHostName == null && !isAtLeastR()) { 811 return SystemProperties.get("net.hostname"); 812 } 813 return mHostName; 814 } 815 816 /** 817 * Adds common client TLVs. 818 * 819 * TODO: Does this belong here? The alternative would be to modify all the buildXyzPacket 820 * methods to take them. 821 */ addCommonClientTlvs(ByteBuffer buf)822 protected void addCommonClientTlvs(ByteBuffer buf) { 823 addTlv(buf, DHCP_MAX_MESSAGE_SIZE, (short) MAX_LENGTH); 824 addTlv(buf, DHCP_VENDOR_CLASS_ID, mVendorId); 825 final String hn = getHostname(); 826 if (!TextUtils.isEmpty(hn)) addTlv(buf, DHCP_HOST_NAME, hn); 827 } 828 829 /** 830 * Adds OEM's customized client TLVs, which will be appended before the End Tlv. 831 */ addCustomizedClientTlvs(ByteBuffer buf)832 protected void addCustomizedClientTlvs(ByteBuffer buf) { 833 if (mCustomizedClientOptions == null) return; 834 for (DhcpOption option : mCustomizedClientOptions) { 835 // A null value means the option should only be put into the PRL. 836 if (option.value == null) continue; 837 // The vendor class ID was already added by addCommonClientTlvs. 838 if (option.type == DHCP_VENDOR_CLASS_ID) continue; 839 addTlv(buf, option.type, option.value); 840 } 841 } 842 843 // The common server TLVs are corresponding to the parameter request list from client. addCommonServerTlvs(ByteBuffer buf)844 protected void addCommonServerTlvs(ByteBuffer buf) { 845 addTlv(buf, DHCP_LEASE_TIME, mLeaseTime); 846 if (mLeaseTime != null && mLeaseTime != INFINITE_LEASE) { 847 // The client should renew at 1/2 the lease-expiry interval 848 addTlv(buf, DHCP_RENEWAL_TIME, (int) (Integer.toUnsignedLong(mLeaseTime) / 2)); 849 // Default rebinding time is set as below by RFC2131 850 addTlv(buf, DHCP_REBINDING_TIME, 851 (int) (Integer.toUnsignedLong(mLeaseTime) * 875L / 1000L)); 852 } 853 addTlv(buf, DHCP_SUBNET_MASK, mSubnetMask); 854 addTlv(buf, DHCP_BROADCAST_ADDRESS, mBroadcastAddress); 855 addTlv(buf, DHCP_ROUTER, mGateways); 856 addTlv(buf, DHCP_DNS_SERVER, mDnsServers); 857 addTlv(buf, DHCP_DOMAIN_NAME, mDomainName); 858 addTlv(buf, DHCP_HOST_NAME, mHostName); 859 addTlv(buf, DHCP_VENDOR_INFO, mVendorInfo); 860 if (mMtu != null && Short.toUnsignedInt(mMtu) >= IPV4_MIN_MTU) { 861 addTlv(buf, DHCP_MTU, mMtu); 862 } 863 if (mIpv6OnlyWaitTime != null) { 864 addTlv(buf, DHCP_IPV6_ONLY_PREFERRED, (int) Integer.toUnsignedLong(mIpv6OnlyWaitTime)); 865 } 866 if (mDmnSrchList != null && mDmnSrchList.size() > 0) { 867 // domain search list string is space separated. 868 String[] searchList = new String[mDmnSrchList.size()]; 869 for (int i = 0; i < mDmnSrchList.size(); i++) { 870 searchList[i] = mDmnSrchList.get(i); 871 } 872 final byte[] domains = DomainUtils.encode(searchList, true /* compression */); 873 addTlv(buf, DHCP_DOMAIN_SEARCHLIST, domains); 874 } 875 addTlv(buf, DHCP_CAPTIVE_PORTAL, mCaptivePortalUrl); 876 } 877 878 /** 879 * Converts a MAC from an array of octets to an ASCII string. 880 */ macToString(byte[] mac)881 public static String macToString(byte[] mac) { 882 String macAddr = ""; 883 884 for (int i = 0; i < mac.length; i++) { 885 String hexString = "0" + Integer.toHexString(mac[i]); 886 887 // substring operation grabs the last 2 digits: this 888 // allows signed bytes to be converted correctly. 889 macAddr += hexString.substring(hexString.length() - 2); 890 891 if (i != (mac.length - 1)) { 892 macAddr += ":"; 893 } 894 } 895 896 return macAddr; 897 } 898 toString()899 public String toString() { 900 String macAddr = macToString(mClientMac); 901 902 return macAddr; 903 } 904 905 /** 906 * Reads a four-octet value from a ByteBuffer and construct 907 * an IPv4 address from that value. 908 */ readIpAddress(ByteBuffer packet)909 private static Inet4Address readIpAddress(ByteBuffer packet) { 910 Inet4Address result = null; 911 byte[] ipAddr = new byte[4]; 912 packet.get(ipAddr); 913 914 try { 915 result = (Inet4Address) Inet4Address.getByAddress(ipAddr); 916 } catch (UnknownHostException ex) { 917 // ipAddr is numeric, so this should not be 918 // triggered. However, if it is, just nullify 919 result = null; 920 } 921 922 return result; 923 } 924 925 /** 926 * Reads a string of specified length from the buffer. 927 */ readAsciiString(@onNull final ByteBuffer buf, int byteCount, boolean nullOk)928 private static String readAsciiString(@NonNull final ByteBuffer buf, int byteCount, 929 boolean nullOk) { 930 final byte[] bytes = new byte[byteCount]; 931 buf.get(bytes); 932 return readAsciiString(bytes, nullOk); 933 } 934 readAsciiString(@onNull final byte[] payload, boolean nullOk)935 private static String readAsciiString(@NonNull final byte[] payload, boolean nullOk) { 936 final byte[] bytes = payload; 937 int length = bytes.length; 938 if (!nullOk) { 939 // Stop at the first null byte. This is because some DHCP options (e.g., the domain 940 // name) are passed to netd via FrameworkListener, which refuses arguments containing 941 // null bytes. We don't do this by default because vendorInfo is an opaque string which 942 // could in theory contain null bytes. 943 for (length = 0; length < bytes.length; length++) { 944 if (bytes[length] == 0) { 945 break; 946 } 947 } 948 } 949 return new String(bytes, 0, length, StandardCharsets.US_ASCII); 950 } 951 isPacketToOrFromClient(short udpSrcPort, short udpDstPort)952 private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) { 953 return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT); 954 } 955 isPacketServerToServer(short udpSrcPort, short udpDstPort)956 private static boolean isPacketServerToServer(short udpSrcPort, short udpDstPort) { 957 return (udpSrcPort == DHCP_SERVER) && (udpDstPort == DHCP_SERVER); 958 } 959 960 public static class ParseException extends Exception { 961 public final int errorCode; ParseException(int errorCode, String msg, Object... args)962 public ParseException(int errorCode, String msg, Object... args) { 963 super(String.format(msg, args)); 964 this.errorCode = errorCode; 965 } 966 } 967 skipOption(ByteBuffer packet, int optionLen)968 private static int skipOption(ByteBuffer packet, int optionLen) 969 throws BufferUnderflowException { 970 int expectedLen = 0; 971 for (int i = 0; i < optionLen; i++) { 972 expectedLen++; 973 packet.get(); 974 } 975 return expectedLen; 976 } 977 shouldSkipOption(byte optionType, byte[] optionsToSkip)978 private static boolean shouldSkipOption(byte optionType, byte[] optionsToSkip) { 979 for (byte option : optionsToSkip) { 980 if (option == optionType) return true; 981 } 982 return false; 983 } 984 985 /** 986 * Creates a concrete DhcpPacket from the supplied ByteBuffer. The 987 * buffer may have an L2 encapsulation (which is the full EthernetII 988 * format starting with the source-address MAC) or an L3 encapsulation 989 * (which starts with the IP header). 990 * <br> 991 * A subset of the optional parameters are parsed and are stored 992 * in object fields. 993 */ 994 @VisibleForTesting decodeFullPacket(ByteBuffer packet, int pktType, byte[] optionsToSkip)995 static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType, byte[] optionsToSkip) 996 throws ParseException { 997 // bootp parameters 998 int transactionId; 999 short secs; 1000 Inet4Address clientIp; 1001 Inet4Address yourIp; 1002 Inet4Address nextIp; 1003 Inet4Address relayIp; 1004 byte[] clientMac; 1005 byte[] clientId = null; 1006 List<Inet4Address> dnsServers = new ArrayList<>(); 1007 List<Inet4Address> gateways = new ArrayList<>(); // aka router 1008 ArrayList<String> dmnSrchList = new ArrayList<>(); 1009 Inet4Address serverIdentifier = null; 1010 Inet4Address netMask = null; 1011 String message = null; 1012 String vendorId = null; 1013 String vendorInfo = null; 1014 boolean rapidCommit = false; 1015 String captivePortalUrl = null; 1016 byte[] expectedParams = null; 1017 String hostName = null; 1018 String domainName = null; 1019 Inet4Address ipSrc = null; 1020 Inet4Address ipDst = null; 1021 Inet4Address bcAddr = null; 1022 Inet4Address requestedIp = null; 1023 String serverHostName; 1024 byte optionOverload = 0; 1025 byte[] userClass = null; 1026 1027 // The following are all unsigned integers. Internally we store them as signed integers of 1028 // the same length because that way we're guaranteed that they can't be out of the range of 1029 // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need 1030 // to cast it. 1031 Short mtu = null; 1032 Short maxMessageSize = null; 1033 Integer leaseTime = null; 1034 Integer T1 = null; 1035 Integer T2 = null; 1036 Integer ipv6OnlyWaitTime = null; 1037 1038 // dhcp options 1039 byte dhcpType = (byte) 0xFF; 1040 1041 packet.order(ByteOrder.BIG_ENDIAN); 1042 1043 // check to see if we need to parse L2, IP, and UDP encaps 1044 if (pktType == ENCAP_L2) { 1045 if (packet.remaining() < MIN_PACKET_LENGTH_L2) { 1046 throw new ParseException(DhcpErrorEvent.L2_TOO_SHORT, 1047 "L2 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L2); 1048 } 1049 1050 byte[] l2dst = new byte[6]; 1051 byte[] l2src = new byte[6]; 1052 1053 packet.get(l2dst); 1054 packet.get(l2src); 1055 1056 short l2type = packet.getShort(); 1057 1058 if (l2type != OsConstants.ETH_P_IP) { 1059 throw new ParseException(DhcpErrorEvent.L2_WRONG_ETH_TYPE, 1060 "Unexpected L2 type 0x%04x, expected 0x%04x", l2type, OsConstants.ETH_P_IP); 1061 } 1062 } 1063 1064 if (pktType <= ENCAP_L3) { 1065 if (packet.remaining() < MIN_PACKET_LENGTH_L3) { 1066 throw new ParseException(DhcpErrorEvent.L3_TOO_SHORT, 1067 "L3 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L3); 1068 } 1069 1070 byte ipTypeAndLength = packet.get(); 1071 int ipVersion = (ipTypeAndLength & 0xf0) >> 4; 1072 if (ipVersion != 4) { 1073 throw new ParseException( 1074 DhcpErrorEvent.L3_NOT_IPV4, "Invalid IP version %d", ipVersion); 1075 } 1076 1077 // System.out.println("ipType is " + ipType); 1078 byte ipDiffServicesField = packet.get(); 1079 short ipTotalLength = packet.getShort(); 1080 short ipIdentification = packet.getShort(); 1081 byte ipFlags = packet.get(); 1082 byte ipFragOffset = packet.get(); 1083 byte ipTTL = packet.get(); 1084 byte ipProto = packet.get(); 1085 short ipChksm = packet.getShort(); 1086 1087 ipSrc = readIpAddress(packet); 1088 ipDst = readIpAddress(packet); 1089 1090 if (ipProto != IP_TYPE_UDP) { 1091 throw new ParseException( 1092 DhcpErrorEvent.L4_NOT_UDP, "Protocol not UDP: %d", ipProto); 1093 } 1094 1095 // Skip options. This cannot cause us to read beyond the end of the buffer because the 1096 // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than 1097 // MIN_PACKET_LENGTH_L3. 1098 int optionWords = ((ipTypeAndLength & 0x0f) - 5); 1099 for (int i = 0; i < optionWords; i++) { 1100 packet.getInt(); 1101 } 1102 1103 // assume UDP 1104 short udpSrcPort = packet.getShort(); 1105 short udpDstPort = packet.getShort(); 1106 short udpLen = packet.getShort(); 1107 short udpChkSum = packet.getShort(); 1108 1109 // Only accept packets to or from the well-known client port (expressly permitting 1110 // packets from ports other than the well-known server port; http://b/24687559), and 1111 // server-to-server packets, e.g. for relays. 1112 if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) && 1113 !isPacketServerToServer(udpSrcPort, udpDstPort)) { 1114 // This should almost never happen because we use SO_ATTACH_FILTER on the packet 1115 // socket to drop packets that don't have the right source ports. However, it's 1116 // possible that a packet arrives between when the socket is bound and when the 1117 // filter is set. http://b/26696823 . 1118 throw new ParseException(DhcpErrorEvent.L4_WRONG_PORT, 1119 "Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort); 1120 } 1121 } 1122 1123 // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length. 1124 if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) { 1125 throw new ParseException(DhcpErrorEvent.BOOTP_TOO_SHORT, 1126 "Invalid type or BOOTP packet too short, %d < %d", 1127 packet.remaining(), MIN_PACKET_LENGTH_BOOTP); 1128 } 1129 1130 byte type = packet.get(); 1131 byte hwType = packet.get(); 1132 int addrLen = packet.get() & 0xff; 1133 byte hops = packet.get(); 1134 transactionId = packet.getInt(); 1135 secs = packet.getShort(); 1136 short bootpFlags = packet.getShort(); 1137 boolean broadcast = (bootpFlags & 0x8000) != 0; 1138 byte[] ipv4addr = new byte[4]; 1139 1140 try { 1141 packet.get(ipv4addr); 1142 clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr); 1143 packet.get(ipv4addr); 1144 yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr); 1145 packet.get(ipv4addr); 1146 nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr); 1147 packet.get(ipv4addr); 1148 relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr); 1149 } catch (UnknownHostException ex) { 1150 throw new ParseException(DhcpErrorEvent.L3_INVALID_IP, 1151 "Invalid IPv4 address: %s", Arrays.toString(ipv4addr)); 1152 } 1153 1154 // Some DHCP servers have been known to announce invalid client hardware address values such 1155 // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at 1156 // all but only checks that the interface MAC address matches the first bytes of the address 1157 // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger 1158 // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795 1159 // TODO: evaluate whether to make this test more liberal. 1160 if (addrLen > HWADDR_LEN) { 1161 addrLen = ETHER_BROADCAST.length; 1162 } 1163 1164 clientMac = new byte[addrLen]; 1165 packet.get(clientMac); 1166 1167 // skip over address padding (16 octets allocated) 1168 packet.position(packet.position() + (16 - addrLen)); 1169 serverHostName = readAsciiString(packet, 64, false); 1170 packet.position(packet.position() + 128); 1171 1172 // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211 1173 if (packet.remaining() < 4) { 1174 throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message"); 1175 } 1176 1177 int dhcpMagicCookie = packet.getInt(); 1178 if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) { 1179 throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE, 1180 "Bad magic cookie 0x%08x, should be 0x%08x", 1181 dhcpMagicCookie, DHCP_MAGIC_COOKIE); 1182 } 1183 1184 // parse options 1185 boolean notFinishedOptions = true; 1186 1187 while ((packet.position() < packet.limit()) && notFinishedOptions) { 1188 final byte optionType = packet.get(); // cannot underflow because position < limit 1189 try { 1190 if (optionType == DHCP_OPTION_END) { 1191 notFinishedOptions = false; 1192 } else if (optionType == DHCP_OPTION_PAD) { 1193 // The pad option doesn't have a length field. Nothing to do. 1194 } else { 1195 int optionLen = packet.get() & 0xFF; 1196 int expectedLen = 0; 1197 1198 if (shouldSkipOption(optionType, optionsToSkip)) { 1199 skipOption(packet, optionLen); 1200 continue; 1201 } 1202 1203 switch(optionType) { 1204 case DHCP_SUBNET_MASK: 1205 netMask = readIpAddress(packet); 1206 expectedLen = 4; 1207 break; 1208 case DHCP_ROUTER: 1209 for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) { 1210 gateways.add(readIpAddress(packet)); 1211 } 1212 break; 1213 case DHCP_DNS_SERVER: 1214 for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) { 1215 dnsServers.add(readIpAddress(packet)); 1216 } 1217 break; 1218 case DHCP_HOST_NAME: 1219 expectedLen = optionLen; 1220 hostName = readAsciiString(packet, optionLen, false); 1221 break; 1222 case DHCP_MTU: 1223 expectedLen = 2; 1224 mtu = packet.getShort(); 1225 break; 1226 case DHCP_DOMAIN_NAME: 1227 expectedLen = optionLen; 1228 domainName = readAsciiString(packet, optionLen, false); 1229 break; 1230 case DHCP_BROADCAST_ADDRESS: 1231 bcAddr = readIpAddress(packet); 1232 expectedLen = 4; 1233 break; 1234 case DHCP_REQUESTED_IP: 1235 requestedIp = readIpAddress(packet); 1236 expectedLen = 4; 1237 break; 1238 case DHCP_LEASE_TIME: 1239 leaseTime = Integer.valueOf(packet.getInt()); 1240 expectedLen = 4; 1241 break; 1242 case DHCP_MESSAGE_TYPE: 1243 dhcpType = packet.get(); 1244 expectedLen = 1; 1245 break; 1246 case DHCP_SERVER_IDENTIFIER: 1247 serverIdentifier = readIpAddress(packet); 1248 expectedLen = 4; 1249 break; 1250 case DHCP_PARAMETER_LIST: 1251 expectedParams = new byte[optionLen]; 1252 packet.get(expectedParams); 1253 expectedLen = optionLen; 1254 break; 1255 case DHCP_MESSAGE: 1256 expectedLen = optionLen; 1257 message = readAsciiString(packet, optionLen, false); 1258 break; 1259 case DHCP_MAX_MESSAGE_SIZE: 1260 expectedLen = 2; 1261 maxMessageSize = Short.valueOf(packet.getShort()); 1262 break; 1263 case DHCP_RENEWAL_TIME: 1264 expectedLen = 4; 1265 T1 = Integer.valueOf(packet.getInt()); 1266 break; 1267 case DHCP_REBINDING_TIME: 1268 expectedLen = 4; 1269 T2 = Integer.valueOf(packet.getInt()); 1270 break; 1271 case DHCP_VENDOR_CLASS_ID: 1272 expectedLen = optionLen; 1273 // Embedded nulls are safe as this does not get passed to netd. 1274 vendorId = readAsciiString(packet, optionLen, true); 1275 break; 1276 case DHCP_CLIENT_IDENTIFIER: { // Client identifier 1277 clientId = new byte[optionLen]; 1278 packet.get(clientId); 1279 expectedLen = optionLen; 1280 } break; 1281 case DHCP_VENDOR_INFO: 1282 expectedLen = optionLen; 1283 // Embedded nulls are safe as this does not get passed to netd. 1284 vendorInfo = readAsciiString(packet, optionLen, true); 1285 break; 1286 case DHCP_OPTION_OVERLOAD: 1287 expectedLen = 1; 1288 optionOverload = packet.get(); 1289 optionOverload &= OPTION_OVERLOAD_BOTH; 1290 break; 1291 case DHCP_USER_CLASS: 1292 userClass = new byte[optionLen]; 1293 packet.get(userClass); 1294 expectedLen = optionLen; 1295 break; 1296 case DHCP_RAPID_COMMIT: 1297 expectedLen = 0; 1298 rapidCommit = true; 1299 break; 1300 case DHCP_CAPTIVE_PORTAL: 1301 expectedLen = optionLen; 1302 captivePortalUrl = readAsciiString(packet, optionLen, true); 1303 break; 1304 case DHCP_IPV6_ONLY_PREFERRED: 1305 if (optionLen == 4) { 1306 expectedLen = optionLen; 1307 ipv6OnlyWaitTime = Integer.valueOf(packet.getInt()); 1308 } else { 1309 // rfc8925#section-3.1: The client MUST ignore the IPv6-Only 1310 // Preferred option if the length field value is not 4. 1311 expectedLen = skipOption(packet, optionLen); 1312 } 1313 break; 1314 case DHCP_DOMAIN_SEARCHLIST: 1315 // TODO: should support multiple options(i.e. length > 255)? 1316 expectedLen = optionLen; 1317 final byte[] bytes = new byte[expectedLen]; 1318 packet.get(bytes); 1319 final ByteBuffer buf = ByteBuffer.wrap(bytes); 1320 dmnSrchList = DomainUtils.decode(buf, true /* compression */); 1321 break; 1322 default: 1323 expectedLen = skipOption(packet, optionLen); 1324 } 1325 1326 if (expectedLen != optionLen) { 1327 final int errorCode = DhcpErrorEvent.errorCodeWithOption( 1328 DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType); 1329 throw new ParseException(errorCode, 1330 "Invalid length %d for option %d, expected %d", 1331 optionLen, optionType, expectedLen); 1332 } 1333 } 1334 } catch (BufferUnderflowException e) { 1335 final int errorCode = DhcpErrorEvent.errorCodeWithOption( 1336 DhcpErrorEvent.BUFFER_UNDERFLOW, optionType); 1337 throw new ParseException(errorCode, "BufferUnderflowException"); 1338 } 1339 } 1340 1341 DhcpPacket newPacket; 1342 1343 switch(dhcpType) { 1344 case (byte) 0xFF: 1345 throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE, 1346 "No DHCP message type option"); 1347 case DHCP_MESSAGE_TYPE_DISCOVER: 1348 newPacket = new DhcpDiscoverPacket(transactionId, secs, relayIp, clientMac, 1349 broadcast, ipSrc, rapidCommit); 1350 break; 1351 case DHCP_MESSAGE_TYPE_OFFER: 1352 newPacket = new DhcpOfferPacket( 1353 transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac); 1354 break; 1355 case DHCP_MESSAGE_TYPE_REQUEST: 1356 newPacket = new DhcpRequestPacket( 1357 transactionId, secs, clientIp, relayIp, clientMac, broadcast); 1358 break; 1359 case DHCP_MESSAGE_TYPE_DECLINE: 1360 newPacket = new DhcpDeclinePacket( 1361 transactionId, secs, clientIp, yourIp, nextIp, relayIp, clientMac, requestedIp, 1362 serverIdentifier); 1363 break; 1364 case DHCP_MESSAGE_TYPE_ACK: 1365 newPacket = new DhcpAckPacket( 1366 transactionId, secs, broadcast, ipSrc, relayIp, clientIp, yourIp, clientMac, 1367 rapidCommit); 1368 break; 1369 case DHCP_MESSAGE_TYPE_NAK: 1370 newPacket = new DhcpNakPacket( 1371 transactionId, secs, relayIp, clientMac, broadcast); 1372 break; 1373 case DHCP_MESSAGE_TYPE_RELEASE: 1374 if (serverIdentifier == null) { 1375 throw new ParseException(DhcpErrorEvent.MISC_ERROR, 1376 "DHCPRELEASE without server identifier"); 1377 } 1378 newPacket = new DhcpReleasePacket( 1379 transactionId, serverIdentifier, clientIp, relayIp, clientMac); 1380 break; 1381 default: 1382 throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE, 1383 "Unimplemented DHCP type %d", dhcpType); 1384 } 1385 1386 newPacket.mBroadcastAddress = bcAddr; 1387 newPacket.mClientId = clientId; 1388 newPacket.mDnsServers = dnsServers; 1389 newPacket.mGateways = gateways; 1390 newPacket.mHostName = hostName; 1391 newPacket.mLeaseTime = leaseTime; 1392 newPacket.mMessage = message; 1393 newPacket.mMtu = mtu; 1394 newPacket.mRequestedIp = requestedIp; 1395 newPacket.mRequestedParams = expectedParams; 1396 newPacket.mServerIdentifier = serverIdentifier; 1397 newPacket.mSubnetMask = netMask; 1398 newPacket.mMaxMessageSize = maxMessageSize; 1399 newPacket.mT1 = T1; 1400 newPacket.mT2 = T2; 1401 newPacket.mVendorId = vendorId; 1402 newPacket.mVendorInfo = vendorInfo; 1403 newPacket.mCaptivePortalUrl = captivePortalUrl; 1404 newPacket.mIpv6OnlyWaitTime = ipv6OnlyWaitTime; 1405 newPacket.mUserClass = userClass; 1406 if ((optionOverload & OPTION_OVERLOAD_SNAME) == 0) { 1407 newPacket.mServerHostName = serverHostName; 1408 } else { 1409 newPacket.mServerHostName = ""; 1410 } 1411 // Domain suffixes in the search list are concatenated to domain name with space separated, 1412 // which will be set to DnsResolver via LinkProperties. 1413 newPacket.mDmnSrchList = dmnSrchList; 1414 newPacket.mDomainName = domainName; 1415 return newPacket; 1416 } 1417 1418 /** 1419 * Parse a packet from an array of bytes, stopping at the given length. 1420 */ decodeFullPacket(byte[] packet, int length, int pktType, byte[] optionsToSkip)1421 public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType, 1422 byte[] optionsToSkip) throws ParseException { 1423 ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN); 1424 try { 1425 return decodeFullPacket(buffer, pktType, optionsToSkip); 1426 } catch (ParseException e) { 1427 throw e; 1428 } catch (Exception e) { 1429 throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage()); 1430 } 1431 } 1432 1433 /** 1434 * Parse a packet from an array of bytes, stopping at the given length. 1435 */ decodeFullPacket(byte[] packet, int length, int pktType)1436 public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType) 1437 throws ParseException { 1438 return decodeFullPacket(packet, length, pktType, new byte[0]); 1439 } 1440 1441 /** 1442 * Construct a DhcpResults object from a DHCP reply packet. 1443 */ toDhcpResults()1444 public DhcpResults toDhcpResults() { 1445 Inet4Address ipAddress = mYourIp; 1446 if (ipAddress.equals(IPV4_ADDR_ANY)) { 1447 ipAddress = mClientIp; 1448 if (ipAddress.equals(IPV4_ADDR_ANY)) { 1449 return null; 1450 } 1451 } 1452 1453 int prefixLength; 1454 if (mSubnetMask != null) { 1455 try { 1456 prefixLength = Inet4AddressUtils.netmaskToPrefixLength(mSubnetMask); 1457 } catch (IllegalArgumentException e) { 1458 // Non-contiguous netmask. 1459 return null; 1460 } 1461 } else { 1462 prefixLength = Inet4AddressUtils.getImplicitNetmask(ipAddress); 1463 } 1464 1465 DhcpResults results = new DhcpResults(); 1466 try { 1467 results.ipAddress = new LinkAddress(ipAddress, prefixLength); 1468 } catch (IllegalArgumentException e) { 1469 return null; 1470 } 1471 1472 if (mGateways.size() > 0) { 1473 results.gateway = mGateways.get(0); 1474 } 1475 1476 results.dnsServers.addAll(mDnsServers); 1477 results.domains = mDomainName; 1478 results.serverAddress = mServerIdentifier; 1479 results.vendorInfo = mVendorInfo; 1480 results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE; 1481 results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0; 1482 results.serverHostName = mServerHostName; 1483 results.captivePortalApiUrl = mCaptivePortalUrl; 1484 // Add the check before setting it 1485 if (mDmnSrchList != null && mDmnSrchList.size() > 0) { 1486 results.dmnsrchList.addAll(mDmnSrchList); 1487 } 1488 return results; 1489 } 1490 1491 /** 1492 * Returns the parsed lease time, in milliseconds, or 0 for infinite. 1493 */ getLeaseTimeMillis(int defaultMinimumLease)1494 public long getLeaseTimeMillis(int defaultMinimumLease) { 1495 // dhcpcd treats the lack of a lease time option as an infinite lease. 1496 if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) { 1497 return 0; 1498 } else if (0 <= mLeaseTime && mLeaseTime < defaultMinimumLease) { 1499 return defaultMinimumLease * 1000L; 1500 } else { 1501 return (mLeaseTime & 0xffffffffL) * 1000; 1502 } 1503 } 1504 1505 /** 1506 * Returns the IPv6-only wait time, in milliseconds, or -1 if the option is not present. 1507 */ getIpv6OnlyWaitTimeMillis()1508 public long getIpv6OnlyWaitTimeMillis() { 1509 if (mIpv6OnlyWaitTime == null) return V6ONLY_PREFERRED_ABSENCE; 1510 return Math.max(MIN_V6ONLY_WAIT_MS, Integer.toUnsignedLong(mIpv6OnlyWaitTime) * 1000); 1511 } 1512 1513 /** 1514 * Builds a DHCP-DISCOVER packet from the required specified parameters. 1515 */ buildDiscoverPacket(int encap, int transactionId, short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, boolean rapidCommit, String hostname, List<DhcpOption> options)1516 public static ByteBuffer buildDiscoverPacket(int encap, int transactionId, 1517 short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, 1518 boolean rapidCommit, String hostname, List<DhcpOption> options) { 1519 DhcpPacket pkt = new DhcpDiscoverPacket(transactionId, secs, INADDR_ANY /* relayIp */, 1520 clientMac, broadcast, INADDR_ANY /* srcIp */, rapidCommit); 1521 pkt.mRequestedParams = expectedParams; 1522 pkt.mHostName = hostname; 1523 pkt.mCustomizedClientOptions = options; 1524 pkt.mVendorId = getVendorId(options); 1525 return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 1526 } 1527 1528 /** 1529 * Builds a DHCP-DISCOVER packet from the required specified parameters. 1530 * 1531 * TODO: remove this method when automerger to mainline-prod is running. 1532 */ buildDiscoverPacket(int encap, int transactionId, short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, boolean rapidCommit, String hostname)1533 public static ByteBuffer buildDiscoverPacket(int encap, int transactionId, 1534 short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams, 1535 boolean rapidCommit, String hostname) { 1536 return buildDiscoverPacket(encap, transactionId, secs, clientMac, broadcast, 1537 expectedParams, rapidCommit, hostname, new ArrayList<DhcpOption>()); 1538 } 1539 1540 /** 1541 * Builds a DHCP-OFFER packet from the required specified parameters. 1542 */ buildOfferPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, short mtu, String captivePortalUrl, Integer ipv6OnlyWaitTime, List<String> domainSearchList)1543 public static ByteBuffer buildOfferPacket(int encap, int transactionId, 1544 boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, 1545 Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, 1546 Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1547 Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, 1548 short mtu, String captivePortalUrl, Integer ipv6OnlyWaitTime, 1549 List<String> domainSearchList) { 1550 DhcpPacket pkt = new DhcpOfferPacket( 1551 transactionId, (short) 0, broadcast, serverIpAddr, relayIp, 1552 INADDR_ANY /* clientIp */, yourIp, mac); 1553 pkt.mGateways = gateways; 1554 pkt.mDnsServers = dnsServers; 1555 pkt.mLeaseTime = timeout; 1556 pkt.mDomainName = domainName; 1557 pkt.mHostName = hostname; 1558 pkt.mServerIdentifier = dhcpServerIdentifier; 1559 pkt.mSubnetMask = netMask; 1560 pkt.mBroadcastAddress = bcAddr; 1561 pkt.mMtu = mtu; 1562 pkt.mCaptivePortalUrl = captivePortalUrl; 1563 if (domainSearchList != null) { 1564 pkt.mDmnSrchList = new ArrayList<>(domainSearchList); 1565 } 1566 if (metered) { 1567 pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED; 1568 } 1569 if (ipv6OnlyWaitTime != null) { 1570 pkt.mIpv6OnlyWaitTime = ipv6OnlyWaitTime; 1571 } 1572 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 1573 } 1574 1575 /** 1576 * Builds a DHCP-OFFER packet from the required specified parameters. 1577 */ buildOfferPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, short mtu, String captivePortalUrl)1578 public static ByteBuffer buildOfferPacket(int encap, int transactionId, 1579 boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, 1580 Inet4Address yourIp, byte[] mac, Integer timeout, Inet4Address netMask, 1581 Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1582 Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, 1583 short mtu, String captivePortalUrl) { 1584 return buildOfferPacket(encap, transactionId, broadcast, serverIpAddr, relayIp, yourIp, 1585 mac, timeout, netMask, bcAddr, gateways, dnsServers, dhcpServerIdentifier, 1586 domainName, hostname, metered, mtu, captivePortalUrl, null /* V6ONLY_WAIT */, 1587 null /* domainSearchList */); 1588 } 1589 1590 /** 1591 * Builds a DHCP-ACK packet from the required specified parameters. 1592 */ buildAckPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, short mtu, boolean rapidCommit, String captivePortalUrl, Integer ipv6OnlyWaitTime, List<String> domainSearchList)1593 public static ByteBuffer buildAckPacket(int encap, int transactionId, 1594 boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, 1595 Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, 1596 Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1597 Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, 1598 short mtu, boolean rapidCommit, String captivePortalUrl, Integer ipv6OnlyWaitTime, 1599 List<String> domainSearchList) { 1600 DhcpPacket pkt = new DhcpAckPacket( 1601 transactionId, (short) 0, broadcast, serverIpAddr, relayIp, requestClientIp, yourIp, 1602 mac, rapidCommit); 1603 pkt.mGateways = gateways; 1604 pkt.mDnsServers = dnsServers; 1605 pkt.mLeaseTime = timeout; 1606 pkt.mDomainName = domainName; 1607 pkt.mHostName = hostname; 1608 pkt.mSubnetMask = netMask; 1609 pkt.mServerIdentifier = dhcpServerIdentifier; 1610 pkt.mBroadcastAddress = bcAddr; 1611 pkt.mMtu = mtu; 1612 pkt.mCaptivePortalUrl = captivePortalUrl; 1613 if (domainSearchList != null) { 1614 pkt.mDmnSrchList = new ArrayList<>(domainSearchList); 1615 } 1616 if (metered) { 1617 pkt.mVendorInfo = VENDOR_INFO_ANDROID_METERED; 1618 } 1619 if (ipv6OnlyWaitTime != null) { 1620 pkt.mIpv6OnlyWaitTime = ipv6OnlyWaitTime; 1621 } 1622 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 1623 } 1624 1625 /** 1626 * Builds a DHCP-ACK packet from the required specified parameters. 1627 */ buildAckPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, short mtu, boolean rapidCommit, String captivePortalUrl)1628 public static ByteBuffer buildAckPacket(int encap, int transactionId, 1629 boolean broadcast, Inet4Address serverIpAddr, Inet4Address relayIp, Inet4Address yourIp, 1630 Inet4Address requestClientIp, byte[] mac, Integer timeout, Inet4Address netMask, 1631 Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1632 Inet4Address dhcpServerIdentifier, String domainName, String hostname, boolean metered, 1633 short mtu, boolean rapidCommit, String captivePortalUrl) { 1634 return buildAckPacket(encap, transactionId, broadcast, serverIpAddr, relayIp, yourIp, 1635 requestClientIp, mac, timeout, netMask, bcAddr, gateways, dnsServers, 1636 dhcpServerIdentifier, domainName, hostname, metered, mtu, rapidCommit, 1637 captivePortalUrl, null /* V6ONLY_WAIT */, null /* domainSearchList */); 1638 } 1639 1640 /** 1641 * Builds a DHCP-NAK packet from the required specified parameters. 1642 */ buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr, Inet4Address relayIp, byte[] mac, boolean broadcast, String message)1643 public static ByteBuffer buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr, 1644 Inet4Address relayIp, byte[] mac, boolean broadcast, String message) { 1645 DhcpPacket pkt = new DhcpNakPacket( 1646 transactionId, (short) 0, relayIp, mac, broadcast); 1647 pkt.mMessage = message; 1648 pkt.mServerIdentifier = serverIpAddr; 1649 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 1650 } 1651 1652 /** 1653 * Builds a DHCP-REQUEST packet from the required specified parameters. 1654 */ buildRequestPacket(int encap, int transactionId, short secs, Inet4Address clientIp, boolean broadcast, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier, byte[] requestedParams, String hostName, List<DhcpOption> options)1655 public static ByteBuffer buildRequestPacket(int encap, 1656 int transactionId, short secs, Inet4Address clientIp, boolean broadcast, 1657 byte[] clientMac, Inet4Address requestedIpAddress, 1658 Inet4Address serverIdentifier, byte[] requestedParams, String hostName, 1659 List<DhcpOption> options) { 1660 DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp, 1661 INADDR_ANY /* relayIp */, clientMac, broadcast); 1662 pkt.mRequestedIp = requestedIpAddress; 1663 pkt.mServerIdentifier = serverIdentifier; 1664 pkt.mHostName = hostName; 1665 pkt.mRequestedParams = requestedParams; 1666 pkt.mCustomizedClientOptions = options; 1667 pkt.mVendorId = getVendorId(options); 1668 ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 1669 return result; 1670 } 1671 1672 /** 1673 * Builds a DHCP-REQUEST packet from the required specified parameters. 1674 * 1675 * TODO: remove this method when automerger to mainline-prod is running. 1676 */ buildRequestPacket(int encap, int transactionId, short secs, Inet4Address clientIp, boolean broadcast, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier, byte[] requestedParams, String hostName)1677 public static ByteBuffer buildRequestPacket(int encap, 1678 int transactionId, short secs, Inet4Address clientIp, boolean broadcast, 1679 byte[] clientMac, Inet4Address requestedIpAddress, 1680 Inet4Address serverIdentifier, byte[] requestedParams, String hostName) { 1681 return buildRequestPacket(encap, transactionId, secs, clientIp, broadcast, clientMac, 1682 requestedIpAddress, serverIdentifier, requestedParams, hostName, 1683 new ArrayList<DhcpOption>()); 1684 } 1685 1686 /** 1687 * Builds a DHCP-DECLINE packet from the required specified parameters. 1688 */ buildDeclinePacket(int encap, int transactionId, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier)1689 public static ByteBuffer buildDeclinePacket(int encap, int transactionId, byte[] clientMac, 1690 Inet4Address requestedIpAddress, Inet4Address serverIdentifier) { 1691 DhcpPacket pkt = new DhcpDeclinePacket(transactionId, (short) 0 /* secs */, 1692 INADDR_ANY /* clientIp */, INADDR_ANY /* yourIp */, INADDR_ANY /* nextIp */, 1693 INADDR_ANY /* relayIp */, clientMac, requestedIpAddress, serverIdentifier); 1694 ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 1695 return result; 1696 } 1697 } 1698