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