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