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 com.android.internal.annotations.VisibleForTesting;
     11 
     12 import java.io.UnsupportedEncodingException;
     13 import java.net.Inet4Address;
     14 import java.net.UnknownHostException;
     15 import java.nio.BufferUnderflowException;
     16 import java.nio.ByteBuffer;
     17 import java.nio.ByteOrder;
     18 import java.nio.ShortBuffer;
     19 import java.nio.charset.StandardCharsets;
     20 import java.util.ArrayList;
     21 import java.util.Arrays;
     22 import java.util.List;
     23 
     24 /**
     25  * Defines basic data and operations needed to build and use packets for the
     26  * DHCP protocol.  Subclasses create the specific packets used at each
     27  * stage of the negotiation.
     28  */
     29 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      */
    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      */
    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 
    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      */
    327     public int getTransactionId() {
    328         return mTransId;
    329     }
    330 
    331     /**
    332      * Returns the client MAC.
    333      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    609     protected static void addTlvEnd(ByteBuffer buf) {
    610         buf.put((byte) 0xFF);
    611     }
    612 
    613     private String getVendorId() {
    614         if (testOverrideVendorId != null) return testOverrideVendorId;
    615         return "android-dhcp-" + Build.VERSION.RELEASE;
    616     }
    617 
    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      */
    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      */
    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 
    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      */
    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      */
    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 
    703     private static boolean isPacketToOrFromClient(short udpSrcPort, short udpDstPort) {
    704         return (udpSrcPort == DHCP_CLIENT) || (udpDstPort == DHCP_CLIENT);
    705     }
    706 
    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;
    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      */
    728     @VisibleForTesting
    729     static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
    730     {
    731         // bootp parameters
    732         int transactionId;
    733         short secs;
    734         Inet4Address clientIp;
    735         Inet4Address yourIp;
    736         Inet4Address nextIp;
    737         Inet4Address relayIp;
    738         byte[] clientMac;
    739         List<Inet4Address> dnsServers = new ArrayList<>();
    740         List<Inet4Address> gateways = new ArrayList<>();  // aka router
    741         Inet4Address serverIdentifier = null;
    742         Inet4Address netMask = null;
    743         String message = null;
    744         String vendorId = null;
    745         String vendorInfo = null;
    746         byte[] expectedParams = null;
    747         String hostName = null;
    748         String domainName = null;
    749         Inet4Address ipSrc = null;
    750         Inet4Address ipDst = null;
    751         Inet4Address bcAddr = null;
    752         Inet4Address requestedIp = null;
    753 
    754         // The following are all unsigned integers. Internally we store them as signed integers of
    755         // the same length because that way we're guaranteed that they can't be out of the range of
    756         // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need
    757         // to cast it.
    758         Short mtu = null;
    759         Short maxMessageSize = null;
    760         Integer leaseTime = null;
    761         Integer T1 = null;
    762         Integer T2 = null;
    763 
    764         // dhcp options
    765         byte dhcpType = (byte) 0xFF;
    766 
    767         packet.order(ByteOrder.BIG_ENDIAN);
    768 
    769         // check to see if we need to parse L2, IP, and UDP encaps
    770         if (pktType == ENCAP_L2) {
    771             if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
    772                 throw new ParseException(DhcpErrorEvent.L2_TOO_SHORT,
    773                         "L2 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L2);
    774             }
    775 
    776             byte[] l2dst = new byte[6];
    777             byte[] l2src = new byte[6];
    778 
    779             packet.get(l2dst);
    780             packet.get(l2src);
    781 
    782             short l2type = packet.getShort();
    783 
    784             if (l2type != OsConstants.ETH_P_IP) {
    785                 throw new ParseException(DhcpErrorEvent.L2_WRONG_ETH_TYPE,
    786                         "Unexpected L2 type 0x%04x, expected 0x%04x", l2type, OsConstants.ETH_P_IP);
    787             }
    788         }
    789 
    790         if (pktType <= ENCAP_L3) {
    791             if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
    792                 throw new ParseException(DhcpErrorEvent.L3_TOO_SHORT,
    793                         "L3 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L3);
    794             }
    795 
    796             byte ipTypeAndLength = packet.get();
    797             int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
    798             if (ipVersion != 4) {
    799                 throw new ParseException(
    800                         DhcpErrorEvent.L3_NOT_IPV4, "Invalid IP version %d", ipVersion);
    801             }
    802 
    803             // System.out.println("ipType is " + ipType);
    804             byte ipDiffServicesField = packet.get();
    805             short ipTotalLength = packet.getShort();
    806             short ipIdentification = packet.getShort();
    807             byte ipFlags = packet.get();
    808             byte ipFragOffset = packet.get();
    809             byte ipTTL = packet.get();
    810             byte ipProto = packet.get();
    811             short ipChksm = packet.getShort();
    812 
    813             ipSrc = readIpAddress(packet);
    814             ipDst = readIpAddress(packet);
    815 
    816             if (ipProto != IP_TYPE_UDP) {
    817                 throw new ParseException(
    818                         DhcpErrorEvent.L4_NOT_UDP, "Protocol not UDP: %d", ipProto);
    819             }
    820 
    821             // Skip options. This cannot cause us to read beyond the end of the buffer because the
    822             // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
    823             // MIN_PACKET_LENGTH_L3.
    824             int optionWords = ((ipTypeAndLength & 0x0f) - 5);
    825             for (int i = 0; i < optionWords; i++) {
    826                 packet.getInt();
    827             }
    828 
    829             // assume UDP
    830             short udpSrcPort = packet.getShort();
    831             short udpDstPort = packet.getShort();
    832             short udpLen = packet.getShort();
    833             short udpChkSum = packet.getShort();
    834 
    835             // Only accept packets to or from the well-known client port (expressly permitting
    836             // packets from ports other than the well-known server port; http://b/24687559), and
    837             // server-to-server packets, e.g. for relays.
    838             if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) &&
    839                 !isPacketServerToServer(udpSrcPort, udpDstPort)) {
    840                 // This should almost never happen because we use SO_ATTACH_FILTER on the packet
    841                 // socket to drop packets that don't have the right source ports. However, it's
    842                 // possible that a packet arrives between when the socket is bound and when the
    843                 // filter is set. http://b/26696823 .
    844                 throw new ParseException(DhcpErrorEvent.L4_WRONG_PORT,
    845                         "Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
    846             }
    847         }
    848 
    849         // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
    850         if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
    851             throw new ParseException(DhcpErrorEvent.BOOTP_TOO_SHORT,
    852                         "Invalid type or BOOTP packet too short, %d < %d",
    853                         packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
    854         }
    855 
    856         byte type = packet.get();
    857         byte hwType = packet.get();
    858         int addrLen = packet.get() & 0xff;
    859         byte hops = packet.get();
    860         transactionId = packet.getInt();
    861         secs = packet.getShort();
    862         short bootpFlags = packet.getShort();
    863         boolean broadcast = (bootpFlags & 0x8000) != 0;
    864         byte[] ipv4addr = new byte[4];
    865 
    866         try {
    867             packet.get(ipv4addr);
    868             clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
    869             packet.get(ipv4addr);
    870             yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
    871             packet.get(ipv4addr);
    872             nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
    873             packet.get(ipv4addr);
    874             relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
    875         } catch (UnknownHostException ex) {
    876             throw new ParseException(DhcpErrorEvent.L3_INVALID_IP,
    877                     "Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
    878         }
    879 
    880         // Some DHCP servers have been known to announce invalid client hardware address values such
    881         // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at
    882         // all but only checks that the interface MAC address matches the first bytes of the address
    883         // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger
    884         // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795
    885         // TODO: evaluate whether to make this test more liberal.
    886         if (addrLen > HWADDR_LEN) {
    887             addrLen = ETHER_BROADCAST.length;
    888         }
    889 
    890         clientMac = new byte[addrLen];
    891         packet.get(clientMac);
    892 
    893         // skip over address padding (16 octets allocated)
    894         packet.position(packet.position() + (16 - addrLen)
    895                         + 64    // skip server host name (64 chars)
    896                         + 128); // skip boot file name (128 chars)
    897 
    898         // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
    899         if (packet.remaining() < 4) {
    900             throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message");
    901         }
    902 
    903         int dhcpMagicCookie = packet.getInt();
    904         if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
    905             throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE,
    906                     "Bad magic cookie 0x%08x, should be 0x%08x",
    907                     dhcpMagicCookie, DHCP_MAGIC_COOKIE);
    908         }
    909 
    910         // parse options
    911         boolean notFinishedOptions = true;
    912 
    913         while ((packet.position() < packet.limit()) && notFinishedOptions) {
    914             final byte optionType = packet.get(); // cannot underflow because position < limit
    915             try {
    916                 if (optionType == DHCP_OPTION_END) {
    917                     notFinishedOptions = false;
    918                 } else if (optionType == DHCP_OPTION_PAD) {
    919                     // The pad option doesn't have a length field. Nothing to do.
    920                 } else {
    921                     int optionLen = packet.get() & 0xFF;
    922                     int expectedLen = 0;
    923 
    924                     switch(optionType) {
    925                         case DHCP_SUBNET_MASK:
    926                             netMask = readIpAddress(packet);
    927                             expectedLen = 4;
    928                             break;
    929                         case DHCP_ROUTER:
    930                             for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
    931                                 gateways.add(readIpAddress(packet));
    932                             }
    933                             break;
    934                         case DHCP_DNS_SERVER:
    935                             for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
    936                                 dnsServers.add(readIpAddress(packet));
    937                             }
    938                             break;
    939                         case DHCP_HOST_NAME:
    940                             expectedLen = optionLen;
    941                             hostName = readAsciiString(packet, optionLen, false);
    942                             break;
    943                         case DHCP_MTU:
    944                             expectedLen = 2;
    945                             mtu = packet.getShort();
    946                             break;
    947                         case DHCP_DOMAIN_NAME:
    948                             expectedLen = optionLen;
    949                             domainName = readAsciiString(packet, optionLen, false);
    950                             break;
    951                         case DHCP_BROADCAST_ADDRESS:
    952                             bcAddr = readIpAddress(packet);
    953                             expectedLen = 4;
    954                             break;
    955                         case DHCP_REQUESTED_IP:
    956                             requestedIp = readIpAddress(packet);
    957                             expectedLen = 4;
    958                             break;
    959                         case DHCP_LEASE_TIME:
    960                             leaseTime = Integer.valueOf(packet.getInt());
    961                             expectedLen = 4;
    962                             break;
    963                         case DHCP_MESSAGE_TYPE:
    964                             dhcpType = packet.get();
    965                             expectedLen = 1;
    966                             break;
    967                         case DHCP_SERVER_IDENTIFIER:
    968                             serverIdentifier = readIpAddress(packet);
    969                             expectedLen = 4;
    970                             break;
    971                         case DHCP_PARAMETER_LIST:
    972                             expectedParams = new byte[optionLen];
    973                             packet.get(expectedParams);
    974                             expectedLen = optionLen;
    975                             break;
    976                         case DHCP_MESSAGE:
    977                             expectedLen = optionLen;
    978                             message = readAsciiString(packet, optionLen, false);
    979                             break;
    980                         case DHCP_MAX_MESSAGE_SIZE:
    981                             expectedLen = 2;
    982                             maxMessageSize = Short.valueOf(packet.getShort());
    983                             break;
    984                         case DHCP_RENEWAL_TIME:
    985                             expectedLen = 4;
    986                             T1 = Integer.valueOf(packet.getInt());
    987                             break;
    988                         case DHCP_REBINDING_TIME:
    989                             expectedLen = 4;
    990                             T2 = Integer.valueOf(packet.getInt());
    991                             break;
    992                         case DHCP_VENDOR_CLASS_ID:
    993                             expectedLen = optionLen;
    994                             // Embedded nulls are safe as this does not get passed to netd.
    995                             vendorId = readAsciiString(packet, optionLen, true);
    996                             break;
    997                         case DHCP_CLIENT_IDENTIFIER: { // Client identifier
    998                             byte[] id = new byte[optionLen];
    999                             packet.get(id);
   1000                             expectedLen = optionLen;
   1001                         } break;
   1002                         case DHCP_VENDOR_INFO:
   1003                             expectedLen = optionLen;
   1004                             // Embedded nulls are safe as this does not get passed to netd.
   1005                             vendorInfo = readAsciiString(packet, optionLen, true);
   1006                             break;
   1007                         default:
   1008                             // ignore any other parameters
   1009                             for (int i = 0; i < optionLen; i++) {
   1010                                 expectedLen++;
   1011                                 byte throwaway = packet.get();
   1012                             }
   1013                     }
   1014 
   1015                     if (expectedLen != optionLen) {
   1016                         final int errorCode = DhcpErrorEvent.errorCodeWithOption(
   1017                                 DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
   1018                         throw new ParseException(errorCode,
   1019                                 "Invalid length %d for option %d, expected %d",
   1020                                 optionLen, optionType, expectedLen);
   1021                     }
   1022                 }
   1023             } catch (BufferUnderflowException e) {
   1024                 final int errorCode = DhcpErrorEvent.errorCodeWithOption(
   1025                         DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
   1026                 throw new ParseException(errorCode, "BufferUnderflowException");
   1027             }
   1028         }
   1029 
   1030         DhcpPacket newPacket;
   1031 
   1032         switch(dhcpType) {
   1033             case (byte) 0xFF:
   1034                 throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE,
   1035                         "No DHCP message type option");
   1036             case DHCP_MESSAGE_TYPE_DISCOVER:
   1037                 newPacket = new DhcpDiscoverPacket(
   1038                     transactionId, secs, clientMac, broadcast);
   1039                 break;
   1040             case DHCP_MESSAGE_TYPE_OFFER:
   1041                 newPacket = new DhcpOfferPacket(
   1042                     transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac);
   1043                 break;
   1044             case DHCP_MESSAGE_TYPE_REQUEST:
   1045                 newPacket = new DhcpRequestPacket(
   1046                     transactionId, secs, clientIp, clientMac, broadcast);
   1047                 break;
   1048             case DHCP_MESSAGE_TYPE_DECLINE:
   1049                 newPacket = new DhcpDeclinePacket(
   1050                     transactionId, secs, clientIp, yourIp, nextIp, relayIp,
   1051                     clientMac);
   1052                 break;
   1053             case DHCP_MESSAGE_TYPE_ACK:
   1054                 newPacket = new DhcpAckPacket(
   1055                     transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac);
   1056                 break;
   1057             case DHCP_MESSAGE_TYPE_NAK:
   1058                 newPacket = new DhcpNakPacket(
   1059                     transactionId, secs, clientIp, yourIp, nextIp, relayIp,
   1060                     clientMac);
   1061                 break;
   1062             case DHCP_MESSAGE_TYPE_INFORM:
   1063                 newPacket = new DhcpInformPacket(
   1064                     transactionId, secs, clientIp, yourIp, nextIp, relayIp,
   1065                     clientMac);
   1066                 break;
   1067             default:
   1068                 throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE,
   1069                         "Unimplemented DHCP type %d", dhcpType);
   1070         }
   1071 
   1072         newPacket.mBroadcastAddress = bcAddr;
   1073         newPacket.mDnsServers = dnsServers;
   1074         newPacket.mDomainName = domainName;
   1075         newPacket.mGateways = gateways;
   1076         newPacket.mHostName = hostName;
   1077         newPacket.mLeaseTime = leaseTime;
   1078         newPacket.mMessage = message;
   1079         newPacket.mMtu = mtu;
   1080         newPacket.mRequestedIp = requestedIp;
   1081         newPacket.mRequestedParams = expectedParams;
   1082         newPacket.mServerIdentifier = serverIdentifier;
   1083         newPacket.mSubnetMask = netMask;
   1084         newPacket.mMaxMessageSize = maxMessageSize;
   1085         newPacket.mT1 = T1;
   1086         newPacket.mT2 = T2;
   1087         newPacket.mVendorId = vendorId;
   1088         newPacket.mVendorInfo = vendorInfo;
   1089         return newPacket;
   1090     }
   1091 
   1092     /**
   1093      * Parse a packet from an array of bytes, stopping at the given length.
   1094      */
   1095     public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
   1096             throws ParseException {
   1097         ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
   1098         try {
   1099             return decodeFullPacket(buffer, pktType);
   1100         } catch (ParseException e) {
   1101             throw e;
   1102         } catch (Exception e) {
   1103             throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage());
   1104         }
   1105     }
   1106 
   1107     /**
   1108      *  Construct a DhcpResults object from a DHCP reply packet.
   1109      */
   1110     public DhcpResults toDhcpResults() {
   1111         Inet4Address ipAddress = mYourIp;
   1112         if (ipAddress.equals(Inet4Address.ANY)) {
   1113             ipAddress = mClientIp;
   1114             if (ipAddress.equals(Inet4Address.ANY)) {
   1115                 return null;
   1116             }
   1117         }
   1118 
   1119         int prefixLength;
   1120         if (mSubnetMask != null) {
   1121             try {
   1122                 prefixLength = NetworkUtils.netmaskToPrefixLength(mSubnetMask);
   1123             } catch (IllegalArgumentException e) {
   1124                 // Non-contiguous netmask.
   1125                 return null;
   1126             }
   1127         } else {
   1128             prefixLength = NetworkUtils.getImplicitNetmask(ipAddress);
   1129         }
   1130 
   1131         DhcpResults results = new DhcpResults();
   1132         try {
   1133             results.ipAddress = new LinkAddress(ipAddress, prefixLength);
   1134         } catch (IllegalArgumentException e) {
   1135             return null;
   1136         }
   1137 
   1138         if (mGateways.size() > 0) {
   1139             results.gateway = mGateways.get(0);
   1140         }
   1141 
   1142         results.dnsServers.addAll(mDnsServers);
   1143         results.domains = mDomainName;
   1144         results.serverAddress = mServerIdentifier;
   1145         results.vendorInfo = mVendorInfo;
   1146         results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
   1147         results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
   1148 
   1149         return results;
   1150     }
   1151 
   1152     /**
   1153      * Returns the parsed lease time, in milliseconds, or 0 for infinite.
   1154      */
   1155     public long getLeaseTimeMillis() {
   1156         // dhcpcd treats the lack of a lease time option as an infinite lease.
   1157         if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) {
   1158             return 0;
   1159         } else if (0 <= mLeaseTime && mLeaseTime < MINIMUM_LEASE) {
   1160             return MINIMUM_LEASE * 1000;
   1161         } else {
   1162             return (mLeaseTime & 0xffffffffL) * 1000;
   1163         }
   1164     }
   1165 
   1166     /**
   1167      * Builds a DHCP-DISCOVER packet from the required specified
   1168      * parameters.
   1169      */
   1170     public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
   1171         short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) {
   1172         DhcpPacket pkt = new DhcpDiscoverPacket(
   1173             transactionId, secs, clientMac, broadcast);
   1174         pkt.mRequestedParams = expectedParams;
   1175         return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
   1176     }
   1177 
   1178     /**
   1179      * Builds a DHCP-OFFER packet from the required specified
   1180      * parameters.
   1181      */
   1182     public static ByteBuffer buildOfferPacket(int encap, int transactionId,
   1183         boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
   1184         byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
   1185         List<Inet4Address> gateways, List<Inet4Address> dnsServers,
   1186         Inet4Address dhcpServerIdentifier, String domainName) {
   1187         DhcpPacket pkt = new DhcpOfferPacket(
   1188             transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac);
   1189         pkt.mGateways = gateways;
   1190         pkt.mDnsServers = dnsServers;
   1191         pkt.mLeaseTime = timeout;
   1192         pkt.mDomainName = domainName;
   1193         pkt.mServerIdentifier = dhcpServerIdentifier;
   1194         pkt.mSubnetMask = netMask;
   1195         pkt.mBroadcastAddress = bcAddr;
   1196         return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
   1197     }
   1198 
   1199     /**
   1200      * Builds a DHCP-ACK packet from the required specified parameters.
   1201      */
   1202     public static ByteBuffer buildAckPacket(int encap, int transactionId,
   1203         boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
   1204         byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
   1205         List<Inet4Address> gateways, List<Inet4Address> dnsServers,
   1206         Inet4Address dhcpServerIdentifier, String domainName) {
   1207         DhcpPacket pkt = new DhcpAckPacket(
   1208             transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac);
   1209         pkt.mGateways = gateways;
   1210         pkt.mDnsServers = dnsServers;
   1211         pkt.mLeaseTime = timeout;
   1212         pkt.mDomainName = domainName;
   1213         pkt.mSubnetMask = netMask;
   1214         pkt.mServerIdentifier = dhcpServerIdentifier;
   1215         pkt.mBroadcastAddress = bcAddr;
   1216         return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
   1217     }
   1218 
   1219     /**
   1220      * Builds a DHCP-NAK packet from the required specified parameters.
   1221      */
   1222     public static ByteBuffer buildNakPacket(int encap, int transactionId,
   1223         Inet4Address serverIpAddr, Inet4Address clientIpAddr, byte[] mac) {
   1224         DhcpPacket pkt = new DhcpNakPacket(transactionId, (short) 0, clientIpAddr,
   1225             serverIpAddr, serverIpAddr, serverIpAddr, mac);
   1226         pkt.mMessage = "requested address not available";
   1227         pkt.mRequestedIp = clientIpAddr;
   1228         return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
   1229     }
   1230 
   1231     /**
   1232      * Builds a DHCP-REQUEST packet from the required specified parameters.
   1233      */
   1234     public static ByteBuffer buildRequestPacket(int encap,
   1235         int transactionId, short secs, Inet4Address clientIp, boolean broadcast,
   1236         byte[] clientMac, Inet4Address requestedIpAddress,
   1237         Inet4Address serverIdentifier, byte[] requestedParams, String hostName) {
   1238         DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp,
   1239             clientMac, broadcast);
   1240         pkt.mRequestedIp = requestedIpAddress;
   1241         pkt.mServerIdentifier = serverIdentifier;
   1242         pkt.mHostName = hostName;
   1243         pkt.mRequestedParams = requestedParams;
   1244         ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
   1245         return result;
   1246     }
   1247 }
   1248