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