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