Home | History | Annotate | Download | only in dhcp
      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      */
    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      */
    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 
    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      */
    330     public int getTransactionId() {
    331         return mTransId;
    332     }
    333 
    334     /**
    335      * Returns the client MAC.
    336      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    612     protected static void addTlvEnd(ByteBuffer buf) {
    613         buf.put((byte) 0xFF);
    614     }
    615 
    616     private String getVendorId() {
    617         if (testOverrideVendorId != null) return testOverrideVendorId;
    618         return "android-dhcp-" + Build.VERSION.RELEASE;
    619     }
    620 
    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      */
    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      */
    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 
    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      */
    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      */
    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 
    707     private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) {
    708         return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT);
    709     }
    710 
    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;
    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
    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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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      */
   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