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