1 package android.net.dhcp; 2 3 import android.net.DhcpResults; 4 import android.net.LinkAddress; 5 import android.net.NetworkUtils; 6 import android.net.metrics.DhcpErrorEvent; 7 import android.os.Build; 8 import android.os.SystemProperties; 9 import android.system.OsConstants; 10 import com.android.internal.annotations.VisibleForTesting; 11 12 import java.io.UnsupportedEncodingException; 13 import java.net.Inet4Address; 14 import java.net.UnknownHostException; 15 import java.nio.BufferUnderflowException; 16 import java.nio.ByteBuffer; 17 import java.nio.ByteOrder; 18 import java.nio.ShortBuffer; 19 import java.nio.charset.StandardCharsets; 20 import java.util.ArrayList; 21 import java.util.Arrays; 22 import java.util.List; 23 24 /** 25 * Defines basic data and operations needed to build and use packets for the 26 * DHCP protocol. Subclasses create the specific packets used at each 27 * stage of the negotiation. 28 * 29 * @hide 30 */ 31 public abstract class DhcpPacket { 32 protected static final String TAG = "DhcpPacket"; 33 34 // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the 35 // CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the 36 // DHCP client timeout. 37 public static final int MINIMUM_LEASE = 60; 38 public static final int INFINITE_LEASE = (int) 0xffffffff; 39 40 public static final Inet4Address INADDR_ANY = (Inet4Address) Inet4Address.ANY; 41 public static final Inet4Address INADDR_BROADCAST = (Inet4Address) Inet4Address.ALL; 42 public static final byte[] ETHER_BROADCAST = new byte[] { 43 (byte) 0xff, (byte) 0xff, (byte) 0xff, 44 (byte) 0xff, (byte) 0xff, (byte) 0xff, 45 }; 46 47 /** 48 * Packet encapsulations. 49 */ 50 public static final int ENCAP_L2 = 0; // EthernetII header included 51 public static final int ENCAP_L3 = 1; // IP/UDP header included 52 public static final int ENCAP_BOOTP = 2; // BOOTP contents only 53 54 /** 55 * Minimum length of a DHCP packet, excluding options, in the above encapsulations. 56 */ 57 public static final int MIN_PACKET_LENGTH_BOOTP = 236; // See diagram in RFC 2131, section 2. 58 public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8; 59 public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14; 60 61 public static final int HWADDR_LEN = 16; 62 public static final int MAX_OPTION_LEN = 255; 63 64 /** 65 * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum 66 * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280, 67 * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500 68 * because in general it is risky to assume that the hardware is able to send/receive packets 69 * larger than 1500 bytes even if the network supports it. 70 */ 71 private static final int MIN_MTU = 1280; 72 private static final int MAX_MTU = 1500; 73 74 /** 75 * IP layer definitions. 76 */ 77 private static final byte IP_TYPE_UDP = (byte) 0x11; 78 79 /** 80 * IP: Version 4, Header Length 20 bytes 81 */ 82 private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45; 83 84 /** 85 * IP: Flags 0, Fragment Offset 0, Don't Fragment 86 */ 87 private static final short IP_FLAGS_OFFSET = (short) 0x4000; 88 89 /** 90 * IP: TOS 91 */ 92 private static final byte IP_TOS_LOWDELAY = (byte) 0x10; 93 94 /** 95 * IP: TTL -- use default 64 from RFC1340 96 */ 97 private static final byte IP_TTL = (byte) 0x40; 98 99 /** 100 * The client DHCP port. 101 */ 102 static final short DHCP_CLIENT = (short) 68; 103 104 /** 105 * The server DHCP port. 106 */ 107 static final short DHCP_SERVER = (short) 67; 108 109 /** 110 * The message op code indicating a request from a client. 111 */ 112 protected static final byte DHCP_BOOTREQUEST = (byte) 1; 113 114 /** 115 * The message op code indicating a response from the server. 116 */ 117 protected static final byte DHCP_BOOTREPLY = (byte) 2; 118 119 /** 120 * The code type used to identify an Ethernet MAC address in the 121 * Client-ID field. 122 */ 123 protected static final byte CLIENT_ID_ETHER = (byte) 1; 124 125 /** 126 * The maximum length of a packet that can be constructed. 127 */ 128 protected static final int MAX_LENGTH = 1500; 129 130 /** 131 * The magic cookie that identifies this as a DHCP packet instead of BOOTP. 132 */ 133 private static final int DHCP_MAGIC_COOKIE = 0x63825363; 134 135 /** 136 * DHCP Optional Type: DHCP Subnet Mask 137 */ 138 protected static final byte DHCP_SUBNET_MASK = 1; 139 protected Inet4Address mSubnetMask; 140 141 /** 142 * DHCP Optional Type: DHCP Router 143 */ 144 protected static final byte DHCP_ROUTER = 3; 145 protected List <Inet4Address> mGateways; 146 147 /** 148 * DHCP Optional Type: DHCP DNS Server 149 */ 150 protected static final byte DHCP_DNS_SERVER = 6; 151 protected List<Inet4Address> mDnsServers; 152 153 /** 154 * DHCP Optional Type: DHCP Host Name 155 */ 156 protected static final byte DHCP_HOST_NAME = 12; 157 protected String mHostName; 158 159 /** 160 * DHCP Optional Type: DHCP DOMAIN NAME 161 */ 162 protected static final byte DHCP_DOMAIN_NAME = 15; 163 protected String mDomainName; 164 165 /** 166 * DHCP Optional Type: DHCP Interface MTU 167 */ 168 protected static final byte DHCP_MTU = 26; 169 protected Short mMtu; 170 171 /** 172 * DHCP Optional Type: DHCP BROADCAST ADDRESS 173 */ 174 protected static final byte DHCP_BROADCAST_ADDRESS = 28; 175 protected Inet4Address mBroadcastAddress; 176 177 /** 178 * DHCP Optional Type: Vendor specific information 179 */ 180 protected static final byte DHCP_VENDOR_INFO = 43; 181 protected String mVendorInfo; 182 183 /** 184 * DHCP Optional Type: DHCP Requested IP Address 185 */ 186 protected static final byte DHCP_REQUESTED_IP = 50; 187 protected Inet4Address mRequestedIp; 188 189 /** 190 * DHCP Optional Type: DHCP Lease Time 191 */ 192 protected static final byte DHCP_LEASE_TIME = 51; 193 protected Integer mLeaseTime; 194 195 /** 196 * DHCP Optional Type: DHCP Message Type 197 */ 198 protected static final byte DHCP_MESSAGE_TYPE = 53; 199 // the actual type values 200 protected static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1; 201 protected static final byte DHCP_MESSAGE_TYPE_OFFER = 2; 202 protected static final byte DHCP_MESSAGE_TYPE_REQUEST = 3; 203 protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4; 204 protected static final byte DHCP_MESSAGE_TYPE_ACK = 5; 205 protected static final byte DHCP_MESSAGE_TYPE_NAK = 6; 206 protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8; 207 208 /** 209 * DHCP Optional Type: DHCP Server Identifier 210 */ 211 protected static final byte DHCP_SERVER_IDENTIFIER = 54; 212 protected Inet4Address mServerIdentifier; 213 214 /** 215 * DHCP Optional Type: DHCP Parameter List 216 */ 217 protected static final byte DHCP_PARAMETER_LIST = 55; 218 protected byte[] mRequestedParams; 219 220 /** 221 * DHCP Optional Type: DHCP MESSAGE 222 */ 223 protected static final byte DHCP_MESSAGE = 56; 224 protected String mMessage; 225 226 /** 227 * DHCP Optional Type: Maximum DHCP Message Size 228 */ 229 protected static final byte DHCP_MAX_MESSAGE_SIZE = 57; 230 protected Short mMaxMessageSize; 231 232 /** 233 * DHCP Optional Type: DHCP Renewal Time Value 234 */ 235 protected static final byte DHCP_RENEWAL_TIME = 58; 236 protected Integer mT1; 237 238 /** 239 * DHCP Optional Type: Rebinding Time Value 240 */ 241 protected static final byte DHCP_REBINDING_TIME = 59; 242 protected Integer mT2; 243 244 /** 245 * DHCP Optional Type: Vendor Class Identifier 246 */ 247 protected static final byte DHCP_VENDOR_CLASS_ID = 60; 248 protected String mVendorId; 249 250 /** 251 * DHCP Optional Type: DHCP Client Identifier 252 */ 253 protected static final byte DHCP_CLIENT_IDENTIFIER = 61; 254 255 /** 256 * DHCP zero-length option code: pad 257 */ 258 protected static final byte DHCP_OPTION_PAD = 0x00; 259 260 /** 261 * DHCP zero-length option code: end of options 262 */ 263 protected static final byte DHCP_OPTION_END = (byte) 0xff; 264 265 /** 266 * The transaction identifier used in this particular DHCP negotiation 267 */ 268 protected final int mTransId; 269 270 /** 271 * The seconds field in the BOOTP header. Per RFC, should be nonzero in client requests only. 272 */ 273 protected final short mSecs; 274 275 /** 276 * The IP address of the client host. This address is typically 277 * proposed by the client (from an earlier DHCP negotiation) or 278 * supplied by the server. 279 */ 280 protected final Inet4Address mClientIp; 281 protected final Inet4Address mYourIp; 282 private final Inet4Address mNextIp; 283 private final Inet4Address mRelayIp; 284 285 /** 286 * Does the client request a broadcast response? 287 */ 288 protected boolean mBroadcast; 289 290 /** 291 * The six-octet MAC of the client. 292 */ 293 protected final byte[] mClientMac; 294 295 /** 296 * Asks the packet object to create a ByteBuffer serialization of 297 * the packet for transmission. 298 */ buildPacket(int encap, short destUdp, short srcUdp)299 public abstract ByteBuffer buildPacket(int encap, short destUdp, 300 short srcUdp); 301 302 /** 303 * Allows the concrete class to fill in packet-type-specific details, 304 * typically optional parameters at the end of the packet. 305 */ finishPacket(ByteBuffer buffer)306 abstract void finishPacket(ByteBuffer buffer); 307 308 // Set in unit tests, to ensure that the test does not break when run on different devices and 309 // on different releases. 310 static String testOverrideVendorId = null; 311 static String testOverrideHostname = null; 312 DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp, Inet4Address nextIp, Inet4Address relayIp, byte[] clientMac, boolean broadcast)313 protected DhcpPacket(int transId, short secs, Inet4Address clientIp, Inet4Address yourIp, 314 Inet4Address nextIp, Inet4Address relayIp, 315 byte[] clientMac, boolean broadcast) { 316 mTransId = transId; 317 mSecs = secs; 318 mClientIp = clientIp; 319 mYourIp = yourIp; 320 mNextIp = nextIp; 321 mRelayIp = relayIp; 322 mClientMac = clientMac; 323 mBroadcast = broadcast; 324 } 325 326 /** 327 * Returns the transaction ID. 328 */ getTransactionId()329 public int getTransactionId() { 330 return mTransId; 331 } 332 333 /** 334 * Returns the client MAC. 335 */ getClientMac()336 public byte[] getClientMac() { 337 return mClientMac; 338 } 339 340 /** 341 * Returns the client ID. This follows RFC 2132 and is based on the hardware address. 342 */ getClientId()343 public byte[] getClientId() { 344 byte[] clientId = new byte[mClientMac.length + 1]; 345 clientId[0] = CLIENT_ID_ETHER; 346 System.arraycopy(mClientMac, 0, clientId, 1, mClientMac.length); 347 return clientId; 348 } 349 350 /** 351 * Creates a new L3 packet (including IP header) containing the 352 * DHCP udp packet. This method relies upon the delegated method 353 * finishPacket() to insert the per-packet contents. 354 */ fillInPacket(int encap, Inet4Address destIp, Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf, byte requestCode, boolean broadcast)355 protected void fillInPacket(int encap, Inet4Address destIp, 356 Inet4Address srcIp, short destUdp, short srcUdp, ByteBuffer buf, 357 byte requestCode, boolean broadcast) { 358 byte[] destIpArray = destIp.getAddress(); 359 byte[] srcIpArray = srcIp.getAddress(); 360 int ipHeaderOffset = 0; 361 int ipLengthOffset = 0; 362 int ipChecksumOffset = 0; 363 int endIpHeader = 0; 364 int udpHeaderOffset = 0; 365 int udpLengthOffset = 0; 366 int udpChecksumOffset = 0; 367 368 buf.clear(); 369 buf.order(ByteOrder.BIG_ENDIAN); 370 371 if (encap == ENCAP_L2) { 372 buf.put(ETHER_BROADCAST); 373 buf.put(mClientMac); 374 buf.putShort((short) OsConstants.ETH_P_IP); 375 } 376 377 // if a full IP packet needs to be generated, put the IP & UDP 378 // headers in place, and pre-populate with artificial values 379 // needed to seed the IP checksum. 380 if (encap <= ENCAP_L3) { 381 ipHeaderOffset = buf.position(); 382 buf.put(IP_VERSION_HEADER_LEN); 383 buf.put(IP_TOS_LOWDELAY); // tos: IPTOS_LOWDELAY 384 ipLengthOffset = buf.position(); 385 buf.putShort((short)0); // length 386 buf.putShort((short)0); // id 387 buf.putShort(IP_FLAGS_OFFSET); // ip offset: don't fragment 388 buf.put(IP_TTL); // TTL: use default 64 from RFC1340 389 buf.put(IP_TYPE_UDP); 390 ipChecksumOffset = buf.position(); 391 buf.putShort((short) 0); // checksum 392 393 buf.put(srcIpArray); 394 buf.put(destIpArray); 395 endIpHeader = buf.position(); 396 397 // UDP header 398 udpHeaderOffset = buf.position(); 399 buf.putShort(srcUdp); 400 buf.putShort(destUdp); 401 udpLengthOffset = buf.position(); 402 buf.putShort((short) 0); // length 403 udpChecksumOffset = buf.position(); 404 buf.putShort((short) 0); // UDP checksum -- initially zero 405 } 406 407 // DHCP payload 408 buf.put(requestCode); 409 buf.put((byte) 1); // Hardware Type: Ethernet 410 buf.put((byte) mClientMac.length); // Hardware Address Length 411 buf.put((byte) 0); // Hop Count 412 buf.putInt(mTransId); // Transaction ID 413 buf.putShort(mSecs); // Elapsed Seconds 414 415 if (broadcast) { 416 buf.putShort((short) 0x8000); // Flags 417 } else { 418 buf.putShort((short) 0x0000); // Flags 419 } 420 421 buf.put(mClientIp.getAddress()); 422 buf.put(mYourIp.getAddress()); 423 buf.put(mNextIp.getAddress()); 424 buf.put(mRelayIp.getAddress()); 425 buf.put(mClientMac); 426 buf.position(buf.position() + 427 (HWADDR_LEN - mClientMac.length) // pad addr to 16 bytes 428 + 64 // empty server host name (64 bytes) 429 + 128); // empty boot file name (128 bytes) 430 buf.putInt(DHCP_MAGIC_COOKIE); // magic number 431 finishPacket(buf); 432 433 // round up to an even number of octets 434 if ((buf.position() & 1) == 1) { 435 buf.put((byte) 0); 436 } 437 438 // If an IP packet is being built, the IP & UDP checksums must be 439 // computed. 440 if (encap <= ENCAP_L3) { 441 // fix UDP header: insert length 442 short udpLen = (short)(buf.position() - udpHeaderOffset); 443 buf.putShort(udpLengthOffset, udpLen); 444 // fix UDP header: checksum 445 // checksum for UDP at udpChecksumOffset 446 int udpSeed = 0; 447 448 // apply IPv4 pseudo-header. Read IP address src and destination 449 // values from the IP header and accumulate checksum. 450 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 2)); 451 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 4)); 452 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 6)); 453 udpSeed += intAbs(buf.getShort(ipChecksumOffset + 8)); 454 455 // accumulate extra data for the pseudo-header 456 udpSeed += IP_TYPE_UDP; 457 udpSeed += udpLen; 458 // and compute UDP checksum 459 buf.putShort(udpChecksumOffset, (short) checksum(buf, udpSeed, 460 udpHeaderOffset, 461 buf.position())); 462 // fix IP header: insert length 463 buf.putShort(ipLengthOffset, (short)(buf.position() - ipHeaderOffset)); 464 // fixup IP-header checksum 465 buf.putShort(ipChecksumOffset, 466 (short) checksum(buf, 0, ipHeaderOffset, endIpHeader)); 467 } 468 } 469 470 /** 471 * Converts a signed short value to an unsigned int value. Needed 472 * because Java does not have unsigned types. 473 */ intAbs(short v)474 private static int intAbs(short v) { 475 return v & 0xFFFF; 476 } 477 478 /** 479 * Performs an IP checksum (used in IP header and across UDP 480 * payload) on the specified portion of a ByteBuffer. The seed 481 * allows the checksum to commence with a specified value. 482 */ checksum(ByteBuffer buf, int seed, int start, int end)483 private int checksum(ByteBuffer buf, int seed, int start, int end) { 484 int sum = seed; 485 int bufPosition = buf.position(); 486 487 // set position of original ByteBuffer, so that the ShortBuffer 488 // will be correctly initialized 489 buf.position(start); 490 ShortBuffer shortBuf = buf.asShortBuffer(); 491 492 // re-set ByteBuffer position 493 buf.position(bufPosition); 494 495 short[] shortArray = new short[(end - start) / 2]; 496 shortBuf.get(shortArray); 497 498 for (short s : shortArray) { 499 sum += intAbs(s); 500 } 501 502 start += shortArray.length * 2; 503 504 // see if a singleton byte remains 505 if (end != start) { 506 short b = buf.get(start); 507 508 // make it unsigned 509 if (b < 0) { 510 b += 256; 511 } 512 513 sum += b * 256; 514 } 515 516 sum = ((sum >> 16) & 0xFFFF) + (sum & 0xFFFF); 517 sum = ((sum + ((sum >> 16) & 0xFFFF)) & 0xFFFF); 518 int negated = ~sum; 519 return intAbs((short) negated); 520 } 521 522 /** 523 * Adds an optional parameter containing a single byte value. 524 */ addTlv(ByteBuffer buf, byte type, byte value)525 protected static void addTlv(ByteBuffer buf, byte type, byte value) { 526 buf.put(type); 527 buf.put((byte) 1); 528 buf.put(value); 529 } 530 531 /** 532 * Adds an optional parameter containing an array of bytes. 533 */ addTlv(ByteBuffer buf, byte type, byte[] payload)534 protected static void addTlv(ByteBuffer buf, byte type, byte[] payload) { 535 if (payload != null) { 536 if (payload.length > MAX_OPTION_LEN) { 537 throw new IllegalArgumentException("DHCP option too long: " 538 + payload.length + " vs. " + MAX_OPTION_LEN); 539 } 540 buf.put(type); 541 buf.put((byte) payload.length); 542 buf.put(payload); 543 } 544 } 545 546 /** 547 * Adds an optional parameter containing an IP address. 548 */ addTlv(ByteBuffer buf, byte type, Inet4Address addr)549 protected static void addTlv(ByteBuffer buf, byte type, Inet4Address addr) { 550 if (addr != null) { 551 addTlv(buf, type, addr.getAddress()); 552 } 553 } 554 555 /** 556 * Adds an optional parameter containing a list of IP addresses. 557 */ addTlv(ByteBuffer buf, byte type, List<Inet4Address> addrs)558 protected static void addTlv(ByteBuffer buf, byte type, List<Inet4Address> addrs) { 559 if (addrs == null || addrs.size() == 0) return; 560 561 int optionLen = 4 * addrs.size(); 562 if (optionLen > MAX_OPTION_LEN) { 563 throw new IllegalArgumentException("DHCP option too long: " 564 + optionLen + " vs. " + MAX_OPTION_LEN); 565 } 566 567 buf.put(type); 568 buf.put((byte)(optionLen)); 569 570 for (Inet4Address addr : addrs) { 571 buf.put(addr.getAddress()); 572 } 573 } 574 575 /** 576 * Adds an optional parameter containing a short integer 577 */ addTlv(ByteBuffer buf, byte type, Short value)578 protected static void addTlv(ByteBuffer buf, byte type, Short value) { 579 if (value != null) { 580 buf.put(type); 581 buf.put((byte) 2); 582 buf.putShort(value.shortValue()); 583 } 584 } 585 586 /** 587 * Adds an optional parameter containing a simple integer 588 */ addTlv(ByteBuffer buf, byte type, Integer value)589 protected static void addTlv(ByteBuffer buf, byte type, Integer value) { 590 if (value != null) { 591 buf.put(type); 592 buf.put((byte) 4); 593 buf.putInt(value.intValue()); 594 } 595 } 596 597 /** 598 * Adds an optional parameter containing an ASCII string. 599 */ addTlv(ByteBuffer buf, byte type, String str)600 protected static void addTlv(ByteBuffer buf, byte type, String str) { 601 try { 602 addTlv(buf, type, str.getBytes("US-ASCII")); 603 } catch (UnsupportedEncodingException e) { 604 throw new IllegalArgumentException("String is not US-ASCII: " + str); 605 } 606 } 607 608 /** 609 * Adds the special end-of-optional-parameters indicator. 610 */ addTlvEnd(ByteBuffer buf)611 protected static void addTlvEnd(ByteBuffer buf) { 612 buf.put((byte) 0xFF); 613 } 614 getVendorId()615 private String getVendorId() { 616 if (testOverrideVendorId != null) return testOverrideVendorId; 617 return "android-dhcp-" + Build.VERSION.RELEASE; 618 } 619 getHostname()620 private String getHostname() { 621 if (testOverrideHostname != null) return testOverrideHostname; 622 return SystemProperties.get("net.hostname"); 623 } 624 625 /** 626 * Adds common client TLVs. 627 * 628 * TODO: Does this belong here? The alternative would be to modify all the buildXyzPacket 629 * methods to take them. 630 */ addCommonClientTlvs(ByteBuffer buf)631 protected void addCommonClientTlvs(ByteBuffer buf) { 632 addTlv(buf, DHCP_MAX_MESSAGE_SIZE, (short) MAX_LENGTH); 633 addTlv(buf, DHCP_VENDOR_CLASS_ID, getVendorId()); 634 addTlv(buf, DHCP_HOST_NAME, getHostname()); 635 } 636 637 /** 638 * Converts a MAC from an array of octets to an ASCII string. 639 */ macToString(byte[] mac)640 public static String macToString(byte[] mac) { 641 String macAddr = ""; 642 643 for (int i = 0; i < mac.length; i++) { 644 String hexString = "0" + Integer.toHexString(mac[i]); 645 646 // substring operation grabs the last 2 digits: this 647 // allows signed bytes to be converted correctly. 648 macAddr += hexString.substring(hexString.length() - 2); 649 650 if (i != (mac.length - 1)) { 651 macAddr += ":"; 652 } 653 } 654 655 return macAddr; 656 } 657 toString()658 public String toString() { 659 String macAddr = macToString(mClientMac); 660 661 return macAddr; 662 } 663 664 /** 665 * Reads a four-octet value from a ByteBuffer and construct 666 * an IPv4 address from that value. 667 */ readIpAddress(ByteBuffer packet)668 private static Inet4Address readIpAddress(ByteBuffer packet) { 669 Inet4Address result = null; 670 byte[] ipAddr = new byte[4]; 671 packet.get(ipAddr); 672 673 try { 674 result = (Inet4Address) Inet4Address.getByAddress(ipAddr); 675 } catch (UnknownHostException ex) { 676 // ipAddr is numeric, so this should not be 677 // triggered. However, if it is, just nullify 678 result = null; 679 } 680 681 return result; 682 } 683 684 /** 685 * Reads a string of specified length from the buffer. 686 */ readAsciiString(ByteBuffer buf, int byteCount, boolean nullOk)687 private static String readAsciiString(ByteBuffer buf, int byteCount, boolean nullOk) { 688 byte[] bytes = new byte[byteCount]; 689 buf.get(bytes); 690 int length = bytes.length; 691 if (!nullOk) { 692 // Stop at the first null byte. This is because some DHCP options (e.g., the domain 693 // name) are passed to netd via FrameworkListener, which refuses arguments containing 694 // null bytes. We don't do this by default because vendorInfo is an opaque string which 695 // could in theory contain null bytes. 696 for (length = 0; length < bytes.length; length++) { 697 if (bytes[length] == 0) { 698 break; 699 } 700 } 701 } 702 return new String(bytes, 0, length, StandardCharsets.US_ASCII); 703 } 704 isPacketToOrFromClient(short udpSrcPort, short udpDstPort)705 private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) { 706 return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT); 707 } 708 isPacketServerToServer(short udpSrcPort, short udpDstPort)709 private static boolean isPacketServerToServer(short udpSrcPort, short udpDstPort) { 710 return (udpSrcPort == DHCP_SERVER) && (udpDstPort == DHCP_SERVER); 711 } 712 713 public static class ParseException extends Exception { 714 public final int errorCode; ParseException(int errorCode, String msg, Object... args)715 public ParseException(int errorCode, String msg, Object... args) { 716 super(String.format(msg, args)); 717 this.errorCode = errorCode; 718 } 719 } 720 721 /** 722 * Creates a concrete DhcpPacket from the supplied ByteBuffer. The 723 * buffer may have an L2 encapsulation (which is the full EthernetII 724 * format starting with the source-address MAC) or an L3 encapsulation 725 * (which starts with the IP header). 726 * <br> 727 * A subset of the optional parameters are parsed and are stored 728 * in object fields. 729 */ 730 @VisibleForTesting decodeFullPacket(ByteBuffer packet, int pktType)731 static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException 732 { 733 // bootp parameters 734 int transactionId; 735 short secs; 736 Inet4Address clientIp; 737 Inet4Address yourIp; 738 Inet4Address nextIp; 739 Inet4Address relayIp; 740 byte[] clientMac; 741 List<Inet4Address> dnsServers = new ArrayList<>(); 742 List<Inet4Address> gateways = new ArrayList<>(); // aka router 743 Inet4Address serverIdentifier = null; 744 Inet4Address netMask = null; 745 String message = null; 746 String vendorId = null; 747 String vendorInfo = null; 748 byte[] expectedParams = null; 749 String hostName = null; 750 String domainName = null; 751 Inet4Address ipSrc = null; 752 Inet4Address ipDst = null; 753 Inet4Address bcAddr = null; 754 Inet4Address requestedIp = null; 755 756 // The following are all unsigned integers. Internally we store them as signed integers of 757 // the same length because that way we're guaranteed that they can't be out of the range of 758 // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need 759 // to cast it. 760 Short mtu = null; 761 Short maxMessageSize = null; 762 Integer leaseTime = null; 763 Integer T1 = null; 764 Integer T2 = null; 765 766 // dhcp options 767 byte dhcpType = (byte) 0xFF; 768 769 packet.order(ByteOrder.BIG_ENDIAN); 770 771 // check to see if we need to parse L2, IP, and UDP encaps 772 if (pktType == ENCAP_L2) { 773 if (packet.remaining() < MIN_PACKET_LENGTH_L2) { 774 throw new ParseException(DhcpErrorEvent.L2_TOO_SHORT, 775 "L2 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L2); 776 } 777 778 byte[] l2dst = new byte[6]; 779 byte[] l2src = new byte[6]; 780 781 packet.get(l2dst); 782 packet.get(l2src); 783 784 short l2type = packet.getShort(); 785 786 if (l2type != OsConstants.ETH_P_IP) { 787 throw new ParseException(DhcpErrorEvent.L2_WRONG_ETH_TYPE, 788 "Unexpected L2 type 0x%04x, expected 0x%04x", l2type, OsConstants.ETH_P_IP); 789 } 790 } 791 792 if (pktType <= ENCAP_L3) { 793 if (packet.remaining() < MIN_PACKET_LENGTH_L3) { 794 throw new ParseException(DhcpErrorEvent.L3_TOO_SHORT, 795 "L3 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L3); 796 } 797 798 byte ipTypeAndLength = packet.get(); 799 int ipVersion = (ipTypeAndLength & 0xf0) >> 4; 800 if (ipVersion != 4) { 801 throw new ParseException( 802 DhcpErrorEvent.L3_NOT_IPV4, "Invalid IP version %d", ipVersion); 803 } 804 805 // System.out.println("ipType is " + ipType); 806 byte ipDiffServicesField = packet.get(); 807 short ipTotalLength = packet.getShort(); 808 short ipIdentification = packet.getShort(); 809 byte ipFlags = packet.get(); 810 byte ipFragOffset = packet.get(); 811 byte ipTTL = packet.get(); 812 byte ipProto = packet.get(); 813 short ipChksm = packet.getShort(); 814 815 ipSrc = readIpAddress(packet); 816 ipDst = readIpAddress(packet); 817 818 if (ipProto != IP_TYPE_UDP) { 819 throw new ParseException( 820 DhcpErrorEvent.L4_NOT_UDP, "Protocol not UDP: %d", ipProto); 821 } 822 823 // Skip options. This cannot cause us to read beyond the end of the buffer because the 824 // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than 825 // MIN_PACKET_LENGTH_L3. 826 int optionWords = ((ipTypeAndLength & 0x0f) - 5); 827 for (int i = 0; i < optionWords; i++) { 828 packet.getInt(); 829 } 830 831 // assume UDP 832 short udpSrcPort = packet.getShort(); 833 short udpDstPort = packet.getShort(); 834 short udpLen = packet.getShort(); 835 short udpChkSum = packet.getShort(); 836 837 // Only accept packets to or from the well-known client port (expressly permitting 838 // packets from ports other than the well-known server port; http://b/24687559), and 839 // server-to-server packets, e.g. for relays. 840 if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) && 841 !isPacketServerToServer(udpSrcPort, udpDstPort)) { 842 // This should almost never happen because we use SO_ATTACH_FILTER on the packet 843 // socket to drop packets that don't have the right source ports. However, it's 844 // possible that a packet arrives between when the socket is bound and when the 845 // filter is set. http://b/26696823 . 846 throw new ParseException(DhcpErrorEvent.L4_WRONG_PORT, 847 "Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort); 848 } 849 } 850 851 // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length. 852 if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) { 853 throw new ParseException(DhcpErrorEvent.BOOTP_TOO_SHORT, 854 "Invalid type or BOOTP packet too short, %d < %d", 855 packet.remaining(), MIN_PACKET_LENGTH_BOOTP); 856 } 857 858 byte type = packet.get(); 859 byte hwType = packet.get(); 860 int addrLen = packet.get() & 0xff; 861 byte hops = packet.get(); 862 transactionId = packet.getInt(); 863 secs = packet.getShort(); 864 short bootpFlags = packet.getShort(); 865 boolean broadcast = (bootpFlags & 0x8000) != 0; 866 byte[] ipv4addr = new byte[4]; 867 868 try { 869 packet.get(ipv4addr); 870 clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr); 871 packet.get(ipv4addr); 872 yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr); 873 packet.get(ipv4addr); 874 nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr); 875 packet.get(ipv4addr); 876 relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr); 877 } catch (UnknownHostException ex) { 878 throw new ParseException(DhcpErrorEvent.L3_INVALID_IP, 879 "Invalid IPv4 address: %s", Arrays.toString(ipv4addr)); 880 } 881 882 // Some DHCP servers have been known to announce invalid client hardware address values such 883 // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at 884 // all but only checks that the interface MAC address matches the first bytes of the address 885 // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger 886 // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795 887 // TODO: evaluate whether to make this test more liberal. 888 if (addrLen > HWADDR_LEN) { 889 addrLen = ETHER_BROADCAST.length; 890 } 891 892 clientMac = new byte[addrLen]; 893 packet.get(clientMac); 894 895 // skip over address padding (16 octets allocated) 896 packet.position(packet.position() + (16 - addrLen) 897 + 64 // skip server host name (64 chars) 898 + 128); // skip boot file name (128 chars) 899 900 // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211 901 if (packet.remaining() < 4) { 902 throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message"); 903 } 904 905 int dhcpMagicCookie = packet.getInt(); 906 if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) { 907 throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE, 908 "Bad magic cookie 0x%08x, should be 0x%08x", 909 dhcpMagicCookie, DHCP_MAGIC_COOKIE); 910 } 911 912 // parse options 913 boolean notFinishedOptions = true; 914 915 while ((packet.position() < packet.limit()) && notFinishedOptions) { 916 final byte optionType = packet.get(); // cannot underflow because position < limit 917 try { 918 if (optionType == DHCP_OPTION_END) { 919 notFinishedOptions = false; 920 } else if (optionType == DHCP_OPTION_PAD) { 921 // The pad option doesn't have a length field. Nothing to do. 922 } else { 923 int optionLen = packet.get() & 0xFF; 924 int expectedLen = 0; 925 926 switch(optionType) { 927 case DHCP_SUBNET_MASK: 928 netMask = readIpAddress(packet); 929 expectedLen = 4; 930 break; 931 case DHCP_ROUTER: 932 for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) { 933 gateways.add(readIpAddress(packet)); 934 } 935 break; 936 case DHCP_DNS_SERVER: 937 for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) { 938 dnsServers.add(readIpAddress(packet)); 939 } 940 break; 941 case DHCP_HOST_NAME: 942 expectedLen = optionLen; 943 hostName = readAsciiString(packet, optionLen, false); 944 break; 945 case DHCP_MTU: 946 expectedLen = 2; 947 mtu = packet.getShort(); 948 break; 949 case DHCP_DOMAIN_NAME: 950 expectedLen = optionLen; 951 domainName = readAsciiString(packet, optionLen, false); 952 break; 953 case DHCP_BROADCAST_ADDRESS: 954 bcAddr = readIpAddress(packet); 955 expectedLen = 4; 956 break; 957 case DHCP_REQUESTED_IP: 958 requestedIp = readIpAddress(packet); 959 expectedLen = 4; 960 break; 961 case DHCP_LEASE_TIME: 962 leaseTime = Integer.valueOf(packet.getInt()); 963 expectedLen = 4; 964 break; 965 case DHCP_MESSAGE_TYPE: 966 dhcpType = packet.get(); 967 expectedLen = 1; 968 break; 969 case DHCP_SERVER_IDENTIFIER: 970 serverIdentifier = readIpAddress(packet); 971 expectedLen = 4; 972 break; 973 case DHCP_PARAMETER_LIST: 974 expectedParams = new byte[optionLen]; 975 packet.get(expectedParams); 976 expectedLen = optionLen; 977 break; 978 case DHCP_MESSAGE: 979 expectedLen = optionLen; 980 message = readAsciiString(packet, optionLen, false); 981 break; 982 case DHCP_MAX_MESSAGE_SIZE: 983 expectedLen = 2; 984 maxMessageSize = Short.valueOf(packet.getShort()); 985 break; 986 case DHCP_RENEWAL_TIME: 987 expectedLen = 4; 988 T1 = Integer.valueOf(packet.getInt()); 989 break; 990 case DHCP_REBINDING_TIME: 991 expectedLen = 4; 992 T2 = Integer.valueOf(packet.getInt()); 993 break; 994 case DHCP_VENDOR_CLASS_ID: 995 expectedLen = optionLen; 996 // Embedded nulls are safe as this does not get passed to netd. 997 vendorId = readAsciiString(packet, optionLen, true); 998 break; 999 case DHCP_CLIENT_IDENTIFIER: { // Client identifier 1000 byte[] id = new byte[optionLen]; 1001 packet.get(id); 1002 expectedLen = optionLen; 1003 } break; 1004 case DHCP_VENDOR_INFO: 1005 expectedLen = optionLen; 1006 // Embedded nulls are safe as this does not get passed to netd. 1007 vendorInfo = readAsciiString(packet, optionLen, true); 1008 break; 1009 default: 1010 // ignore any other parameters 1011 for (int i = 0; i < optionLen; i++) { 1012 expectedLen++; 1013 byte throwaway = packet.get(); 1014 } 1015 } 1016 1017 if (expectedLen != optionLen) { 1018 final int errorCode = DhcpErrorEvent.errorCodeWithOption( 1019 DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType); 1020 throw new ParseException(errorCode, 1021 "Invalid length %d for option %d, expected %d", 1022 optionLen, optionType, expectedLen); 1023 } 1024 } 1025 } catch (BufferUnderflowException e) { 1026 final int errorCode = DhcpErrorEvent.errorCodeWithOption( 1027 DhcpErrorEvent.BUFFER_UNDERFLOW, optionType); 1028 throw new ParseException(errorCode, "BufferUnderflowException"); 1029 } 1030 } 1031 1032 DhcpPacket newPacket; 1033 1034 switch(dhcpType) { 1035 case (byte) 0xFF: 1036 throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE, 1037 "No DHCP message type option"); 1038 case DHCP_MESSAGE_TYPE_DISCOVER: 1039 newPacket = new DhcpDiscoverPacket( 1040 transactionId, secs, clientMac, broadcast); 1041 break; 1042 case DHCP_MESSAGE_TYPE_OFFER: 1043 newPacket = new DhcpOfferPacket( 1044 transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac); 1045 break; 1046 case DHCP_MESSAGE_TYPE_REQUEST: 1047 newPacket = new DhcpRequestPacket( 1048 transactionId, secs, clientIp, clientMac, broadcast); 1049 break; 1050 case DHCP_MESSAGE_TYPE_DECLINE: 1051 newPacket = new DhcpDeclinePacket( 1052 transactionId, secs, clientIp, yourIp, nextIp, relayIp, 1053 clientMac); 1054 break; 1055 case DHCP_MESSAGE_TYPE_ACK: 1056 newPacket = new DhcpAckPacket( 1057 transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac); 1058 break; 1059 case DHCP_MESSAGE_TYPE_NAK: 1060 newPacket = new DhcpNakPacket( 1061 transactionId, secs, clientIp, yourIp, nextIp, relayIp, 1062 clientMac); 1063 break; 1064 case DHCP_MESSAGE_TYPE_INFORM: 1065 newPacket = new DhcpInformPacket( 1066 transactionId, secs, clientIp, yourIp, nextIp, relayIp, 1067 clientMac); 1068 break; 1069 default: 1070 throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE, 1071 "Unimplemented DHCP type %d", dhcpType); 1072 } 1073 1074 newPacket.mBroadcastAddress = bcAddr; 1075 newPacket.mDnsServers = dnsServers; 1076 newPacket.mDomainName = domainName; 1077 newPacket.mGateways = gateways; 1078 newPacket.mHostName = hostName; 1079 newPacket.mLeaseTime = leaseTime; 1080 newPacket.mMessage = message; 1081 newPacket.mMtu = mtu; 1082 newPacket.mRequestedIp = requestedIp; 1083 newPacket.mRequestedParams = expectedParams; 1084 newPacket.mServerIdentifier = serverIdentifier; 1085 newPacket.mSubnetMask = netMask; 1086 newPacket.mMaxMessageSize = maxMessageSize; 1087 newPacket.mT1 = T1; 1088 newPacket.mT2 = T2; 1089 newPacket.mVendorId = vendorId; 1090 newPacket.mVendorInfo = vendorInfo; 1091 return newPacket; 1092 } 1093 1094 /** 1095 * Parse a packet from an array of bytes, stopping at the given length. 1096 */ decodeFullPacket(byte[] packet, int length, int pktType)1097 public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType) 1098 throws ParseException { 1099 ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN); 1100 try { 1101 return decodeFullPacket(buffer, pktType); 1102 } catch (ParseException e) { 1103 throw e; 1104 } catch (Exception e) { 1105 throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage()); 1106 } 1107 } 1108 1109 /** 1110 * Construct a DhcpResults object from a DHCP reply packet. 1111 */ toDhcpResults()1112 public DhcpResults toDhcpResults() { 1113 Inet4Address ipAddress = mYourIp; 1114 if (ipAddress.equals(Inet4Address.ANY)) { 1115 ipAddress = mClientIp; 1116 if (ipAddress.equals(Inet4Address.ANY)) { 1117 return null; 1118 } 1119 } 1120 1121 int prefixLength; 1122 if (mSubnetMask != null) { 1123 try { 1124 prefixLength = NetworkUtils.netmaskToPrefixLength(mSubnetMask); 1125 } catch (IllegalArgumentException e) { 1126 // Non-contiguous netmask. 1127 return null; 1128 } 1129 } else { 1130 prefixLength = NetworkUtils.getImplicitNetmask(ipAddress); 1131 } 1132 1133 DhcpResults results = new DhcpResults(); 1134 try { 1135 results.ipAddress = new LinkAddress(ipAddress, prefixLength); 1136 } catch (IllegalArgumentException e) { 1137 return null; 1138 } 1139 1140 if (mGateways.size() > 0) { 1141 results.gateway = mGateways.get(0); 1142 } 1143 1144 results.dnsServers.addAll(mDnsServers); 1145 results.domains = mDomainName; 1146 results.serverAddress = mServerIdentifier; 1147 results.vendorInfo = mVendorInfo; 1148 results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE; 1149 results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0; 1150 1151 return results; 1152 } 1153 1154 /** 1155 * Returns the parsed lease time, in milliseconds, or 0 for infinite. 1156 */ getLeaseTimeMillis()1157 public long getLeaseTimeMillis() { 1158 // dhcpcd treats the lack of a lease time option as an infinite lease. 1159 if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) { 1160 return 0; 1161 } else if (0 <= mLeaseTime && mLeaseTime < MINIMUM_LEASE) { 1162 return MINIMUM_LEASE * 1000; 1163 } else { 1164 return (mLeaseTime & 0xffffffffL) * 1000; 1165 } 1166 } 1167 1168 /** 1169 * Builds a DHCP-DISCOVER packet from the required specified 1170 * parameters. 1171 */ buildDiscoverPacket(int encap, int transactionId, short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams)1172 public static ByteBuffer buildDiscoverPacket(int encap, int transactionId, 1173 short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) { 1174 DhcpPacket pkt = new DhcpDiscoverPacket( 1175 transactionId, secs, clientMac, broadcast); 1176 pkt.mRequestedParams = expectedParams; 1177 return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 1178 } 1179 1180 /** 1181 * Builds a DHCP-OFFER packet from the required specified 1182 * parameters. 1183 */ buildOfferPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName)1184 public static ByteBuffer buildOfferPacket(int encap, int transactionId, 1185 boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr, 1186 byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, 1187 List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1188 Inet4Address dhcpServerIdentifier, String domainName) { 1189 DhcpPacket pkt = new DhcpOfferPacket( 1190 transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac); 1191 pkt.mGateways = gateways; 1192 pkt.mDnsServers = dnsServers; 1193 pkt.mLeaseTime = timeout; 1194 pkt.mDomainName = domainName; 1195 pkt.mServerIdentifier = dhcpServerIdentifier; 1196 pkt.mSubnetMask = netMask; 1197 pkt.mBroadcastAddress = bcAddr; 1198 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 1199 } 1200 1201 /** 1202 * Builds a DHCP-ACK packet from the required specified parameters. 1203 */ buildAckPacket(int encap, int transactionId, boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr, byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, List<Inet4Address> gateways, List<Inet4Address> dnsServers, Inet4Address dhcpServerIdentifier, String domainName)1204 public static ByteBuffer buildAckPacket(int encap, int transactionId, 1205 boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr, 1206 byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr, 1207 List<Inet4Address> gateways, List<Inet4Address> dnsServers, 1208 Inet4Address dhcpServerIdentifier, String domainName) { 1209 DhcpPacket pkt = new DhcpAckPacket( 1210 transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac); 1211 pkt.mGateways = gateways; 1212 pkt.mDnsServers = dnsServers; 1213 pkt.mLeaseTime = timeout; 1214 pkt.mDomainName = domainName; 1215 pkt.mSubnetMask = netMask; 1216 pkt.mServerIdentifier = dhcpServerIdentifier; 1217 pkt.mBroadcastAddress = bcAddr; 1218 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 1219 } 1220 1221 /** 1222 * Builds a DHCP-NAK packet from the required specified parameters. 1223 */ buildNakPacket(int encap, int transactionId, Inet4Address serverIpAddr, Inet4Address clientIpAddr, byte[] mac)1224 public static ByteBuffer buildNakPacket(int encap, int transactionId, 1225 Inet4Address serverIpAddr, Inet4Address clientIpAddr, byte[] mac) { 1226 DhcpPacket pkt = new DhcpNakPacket(transactionId, (short) 0, clientIpAddr, 1227 serverIpAddr, serverIpAddr, serverIpAddr, mac); 1228 pkt.mMessage = "requested address not available"; 1229 pkt.mRequestedIp = clientIpAddr; 1230 return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER); 1231 } 1232 1233 /** 1234 * Builds a DHCP-REQUEST packet from the required specified parameters. 1235 */ buildRequestPacket(int encap, int transactionId, short secs, Inet4Address clientIp, boolean broadcast, byte[] clientMac, Inet4Address requestedIpAddress, Inet4Address serverIdentifier, byte[] requestedParams, String hostName)1236 public static ByteBuffer buildRequestPacket(int encap, 1237 int transactionId, short secs, Inet4Address clientIp, boolean broadcast, 1238 byte[] clientMac, Inet4Address requestedIpAddress, 1239 Inet4Address serverIdentifier, byte[] requestedParams, String hostName) { 1240 DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp, 1241 clientMac, broadcast); 1242 pkt.mRequestedIp = requestedIpAddress; 1243 pkt.mServerIdentifier = serverIdentifier; 1244 pkt.mHostName = hostName; 1245 pkt.mRequestedParams = requestedParams; 1246 ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT); 1247 return result; 1248 } 1249 } 1250