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