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 
     11 import java.io.UnsupportedEncodingException;
     12 import java.net.Inet4Address;
     13 import java.net.UnknownHostException;
     14 import java.nio.BufferUnderflowException;
     15 import java.nio.ByteBuffer;
     16 import java.nio.ByteOrder;
     17 import java.nio.charset.StandardCharsets;
     18 import java.nio.ShortBuffer;
     19 
     20 import java.util.ArrayList;
     21 import java.util.Arrays;
     22 import java.util.List;
     23 
     24 /**
     25  * Defines basic data and operations needed to build and use packets for the
     26  * DHCP protocol.  Subclasses create the specific packets used at each
     27  * stage of the negotiation.
     28  */
     29 abstract class DhcpPacket {
     30     protected static final String TAG = "DhcpPacket";
     31 
     32     // dhcpcd has a minimum lease of 20 seconds, but DhcpStateMachine would refuse to wake up the
     33     // CPU for anything shorter than 5 minutes. For sanity's sake, this must be higher than the
     34     // DHCP client timeout.
     35     public static final int MINIMUM_LEASE = 60;
     36     public static final int INFINITE_LEASE = (int) 0xffffffff;
     37 
     38     public static final Inet4Address INADDR_ANY = (Inet4Address) Inet4Address.ANY;
     39     public static final Inet4Address INADDR_BROADCAST = (Inet4Address) Inet4Address.ALL;
     40     public static final byte[] ETHER_BROADCAST = new byte[] {
     41             (byte) 0xff, (byte) 0xff, (byte) 0xff,
     42             (byte) 0xff, (byte) 0xff, (byte) 0xff,
     43     };
     44 
     45     /**
     46      * Packet encapsulations.
     47      */
     48     public static final int ENCAP_L2 = 0;    // EthernetII header included
     49     public static final int ENCAP_L3 = 1;    // IP/UDP header included
     50     public static final int ENCAP_BOOTP = 2; // BOOTP contents only
     51 
     52     /**
     53      * Minimum length of a DHCP packet, excluding options, in the above encapsulations.
     54      */
     55     public static final int MIN_PACKET_LENGTH_BOOTP = 236;  // See diagram in RFC 2131, section 2.
     56     public static final int MIN_PACKET_LENGTH_L3 = MIN_PACKET_LENGTH_BOOTP + 20 + 8;
     57     public static final int MIN_PACKET_LENGTH_L2 = MIN_PACKET_LENGTH_L3 + 14;
     58 
     59     public static final int HWADDR_LEN = 16;
     60     public static final int MAX_OPTION_LEN = 255;
     61 
     62     /**
     63      * The minimum and maximum MTU that we are prepared to use. We set the minimum to the minimum
     64      * IPv6 MTU because the IPv6 stack enters unusual codepaths when the link MTU drops below 1280,
     65      * and does not recover if the MTU is brought above 1280 again. We set the maximum to 1500
     66      * because in general it is risky to assume that the hardware is able to send/receive packets
     67      * larger than 1500 bytes even if the network supports it.
     68      */
     69     private static final int MIN_MTU = 1280;
     70     private static final int MAX_MTU = 1500;
     71 
     72     /**
     73      * IP layer definitions.
     74      */
     75     private static final byte IP_TYPE_UDP = (byte) 0x11;
     76 
     77     /**
     78      * IP: Version 4, Header Length 20 bytes
     79      */
     80     private static final byte IP_VERSION_HEADER_LEN = (byte) 0x45;
     81 
     82     /**
     83      * IP: Flags 0, Fragment Offset 0, Don't Fragment
     84      */
     85     private static final short IP_FLAGS_OFFSET = (short) 0x4000;
     86 
     87     /**
     88      * IP: TOS
     89      */
     90     private static final byte IP_TOS_LOWDELAY = (byte) 0x10;
     91 
     92     /**
     93      * IP: TTL -- use default 64 from RFC1340
     94      */
     95     private static final byte IP_TTL = (byte) 0x40;
     96 
     97     /**
     98      * The client DHCP port.
     99      */
    100     static final short DHCP_CLIENT = (short) 68;
    101 
    102     /**
    103      * The server DHCP port.
    104      */
    105     static final short DHCP_SERVER = (short) 67;
    106 
    107     /**
    108      * The message op code indicating a request from a client.
    109      */
    110     protected static final byte DHCP_BOOTREQUEST = (byte) 1;
    111 
    112     /**
    113      * The message op code indicating a response from the server.
    114      */
    115     protected static final byte DHCP_BOOTREPLY = (byte) 2;
    116 
    117     /**
    118      * The code type used to identify an Ethernet MAC address in the
    119      * Client-ID field.
    120      */
    121     protected static final byte CLIENT_ID_ETHER = (byte) 1;
    122 
    123     /**
    124      * The maximum length of a packet that can be constructed.
    125      */
    126     protected static final int MAX_LENGTH = 1500;
    127 
    128     /**
    129      * The magic cookie that identifies this as a DHCP packet instead of BOOTP.
    130      */
    131     private static final int DHCP_MAGIC_COOKIE = 0x63825363;
    132 
    133     /**
    134      * DHCP Optional Type: DHCP Subnet Mask
    135      */
    136     protected static final byte DHCP_SUBNET_MASK = 1;
    137     protected Inet4Address mSubnetMask;
    138 
    139     /**
    140      * DHCP Optional Type: DHCP Router
    141      */
    142     protected static final byte DHCP_ROUTER = 3;
    143     protected List <Inet4Address> mGateways;
    144 
    145     /**
    146      * DHCP Optional Type: DHCP DNS Server
    147      */
    148     protected static final byte DHCP_DNS_SERVER = 6;
    149     protected List<Inet4Address> mDnsServers;
    150 
    151     /**
    152      * DHCP Optional Type: DHCP Host Name
    153      */
    154     protected static final byte DHCP_HOST_NAME = 12;
    155     protected String mHostName;
    156 
    157     /**
    158      * DHCP Optional Type: DHCP DOMAIN NAME
    159      */
    160     protected static final byte DHCP_DOMAIN_NAME = 15;
    161     protected String mDomainName;
    162 
    163     /**
    164      * DHCP Optional Type: DHCP Interface MTU
    165      */
    166     protected static final byte DHCP_MTU = 26;
    167     protected Short mMtu;
    168 
    169     /**
    170      * DHCP Optional Type: DHCP BROADCAST ADDRESS
    171      */
    172     protected static final byte DHCP_BROADCAST_ADDRESS = 28;
    173     protected Inet4Address mBroadcastAddress;
    174 
    175     /**
    176      * DHCP Optional Type: Vendor specific information
    177      */
    178     protected static final byte DHCP_VENDOR_INFO = 43;
    179     protected String mVendorInfo;
    180 
    181     /**
    182      * DHCP Optional Type: DHCP Requested IP Address
    183      */
    184     protected static final byte DHCP_REQUESTED_IP = 50;
    185     protected Inet4Address mRequestedIp;
    186 
    187     /**
    188      * DHCP Optional Type: DHCP Lease Time
    189      */
    190     protected static final byte DHCP_LEASE_TIME = 51;
    191     protected Integer mLeaseTime;
    192 
    193     /**
    194      * DHCP Optional Type: DHCP Message Type
    195      */
    196     protected static final byte DHCP_MESSAGE_TYPE = 53;
    197     // the actual type values
    198     protected static final byte DHCP_MESSAGE_TYPE_DISCOVER = 1;
    199     protected static final byte DHCP_MESSAGE_TYPE_OFFER = 2;
    200     protected static final byte DHCP_MESSAGE_TYPE_REQUEST = 3;
    201     protected static final byte DHCP_MESSAGE_TYPE_DECLINE = 4;
    202     protected static final byte DHCP_MESSAGE_TYPE_ACK = 5;
    203     protected static final byte DHCP_MESSAGE_TYPE_NAK = 6;
    204     protected static final byte DHCP_MESSAGE_TYPE_INFORM = 8;
    205 
    206     /**
    207      * DHCP Optional Type: DHCP Server Identifier
    208      */
    209     protected static final byte DHCP_SERVER_IDENTIFIER = 54;
    210     protected Inet4Address mServerIdentifier;
    211 
    212     /**
    213      * DHCP Optional Type: DHCP Parameter List
    214      */
    215     protected static final byte DHCP_PARAMETER_LIST = 55;
    216     protected byte[] mRequestedParams;
    217 
    218     /**
    219      * DHCP Optional Type: DHCP MESSAGE
    220      */
    221     protected static final byte DHCP_MESSAGE = 56;
    222     protected String mMessage;
    223 
    224     /**
    225      * DHCP Optional Type: Maximum DHCP Message Size
    226      */
    227     protected static final byte DHCP_MAX_MESSAGE_SIZE = 57;
    228     protected Short mMaxMessageSize;
    229 
    230     /**
    231      * DHCP Optional Type: DHCP Renewal Time Value
    232      */
    233     protected static final byte DHCP_RENEWAL_TIME = 58;
    234     protected Integer mT1;
    235 
    236     /**
    237      * DHCP Optional Type: Rebinding Time Value
    238      */
    239     protected static final byte DHCP_REBINDING_TIME = 59;
    240     protected Integer mT2;
    241 
    242     /**
    243      * DHCP Optional Type: Vendor Class Identifier
    244      */
    245     protected static final byte DHCP_VENDOR_CLASS_ID = 60;
    246     protected String mVendorId;
    247 
    248     /**
    249      * DHCP Optional Type: DHCP Client Identifier
    250      */
    251     protected static final byte DHCP_CLIENT_IDENTIFIER = 61;
    252 
    253     /**
    254      * DHCP zero-length option code: pad
    255      */
    256     protected static final byte DHCP_OPTION_PAD = 0x00;
    257 
    258     /**
    259      * DHCP zero-length option code: end of options
    260      */
    261     protected static final byte DHCP_OPTION_END = (byte) 0xff;
    262 
    263     /**
    264      * The transaction identifier used in this particular DHCP negotiation
    265      */
    266     protected final int mTransId;
    267 
    268     /**
    269      * The seconds field in the BOOTP header. Per RFC, should be nonzero in client requests only.
    270      */
    271     protected final short mSecs;
    272 
    273     /**
    274      * The IP address of the client host.  This address is typically
    275      * proposed by the client (from an earlier DHCP negotiation) or
    276      * supplied by the server.
    277      */
    278     protected final Inet4Address mClientIp;
    279     protected final Inet4Address mYourIp;
    280     private final Inet4Address mNextIp;
    281     private final Inet4Address mRelayIp;
    282 
    283     /**
    284      * Does the client request a broadcast response?
    285      */
    286     protected boolean mBroadcast;
    287 
    288     /**
    289      * The six-octet MAC of the client.
    290      */
    291     protected final byte[] mClientMac;
    292 
    293     /**
    294      * Asks the packet object to create a ByteBuffer serialization of
    295      * the packet for transmission.
    296      */
    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     public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
    729     {
    730         // bootp parameters
    731         int transactionId;
    732         short secs;
    733         Inet4Address clientIp;
    734         Inet4Address yourIp;
    735         Inet4Address nextIp;
    736         Inet4Address relayIp;
    737         byte[] clientMac;
    738         List<Inet4Address> dnsServers = new ArrayList<>();
    739         List<Inet4Address> gateways = new ArrayList<>();  // aka router
    740         Inet4Address serverIdentifier = null;
    741         Inet4Address netMask = null;
    742         String message = null;
    743         String vendorId = null;
    744         String vendorInfo = null;
    745         byte[] expectedParams = null;
    746         String hostName = null;
    747         String domainName = null;
    748         Inet4Address ipSrc = null;
    749         Inet4Address ipDst = null;
    750         Inet4Address bcAddr = null;
    751         Inet4Address requestedIp = null;
    752 
    753         // The following are all unsigned integers. Internally we store them as signed integers of
    754         // the same length because that way we're guaranteed that they can't be out of the range of
    755         // the unsigned field in the packet. Callers wanting to pass in an unsigned value will need
    756         // to cast it.
    757         Short mtu = null;
    758         Short maxMessageSize = null;
    759         Integer leaseTime = null;
    760         Integer T1 = null;
    761         Integer T2 = null;
    762 
    763         // dhcp options
    764         byte dhcpType = (byte) 0xFF;
    765 
    766         packet.order(ByteOrder.BIG_ENDIAN);
    767 
    768         // check to see if we need to parse L2, IP, and UDP encaps
    769         if (pktType == ENCAP_L2) {
    770             if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
    771                 throw new ParseException(DhcpErrorEvent.L2_TOO_SHORT,
    772                         "L2 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L2);
    773             }
    774 
    775             byte[] l2dst = new byte[6];
    776             byte[] l2src = new byte[6];
    777 
    778             packet.get(l2dst);
    779             packet.get(l2src);
    780 
    781             short l2type = packet.getShort();
    782 
    783             if (l2type != OsConstants.ETH_P_IP) {
    784                 throw new ParseException(DhcpErrorEvent.L2_WRONG_ETH_TYPE,
    785                         "Unexpected L2 type 0x%04x, expected 0x%04x", l2type, OsConstants.ETH_P_IP);
    786             }
    787         }
    788 
    789         if (pktType <= ENCAP_L3) {
    790             if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
    791                 throw new ParseException(DhcpErrorEvent.L3_TOO_SHORT,
    792                         "L3 packet too short, %d < %d", packet.remaining(), MIN_PACKET_LENGTH_L3);
    793             }
    794 
    795             byte ipTypeAndLength = packet.get();
    796             int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
    797             if (ipVersion != 4) {
    798                 throw new ParseException(
    799                         DhcpErrorEvent.L3_NOT_IPV4, "Invalid IP version %d", ipVersion);
    800             }
    801 
    802             // System.out.println("ipType is " + ipType);
    803             byte ipDiffServicesField = packet.get();
    804             short ipTotalLength = packet.getShort();
    805             short ipIdentification = packet.getShort();
    806             byte ipFlags = packet.get();
    807             byte ipFragOffset = packet.get();
    808             byte ipTTL = packet.get();
    809             byte ipProto = packet.get();
    810             short ipChksm = packet.getShort();
    811 
    812             ipSrc = readIpAddress(packet);
    813             ipDst = readIpAddress(packet);
    814 
    815             if (ipProto != IP_TYPE_UDP) {
    816                 throw new ParseException(
    817                         DhcpErrorEvent.L4_NOT_UDP, "Protocol not UDP: %d", ipProto);
    818             }
    819 
    820             // Skip options. This cannot cause us to read beyond the end of the buffer because the
    821             // IPv4 header cannot be more than (0x0f * 4) = 60 bytes long, and that is less than
    822             // MIN_PACKET_LENGTH_L3.
    823             int optionWords = ((ipTypeAndLength & 0x0f) - 5);
    824             for (int i = 0; i < optionWords; i++) {
    825                 packet.getInt();
    826             }
    827 
    828             // assume UDP
    829             short udpSrcPort = packet.getShort();
    830             short udpDstPort = packet.getShort();
    831             short udpLen = packet.getShort();
    832             short udpChkSum = packet.getShort();
    833 
    834             // Only accept packets to or from the well-known client port (expressly permitting
    835             // packets from ports other than the well-known server port; http://b/24687559), and
    836             // server-to-server packets, e.g. for relays.
    837             if (!isPacketToOrFromClient(udpSrcPort, udpDstPort) &&
    838                 !isPacketServerToServer(udpSrcPort, udpDstPort)) {
    839                 // This should almost never happen because we use SO_ATTACH_FILTER on the packet
    840                 // socket to drop packets that don't have the right source ports. However, it's
    841                 // possible that a packet arrives between when the socket is bound and when the
    842                 // filter is set. http://b/26696823 .
    843                 throw new ParseException(DhcpErrorEvent.L4_WRONG_PORT,
    844                         "Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
    845             }
    846         }
    847 
    848         // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
    849         if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
    850             throw new ParseException(DhcpErrorEvent.BOOTP_TOO_SHORT,
    851                         "Invalid type or BOOTP packet too short, %d < %d",
    852                         packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
    853         }
    854 
    855         byte type = packet.get();
    856         byte hwType = packet.get();
    857         int addrLen = packet.get() & 0xff;
    858         byte hops = packet.get();
    859         transactionId = packet.getInt();
    860         secs = packet.getShort();
    861         short bootpFlags = packet.getShort();
    862         boolean broadcast = (bootpFlags & 0x8000) != 0;
    863         byte[] ipv4addr = new byte[4];
    864 
    865         try {
    866             packet.get(ipv4addr);
    867             clientIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
    868             packet.get(ipv4addr);
    869             yourIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
    870             packet.get(ipv4addr);
    871             nextIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
    872             packet.get(ipv4addr);
    873             relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
    874         } catch (UnknownHostException ex) {
    875             throw new ParseException(DhcpErrorEvent.L3_INVALID_IP,
    876                     "Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
    877         }
    878 
    879         // Some DHCP servers have been known to announce invalid client hardware address values such
    880         // as 0xff. The legacy DHCP client accepted these becuause it does not check the length at
    881         // all but only checks that the interface MAC address matches the first bytes of the address
    882         // in the packets. We're a bit stricter: if the length is obviously invalid (i.e., bigger
    883         // than the size of the field), we fudge it to 6 (Ethernet). http://b/23725795
    884         // TODO: evaluate whether to make this test more liberal.
    885         if (addrLen > HWADDR_LEN) {
    886             addrLen = ETHER_BROADCAST.length;
    887         }
    888 
    889         clientMac = new byte[addrLen];
    890         packet.get(clientMac);
    891 
    892         // skip over address padding (16 octets allocated)
    893         packet.position(packet.position() + (16 - addrLen)
    894                         + 64    // skip server host name (64 chars)
    895                         + 128); // skip boot file name (128 chars)
    896 
    897         int dhcpMagicCookie = packet.getInt();
    898 
    899         if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
    900             throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE,
    901                     "Bad magic cookie 0x%08x, should be 0x%08x",
    902                     dhcpMagicCookie, DHCP_MAGIC_COOKIE);
    903         }
    904 
    905         // parse options
    906         boolean notFinishedOptions = true;
    907 
    908         while ((packet.position() < packet.limit()) && notFinishedOptions) {
    909             final byte optionType = packet.get(); // cannot underflow because position < limit
    910             try {
    911                 if (optionType == DHCP_OPTION_END) {
    912                     notFinishedOptions = false;
    913                 } else if (optionType == DHCP_OPTION_PAD) {
    914                     // The pad option doesn't have a length field. Nothing to do.
    915                 } else {
    916                     int optionLen = packet.get() & 0xFF;
    917                     int expectedLen = 0;
    918 
    919                     switch(optionType) {
    920                         case DHCP_SUBNET_MASK:
    921                             netMask = readIpAddress(packet);
    922                             expectedLen = 4;
    923                             break;
    924                         case DHCP_ROUTER:
    925                             for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
    926                                 gateways.add(readIpAddress(packet));
    927                             }
    928                             break;
    929                         case DHCP_DNS_SERVER:
    930                             for (expectedLen = 0; expectedLen < optionLen; expectedLen += 4) {
    931                                 dnsServers.add(readIpAddress(packet));
    932                             }
    933                             break;
    934                         case DHCP_HOST_NAME:
    935                             expectedLen = optionLen;
    936                             hostName = readAsciiString(packet, optionLen, false);
    937                             break;
    938                         case DHCP_MTU:
    939                             expectedLen = 2;
    940                             mtu = packet.getShort();
    941                             break;
    942                         case DHCP_DOMAIN_NAME:
    943                             expectedLen = optionLen;
    944                             domainName = readAsciiString(packet, optionLen, false);
    945                             break;
    946                         case DHCP_BROADCAST_ADDRESS:
    947                             bcAddr = readIpAddress(packet);
    948                             expectedLen = 4;
    949                             break;
    950                         case DHCP_REQUESTED_IP:
    951                             requestedIp = readIpAddress(packet);
    952                             expectedLen = 4;
    953                             break;
    954                         case DHCP_LEASE_TIME:
    955                             leaseTime = Integer.valueOf(packet.getInt());
    956                             expectedLen = 4;
    957                             break;
    958                         case DHCP_MESSAGE_TYPE:
    959                             dhcpType = packet.get();
    960                             expectedLen = 1;
    961                             break;
    962                         case DHCP_SERVER_IDENTIFIER:
    963                             serverIdentifier = readIpAddress(packet);
    964                             expectedLen = 4;
    965                             break;
    966                         case DHCP_PARAMETER_LIST:
    967                             expectedParams = new byte[optionLen];
    968                             packet.get(expectedParams);
    969                             expectedLen = optionLen;
    970                             break;
    971                         case DHCP_MESSAGE:
    972                             expectedLen = optionLen;
    973                             message = readAsciiString(packet, optionLen, false);
    974                             break;
    975                         case DHCP_MAX_MESSAGE_SIZE:
    976                             expectedLen = 2;
    977                             maxMessageSize = Short.valueOf(packet.getShort());
    978                             break;
    979                         case DHCP_RENEWAL_TIME:
    980                             expectedLen = 4;
    981                             T1 = Integer.valueOf(packet.getInt());
    982                             break;
    983                         case DHCP_REBINDING_TIME:
    984                             expectedLen = 4;
    985                             T2 = Integer.valueOf(packet.getInt());
    986                             break;
    987                         case DHCP_VENDOR_CLASS_ID:
    988                             expectedLen = optionLen;
    989                             // Embedded nulls are safe as this does not get passed to netd.
    990                             vendorId = readAsciiString(packet, optionLen, true);
    991                             break;
    992                         case DHCP_CLIENT_IDENTIFIER: { // Client identifier
    993                             byte[] id = new byte[optionLen];
    994                             packet.get(id);
    995                             expectedLen = optionLen;
    996                         } break;
    997                         case DHCP_VENDOR_INFO:
    998                             expectedLen = optionLen;
    999                             // Embedded nulls are safe as this does not get passed to netd.
   1000                             vendorInfo = readAsciiString(packet, optionLen, true);
   1001                             break;
   1002                         default:
   1003                             // ignore any other parameters
   1004                             for (int i = 0; i < optionLen; i++) {
   1005                                 expectedLen++;
   1006                                 byte throwaway = packet.get();
   1007                             }
   1008                     }
   1009 
   1010                     if (expectedLen != optionLen) {
   1011                         final int errorCode = DhcpErrorEvent.errorCodeWithOption(
   1012                                 DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
   1013                         throw new ParseException(errorCode,
   1014                                 "Invalid length %d for option %d, expected %d",
   1015                                 optionLen, optionType, expectedLen);
   1016                     }
   1017                 }
   1018             } catch (BufferUnderflowException e) {
   1019                 final int errorCode = DhcpErrorEvent.errorCodeWithOption(
   1020                         DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
   1021                 throw new ParseException(errorCode, "BufferUnderflowException");
   1022             }
   1023         }
   1024 
   1025         DhcpPacket newPacket;
   1026 
   1027         switch(dhcpType) {
   1028             case (byte) 0xFF:
   1029                 throw new ParseException(DhcpErrorEvent.DHCP_NO_MSG_TYPE,
   1030                         "No DHCP message type option");
   1031             case DHCP_MESSAGE_TYPE_DISCOVER:
   1032                 newPacket = new DhcpDiscoverPacket(
   1033                     transactionId, secs, clientMac, broadcast);
   1034                 break;
   1035             case DHCP_MESSAGE_TYPE_OFFER:
   1036                 newPacket = new DhcpOfferPacket(
   1037                     transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac);
   1038                 break;
   1039             case DHCP_MESSAGE_TYPE_REQUEST:
   1040                 newPacket = new DhcpRequestPacket(
   1041                     transactionId, secs, clientIp, clientMac, broadcast);
   1042                 break;
   1043             case DHCP_MESSAGE_TYPE_DECLINE:
   1044                 newPacket = new DhcpDeclinePacket(
   1045                     transactionId, secs, clientIp, yourIp, nextIp, relayIp,
   1046                     clientMac);
   1047                 break;
   1048             case DHCP_MESSAGE_TYPE_ACK:
   1049                 newPacket = new DhcpAckPacket(
   1050                     transactionId, secs, broadcast, ipSrc, clientIp, yourIp, clientMac);
   1051                 break;
   1052             case DHCP_MESSAGE_TYPE_NAK:
   1053                 newPacket = new DhcpNakPacket(
   1054                     transactionId, secs, clientIp, yourIp, nextIp, relayIp,
   1055                     clientMac);
   1056                 break;
   1057             case DHCP_MESSAGE_TYPE_INFORM:
   1058                 newPacket = new DhcpInformPacket(
   1059                     transactionId, secs, clientIp, yourIp, nextIp, relayIp,
   1060                     clientMac);
   1061                 break;
   1062             default:
   1063                 throw new ParseException(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE,
   1064                         "Unimplemented DHCP type %d", dhcpType);
   1065         }
   1066 
   1067         newPacket.mBroadcastAddress = bcAddr;
   1068         newPacket.mDnsServers = dnsServers;
   1069         newPacket.mDomainName = domainName;
   1070         newPacket.mGateways = gateways;
   1071         newPacket.mHostName = hostName;
   1072         newPacket.mLeaseTime = leaseTime;
   1073         newPacket.mMessage = message;
   1074         newPacket.mMtu = mtu;
   1075         newPacket.mRequestedIp = requestedIp;
   1076         newPacket.mRequestedParams = expectedParams;
   1077         newPacket.mServerIdentifier = serverIdentifier;
   1078         newPacket.mSubnetMask = netMask;
   1079         newPacket.mMaxMessageSize = maxMessageSize;
   1080         newPacket.mT1 = T1;
   1081         newPacket.mT2 = T2;
   1082         newPacket.mVendorId = vendorId;
   1083         newPacket.mVendorInfo = vendorInfo;
   1084         return newPacket;
   1085     }
   1086 
   1087     /**
   1088      * Parse a packet from an array of bytes, stopping at the given length.
   1089      */
   1090     public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
   1091             throws ParseException {
   1092         ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
   1093         return decodeFullPacket(buffer, pktType);
   1094     }
   1095 
   1096     /**
   1097      *  Construct a DhcpResults object from a DHCP reply packet.
   1098      */
   1099     public DhcpResults toDhcpResults() {
   1100         Inet4Address ipAddress = mYourIp;
   1101         if (ipAddress.equals(Inet4Address.ANY)) {
   1102             ipAddress = mClientIp;
   1103             if (ipAddress.equals(Inet4Address.ANY)) {
   1104                 return null;
   1105             }
   1106         }
   1107 
   1108         int prefixLength;
   1109         if (mSubnetMask != null) {
   1110             try {
   1111                 prefixLength = NetworkUtils.netmaskToPrefixLength(mSubnetMask);
   1112             } catch (IllegalArgumentException e) {
   1113                 // Non-contiguous netmask.
   1114                 return null;
   1115             }
   1116         } else {
   1117             prefixLength = NetworkUtils.getImplicitNetmask(ipAddress);
   1118         }
   1119 
   1120         DhcpResults results = new DhcpResults();
   1121         try {
   1122             results.ipAddress = new LinkAddress(ipAddress, prefixLength);
   1123         } catch (IllegalArgumentException e) {
   1124             return null;
   1125         }
   1126 
   1127         if (mGateways.size() > 0) {
   1128             results.gateway = mGateways.get(0);
   1129         }
   1130 
   1131         results.dnsServers.addAll(mDnsServers);
   1132         results.domains = mDomainName;
   1133         results.serverAddress = mServerIdentifier;
   1134         results.vendorInfo = mVendorInfo;
   1135         results.leaseDuration = (mLeaseTime != null) ? mLeaseTime : INFINITE_LEASE;
   1136         results.mtu = (mMtu != null && MIN_MTU <= mMtu && mMtu <= MAX_MTU) ? mMtu : 0;
   1137 
   1138         return results;
   1139     }
   1140 
   1141     /**
   1142      * Returns the parsed lease time, in milliseconds, or 0 for infinite.
   1143      */
   1144     public long getLeaseTimeMillis() {
   1145         // dhcpcd treats the lack of a lease time option as an infinite lease.
   1146         if (mLeaseTime == null || mLeaseTime == INFINITE_LEASE) {
   1147             return 0;
   1148         } else if (0 <= mLeaseTime && mLeaseTime < MINIMUM_LEASE) {
   1149             return MINIMUM_LEASE * 1000;
   1150         } else {
   1151             return (mLeaseTime & 0xffffffffL) * 1000;
   1152         }
   1153     }
   1154 
   1155     /**
   1156      * Builds a DHCP-DISCOVER packet from the required specified
   1157      * parameters.
   1158      */
   1159     public static ByteBuffer buildDiscoverPacket(int encap, int transactionId,
   1160         short secs, byte[] clientMac, boolean broadcast, byte[] expectedParams) {
   1161         DhcpPacket pkt = new DhcpDiscoverPacket(
   1162             transactionId, secs, clientMac, broadcast);
   1163         pkt.mRequestedParams = expectedParams;
   1164         return pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
   1165     }
   1166 
   1167     /**
   1168      * Builds a DHCP-OFFER packet from the required specified
   1169      * parameters.
   1170      */
   1171     public static ByteBuffer buildOfferPacket(int encap, int transactionId,
   1172         boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
   1173         byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
   1174         List<Inet4Address> gateways, List<Inet4Address> dnsServers,
   1175         Inet4Address dhcpServerIdentifier, String domainName) {
   1176         DhcpPacket pkt = new DhcpOfferPacket(
   1177             transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac);
   1178         pkt.mGateways = gateways;
   1179         pkt.mDnsServers = dnsServers;
   1180         pkt.mLeaseTime = timeout;
   1181         pkt.mDomainName = domainName;
   1182         pkt.mServerIdentifier = dhcpServerIdentifier;
   1183         pkt.mSubnetMask = netMask;
   1184         pkt.mBroadcastAddress = bcAddr;
   1185         return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
   1186     }
   1187 
   1188     /**
   1189      * Builds a DHCP-ACK packet from the required specified parameters.
   1190      */
   1191     public static ByteBuffer buildAckPacket(int encap, int transactionId,
   1192         boolean broadcast, Inet4Address serverIpAddr, Inet4Address clientIpAddr,
   1193         byte[] mac, Integer timeout, Inet4Address netMask, Inet4Address bcAddr,
   1194         List<Inet4Address> gateways, List<Inet4Address> dnsServers,
   1195         Inet4Address dhcpServerIdentifier, String domainName) {
   1196         DhcpPacket pkt = new DhcpAckPacket(
   1197             transactionId, (short) 0, broadcast, serverIpAddr, INADDR_ANY, clientIpAddr, mac);
   1198         pkt.mGateways = gateways;
   1199         pkt.mDnsServers = dnsServers;
   1200         pkt.mLeaseTime = timeout;
   1201         pkt.mDomainName = domainName;
   1202         pkt.mSubnetMask = netMask;
   1203         pkt.mServerIdentifier = dhcpServerIdentifier;
   1204         pkt.mBroadcastAddress = bcAddr;
   1205         return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
   1206     }
   1207 
   1208     /**
   1209      * Builds a DHCP-NAK packet from the required specified parameters.
   1210      */
   1211     public static ByteBuffer buildNakPacket(int encap, int transactionId,
   1212         Inet4Address serverIpAddr, Inet4Address clientIpAddr, byte[] mac) {
   1213         DhcpPacket pkt = new DhcpNakPacket(transactionId, (short) 0, clientIpAddr,
   1214             serverIpAddr, serverIpAddr, serverIpAddr, mac);
   1215         pkt.mMessage = "requested address not available";
   1216         pkt.mRequestedIp = clientIpAddr;
   1217         return pkt.buildPacket(encap, DHCP_CLIENT, DHCP_SERVER);
   1218     }
   1219 
   1220     /**
   1221      * Builds a DHCP-REQUEST packet from the required specified parameters.
   1222      */
   1223     public static ByteBuffer buildRequestPacket(int encap,
   1224         int transactionId, short secs, Inet4Address clientIp, boolean broadcast,
   1225         byte[] clientMac, Inet4Address requestedIpAddress,
   1226         Inet4Address serverIdentifier, byte[] requestedParams, String hostName) {
   1227         DhcpPacket pkt = new DhcpRequestPacket(transactionId, secs, clientIp,
   1228             clientMac, broadcast);
   1229         pkt.mRequestedIp = requestedIpAddress;
   1230         pkt.mServerIdentifier = serverIdentifier;
   1231         pkt.mHostName = hostName;
   1232         pkt.mRequestedParams = requestedParams;
   1233         ByteBuffer result = pkt.buildPacket(encap, DHCP_SERVER, DHCP_CLIENT);
   1234         return result;
   1235     }
   1236 }
   1237